• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rokucommunity / brighterscript / #15061

06 Jan 2026 01:31PM UTC coverage: 87.061% (+0.006%) from 87.055%
#15061

push

web-flow
Merge e7a80744a into 2ea4d2108

14502 of 17597 branches covered (82.41%)

Branch coverage included in aggregate %.

196 of 264 new or added lines in 12 files covered. (74.24%)

185 existing lines in 8 files now uncovered.

15252 of 16579 relevant lines covered (92.0%)

24191.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.77
/src/types/IntersectionType.ts
1
import type { GetTypeOptions, TypeCompatibilityData } from '../interfaces';
2
import { isAssociativeArrayType, isDynamicType, isIntersectionType, isObjectType, isTypedFunctionType } from '../astUtils/reflection';
1✔
3
import { BscType } from './BscType';
1✔
4
import { ReferenceType } from './ReferenceType';
1✔
5
import { addAssociatedTypesTableAsSiblingToMemberTable, getAllTypesFromComplexType, isEnumTypeCompatible, joinTypesString, reduceTypesForIntersectionType } from './helpers';
1✔
6
import { BscTypeKind } from './BscTypeKind';
1✔
7
import type { TypeCacheEntry } from '../SymbolTable';
8
import { SymbolTable } from '../SymbolTable';
1✔
9
import { SymbolTypeFlag } from '../SymbolTypeFlag';
1✔
10
import { BuiltInInterfaceAdder } from './BuiltInInterfaceAdder';
1✔
11
import { util } from '../util';
1✔
12
import { DynamicType } from './DynamicType';
1✔
13

14
export function intersectionTypeFactory(types: BscType[]) {
1✔
NEW
15
    return new IntersectionType(types);
×
16
}
17

18
export class IntersectionType extends BscType {
1✔
19
    constructor(
20
        public types: BscType[]
72✔
21
    ) {
22
        super(joinTypesString(types, 'and', BscTypeKind.IntersectionType));
72✔
23
        this.callFuncAssociatedTypesTable = new SymbolTable(`Intersection: CallFuncAssociatedTypes`);
72✔
24
    }
25

26
    public readonly kind = BscTypeKind.IntersectionType;
72✔
27

28
    public readonly callFuncAssociatedTypesTable: SymbolTable;
29

30
    public addType(type: BscType) {
NEW
31
        this.types.push(type);
×
32
    }
33

34
    isResolvable(): boolean {
35
        for (const type of this.types) {
38✔
36
            // resolvable if any inner type is resolvable
37
            if (type.isResolvable()) {
41✔
38
                return true;
35✔
39
            }
40
        }
41
        return false;
3✔
42
    }
43

44
    private getMemberTypeFromInnerTypes(name: string, options: GetTypeOptions): BscType {
45
        const typeFromMembers = this.types.map((innerType) => {
159✔
46
            return innerType?.getMemberType(name, { ...options, ignoreAADefaultDynamicMembers: true });
318!
47
        });
48
        const filteredTypes = reduceTypesForIntersectionType(typeFromMembers.filter(t => t !== undefined));
318✔
49

50
        if (filteredTypes.length === 0) {
159✔
51
            if (this.types.some(isAssociativeArrayType)) {
38!
NEW
52
                return DynamicType.instance;
×
53
            }
54
            return undefined;
38✔
55
        } else if (filteredTypes.length === 1) {
121✔
56
            return filteredTypes[0];
118✔
57
        }
58
        return new IntersectionType(filteredTypes);
3✔
59
    }
60

61
    private getCallFuncFromInnerTypes(name: string, options: GetTypeOptions): BscType {
NEW
62
        const typeFromMembers = reduceTypesForIntersectionType(this.types.map((innerType) => innerType?.getCallFuncType(name, options)).filter(t => t !== undefined));
×
63

NEW
64
        if (typeFromMembers.length === 0) {
×
NEW
65
            return undefined;
×
NEW
66
        } else if (typeFromMembers.length === 1) {
×
NEW
67
            return typeFromMembers[0];
×
68
        }
NEW
69
        return new IntersectionType(typeFromMembers);
×
70
    }
71

72
    getMemberType(name: string, options: GetTypeOptions) {
73
        const innerTypesMemberType = this.getMemberTypeFromInnerTypes(name, options);
69✔
74
        if (!innerTypesMemberType) {
69✔
75
            // We don't have any members of any inner types that match
76
            // so instead, create reference type that will
77
            return new ReferenceType(name, name, options.flags, () => {
9✔
78
                return {
78✔
79
                    name: `IntersectionType MemberTable: '${this.__identifier}'`,
80
                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
81
                        const referenceTypeInnerMemberTypes = this.getMemberTypeFromInnerTypes(name, options);
78✔
82
                        if (!referenceTypeInnerMemberTypes) {
78✔
83
                            return undefined;
29✔
84
                        }
85
                        return referenceTypeInnerMemberTypes;
49✔
86
                    },
87
                    setCachedType: (innerName: string, innerCacheEntry: TypeCacheEntry, innerOptions: GetTypeOptions) => {
88
                        // TODO: is this even cachable? This is a NO-OP for now, and it shouldn't hurt anything
89
                    },
90
                    addSibling: (symbolTable: SymbolTable) => {
91
                        // TODO: I don't know what this means in this context?
92
                    }
93
                };
94
            });
95
        }
96
        return innerTypesMemberType;
60✔
97
    }
98

99
    getCallFuncType(name: string, options: GetTypeOptions) {
NEW
100
        const resultCallFuncType = this.getCallFuncFromInnerTypes(name, options);
×
NEW
101
        if (!resultCallFuncType) {
×
102
            // We don't have any members of any inner types that match
103
            // so instead, create reference type that will
NEW
104
            return new ReferenceType(name, name, options.flags, () => {
×
NEW
105
                return {
×
106
                    name: `IntersectionType CallFunc MemberTable: '${this.__identifier}'`,
107
                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
NEW
108
                        const referenceTypeInnerMemberType = this.getCallFuncFromInnerTypes(name, options);
×
NEW
109
                        if (!referenceTypeInnerMemberType) {
×
NEW
110
                            return undefined;
×
111
                        }
NEW
112
                        return referenceTypeInnerMemberType;
×
113
                    },
114
                    setCachedType: (innerName: string, innerCacheEntry: TypeCacheEntry, innerOptions: GetTypeOptions) => {
115
                        // TODO: is this even cachable? This is a NO-OP for now, and it shouldn't hurt anything
116
                    },
117
                    addSibling: (symbolTable: SymbolTable) => {
118
                        // TODO: I don't know what this means in this context?
119
                    }
120
                };
121
            });
122
        }
123

NEW
124
        if (isTypedFunctionType(resultCallFuncType)) {
×
NEW
125
            const typesToCheck = [...resultCallFuncType.params.map(p => p.type), resultCallFuncType.returnType];
×
126

NEW
127
            for (const type of typesToCheck) {
×
NEW
128
                addAssociatedTypesTableAsSiblingToMemberTable(type, this.callFuncAssociatedTypesTable, SymbolTypeFlag.runtime);
×
129
            }
130
        }
NEW
131
        return resultCallFuncType;
×
132
    }
133

134
    get returnType() {
NEW
135
        return util.getReturnTypeOfIntersectionOfFunctions(this);
×
136
    }
137

138

139
    isTypeCompatible(targetType: BscType, data?: TypeCompatibilityData): boolean {
140
        if (isDynamicType(targetType) || isObjectType(targetType) || this === targetType) {
13!
NEW
141
            return true;
×
142
        }
143
        if (isEnumTypeCompatible(this, targetType, data)) {
13!
NEW
144
            return true;
×
145
        }
146
        if (isIntersectionType(targetType)) {
13✔
147
            // check if this all the types of this type are in the target (eg, target is a super set of this types)
148
            let allMembersSatisfied = true;
6✔
149
            for (const memberType of this.types) {
6✔
150
                let foundCompatibleInnerType = false;
14✔
151
                for (const targetInnerType of targetType.types) {
14✔
152
                    if (memberType.isTypeCompatible(targetInnerType, data)) {
25✔
153
                        foundCompatibleInnerType = true;
11✔
154
                        break;
11✔
155
                    }
156
                }
157
                if (!foundCompatibleInnerType) {
14✔
158
                    allMembersSatisfied = false;
3✔
159
                }
160
            }
161
            return allMembersSatisfied;
6✔
162
        }
163
        let foundCompatibleInnerType = true;
7✔
164
        for (const innerType of this.types) {
7✔
165
            if (!innerType.isTypeCompatible(targetType, data)) {
14✔
166
                foundCompatibleInnerType = false;
6✔
167
            }
168
        }
169

170
        return foundCompatibleInnerType;
7✔
171
    }
172
    toString(): string {
173
        return joinTypesString(this.types, 'and', BscTypeKind.IntersectionType);
4✔
174
    }
175

176
    /**
177
     * Used for transpilation
178
     */
179
    toTypeString(): string {
NEW
180
        const uniqueTypeStrings = new Set<string>(getAllTypesFromComplexType(this).map(t => t.toTypeString()));
×
181

NEW
182
        if (uniqueTypeStrings.size === 1) {
×
NEW
183
            return uniqueTypeStrings.values().next().value;
×
184
        }
NEW
185
        return 'dynamic';
×
186
    }
187

188
    checkAllMemberTypes(predicate: (BscType) => boolean) {
NEW
189
        return this.types.reduce((acc, type) => {
×
NEW
190
            return acc && predicate(type);
×
191
        }, true);
192
    }
193

194
    isEqual(targetType: BscType): boolean {
195
        if (!isIntersectionType(targetType)) {
1!
NEW
196
            return false;
×
197
        }
198
        if (this === targetType) {
1!
NEW
199
            return true;
×
200
        }
201
        for (const type of this.types) {
1✔
202
            let foundMatch = false;
3✔
203
            for (const targetTypeInner of targetType.types) {
3✔
204
                if (type.isEqual(targetTypeInner)) {
6✔
205
                    foundMatch = true;
3✔
206
                    break;
3✔
207
                }
208
            }
209
            if (!foundMatch) {
3!
NEW
210
                return false;
×
211
            }
212
        }
213
        return true;
1✔
214
    }
215

216
    getMemberTable(): SymbolTable {
217
        const intersectionTable = new SymbolTable(this.__identifier + ' IntersectionTable');
4✔
218

219
        for (const type of this.types) {
4✔
220
            type.addBuiltInInterfaces();
8✔
221
            for (const symbol of type.getMemberTable().getAllSymbols(SymbolTypeFlag.runtime)) {
8✔
222
                const foundType = this.getMemberTypeFromInnerTypes(symbol.name, { flags: SymbolTypeFlag.runtime });
8✔
223
                /*
224

225
                const allResolvableTypes = foundType.reduce((acc, curType) => {
226
                    return acc && curType?.isResolvable();
227
                }, true);
228

229
                if (!allResolvableTypes) {
230
                    continue;
231
                }
232
                const uniqueType = getUniqueType(findTypeUnion(foundType), intersectionTypeFactory);*/
233
                intersectionTable.addSymbol(symbol.name, {}, foundType, SymbolTypeFlag.runtime);
8✔
234
            }
235
        }
236
        const firstType = this.types[0];
4✔
237
        if (!firstType) {
4!
NEW
238
            return intersectionTable;
×
239
        }
240
        firstType.addBuiltInInterfaces();
4✔
241
        for (const symbol of firstType.getMemberTable().getAllSymbols(SymbolTypeFlag.runtime)) {
4✔
242
            const foundType = this.getMemberTypeFromInnerTypes(symbol.name, { flags: SymbolTypeFlag.runtime });
4✔
243
            /* const allResolvableTypes = foundType.reduce((acc, curType) => {
244
                 return acc && curType?.isResolvable();
245
             }, true);
246

247
             if (!allResolvableTypes) {
248
                 continue;
249
             }
250
             const uniqueType = getUniqueType(findTypeUnion(foundType), unionTypeFactory);*/
251
            intersectionTable.addSymbol(symbol.name, {}, foundType, SymbolTypeFlag.runtime);
4✔
252
        }
253
        return intersectionTable;
4✔
254
    }
255
}
256

257
BuiltInInterfaceAdder.intersectionTypeFactory = (types: BscType[]) => {
1✔
NEW
258
    return new IntersectionType(types);
×
259
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc