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

rokucommunity / brighterscript / #15223

22 Feb 2026 02:28AM UTC coverage: 87.207% (+0.005%) from 87.202%
#15223

push

web-flow
Merge f055a8d04 into 1556715dd

14751 of 17875 branches covered (82.52%)

Branch coverage included in aggregate %.

107 of 117 new or added lines in 19 files covered. (91.45%)

160 existing lines in 15 files now uncovered.

15496 of 16809 relevant lines covered (92.19%)

25606.76 hits per line

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

77.73
/src/types/IntersectionType.ts
1
import type { GetTypeOptions, TypeCompatibilityData } from '../interfaces';
2
import { isDynamicType, isIntersectionType, isObjectType, isTypedFunctionType, isTypeStatementType } from '../astUtils/reflection';
1✔
3
import { BscType } from './BscType';
1✔
4
import { ReferenceTypeWithDefault, ReferenceType } from './ReferenceType';
1✔
5
import { addAssociatedTypesTableAsSiblingToMemberTable, getAllTypesFromCompoundType, isEnumTypeCompatible, isTypeWithPotentialDefaultDynamicMember, 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✔
15
    return new IntersectionType(types);
×
16
}
17

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

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

28
    public readonly callFuncAssociatedTypesTable: SymbolTable;
29

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

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

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

50
        if (filteredTypes.length === 0 && this.types.some(isTypeWithPotentialDefaultDynamicMember)) {
338!
51
            const typesFromMembersWithDynamicAA = this.types.map((innerType) => {
×
52
                return innerType?.getMemberType(name, options);
×
53
            });
54
            filteredTypes = reduceTypesForIntersectionType(typesFromMembersWithDynamicAA.map(t => t).filter(t => t !== undefined));
×
55
        }
56
        if (filteredTypes.length === 0) {
338✔
57
            return undefined;
73✔
58
        } else if (filteredTypes.length === 1) {
265✔
59
            return filteredTypes[0];
262✔
60
        }
61
        return new IntersectionType(filteredTypes);
3✔
62
    }
63

64
    private getCallFuncFromInnerTypes(name: string, options: GetTypeOptions): BscType {
65
        const typeFromMembers = reduceTypesForIntersectionType(this.types.map((innerType) => innerType?.getCallFuncType(name, options)).filter(t => t !== undefined));
820!
66

67
        if (typeFromMembers.length === 0) {
410✔
68
            return undefined;
140✔
69
        } else if (typeFromMembers.length === 1) {
270✔
70
            return typeFromMembers[0];
268✔
71
        }
72
        return new IntersectionType(typeFromMembers);
2✔
73
    }
74

75
    getMemberType(name: string, options: GetTypeOptions) {
76
        const innerTypesMemberType = this.getMemberTypeFromInnerTypes(name, options);
138✔
77
        if (!innerTypesMemberType) {
138✔
78
            // We don't have any members of any inner types that match
79
            // so instead, create reference type that will
80
            return new ReferenceType(name, name, options.flags, () => {
11✔
81
                return {
111✔
82
                    name: `IntersectionType MemberTable: '${this.__identifier}'`,
83
                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
84
                        const referenceTypeInnerMemberTypes = this.getMemberTypeFromInnerTypes(name, options);
111✔
85
                        if (!referenceTypeInnerMemberTypes) {
111✔
86
                            if (this.hasMemberTypeWithDefaultDynamicMember && !innerOptions.ignoreDefaultDynamicMembers) {
62!
87
                                return DynamicType.instance;
×
88
                            }
89
                            return undefined;
62✔
90
                        }
91
                        return referenceTypeInnerMemberTypes;
49✔
92
                    },
93
                    setCachedType: (innerName: string, innerCacheEntry: TypeCacheEntry, innerOptions: GetTypeOptions) => {
94
                        // TODO: is this even cachable? This is a NO-OP for now, and it shouldn't hurt anything
95
                    },
96
                    addSibling: (symbolTable: SymbolTable) => {
97
                        // TODO: I don't know what this means in this context?
98
                    }
99
                };
100
            });
101
        }
102
        if (!innerTypesMemberType?.isResolvable()) {
127!
103
            const shouldCreateDynamicAAMember = this.hasMemberTypeWithDefaultDynamicMember && !options.ignoreDefaultDynamicMembers;
26✔
104
            if (shouldCreateDynamicAAMember) {
26!
105
                return new ReferenceTypeWithDefault(innerTypesMemberType, DynamicType.instance);
26✔
106
            }
107
        }
108
        return innerTypesMemberType;
101✔
109
    }
110

111
    getCallFuncType(name: string, options: GetTypeOptions) {
112
        const resultCallFuncType = this.getCallFuncFromInnerTypes(name, options);
15✔
113
        if (!resultCallFuncType) {
15✔
114
            // We don't have any members of any inner types that match
115
            // so instead, create reference type that will
116
            return new ReferenceType(name, name, options.flags, () => {
5✔
117
                return {
395✔
118
                    name: `IntersectionType CallFunc MemberTable: '${this.__identifier}'`,
119
                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
120
                        const referenceTypeInnerMemberType = this.getCallFuncFromInnerTypes(name, options);
395✔
121
                        if (!referenceTypeInnerMemberType) {
395✔
122
                            if (this.hasMemberTypeWithDefaultDynamicMember && !innerOptions.ignoreDefaultDynamicMembers) {
135!
123
                                return DynamicType.instance;
×
124
                            }
125
                        }
126
                        return referenceTypeInnerMemberType;
395✔
127
                    },
128
                    setCachedType: (innerName: string, innerCacheEntry: TypeCacheEntry, innerOptions: GetTypeOptions) => {
129
                        // TODO: is this even cachable? This is a NO-OP for now, and it shouldn't hurt anything
130
                    },
131
                    addSibling: (symbolTable: SymbolTable) => {
132
                        // TODO: I don't know what this means in this context?
133
                    }
134
                };
135
            });
136
        }
137

138
        if (!resultCallFuncType?.isResolvable()) {
10!
139
            const shouldCreateDynamicAAMember = this.hasMemberTypeWithDefaultDynamicMember && !options.ignoreDefaultDynamicMembers;
×
140
            if (shouldCreateDynamicAAMember) {
×
141
                return new ReferenceTypeWithDefault(resultCallFuncType, DynamicType.instance);
×
142
            }
143
        }
144

145
        if (isTypedFunctionType(resultCallFuncType)) {
10✔
146
            const typesToCheck = [...resultCallFuncType.params.map(p => p.type), resultCallFuncType.returnType];
8✔
147

148
            for (const type of typesToCheck) {
8✔
149
                addAssociatedTypesTableAsSiblingToMemberTable(type, this.callFuncAssociatedTypesTable, SymbolTypeFlag.runtime);
12✔
150
            }
151
        }
152
        return resultCallFuncType;
10✔
153
    }
154

155
    get returnType() {
156
        return util.getReturnTypeOfIntersectionOfFunctions(this);
2✔
157
    }
158

159

160
    isTypeCompatible(targetType: BscType, data?: TypeCompatibilityData): boolean {
161
        while (isTypeStatementType(targetType)) {
19✔
NEW
162
            targetType = targetType.wrappedType;
×
163
        }
164
        if (isDynamicType(targetType) || isObjectType(targetType) || this === targetType) {
19!
165
            return true;
×
166
        }
167
        if (isEnumTypeCompatible(this, targetType, data)) {
19!
168
            return true;
×
169
        }
170
        if (isIntersectionType(targetType)) {
19✔
171
            // check if this all the types of this type are in the target (eg, target is a super set of this types)
172
            let allMembersSatisfied = true;
6✔
173
            for (const memberType of this.types) {
6✔
174
                let foundCompatibleInnerType = false;
14✔
175
                for (const targetInnerType of targetType.types) {
14✔
176
                    if (memberType.isTypeCompatible(targetInnerType, data)) {
25✔
177
                        foundCompatibleInnerType = true;
11✔
178
                        break;
11✔
179
                    }
180
                }
181
                if (!foundCompatibleInnerType) {
14✔
182
                    allMembersSatisfied = false;
3✔
183
                }
184
            }
185
            return allMembersSatisfied;
6✔
186
        }
187
        let foundCompatibleInnerType = true;
13✔
188
        for (const innerType of this.types) {
13✔
189
            if (!innerType.isTypeCompatible(targetType, data)) {
26✔
190
                foundCompatibleInnerType = false;
8✔
191
            }
192
        }
193

194
        return foundCompatibleInnerType;
13✔
195
    }
196
    toString(): string {
197
        return joinTypesString(this.types, 'and', BscTypeKind.IntersectionType);
23✔
198
    }
199

200
    /**
201
     * Used for transpilation
202
     */
203
    toTypeString(): string {
UNCOV
204
        const uniqueTypeStrings = new Set<string>(getAllTypesFromCompoundType(this).map(t => t.toTypeString()));
×
205

UNCOV
206
        if (uniqueTypeStrings.size === 1) {
×
207
            return uniqueTypeStrings.values().next().value;
×
208
        }
209
        return 'dynamic';
×
210
    }
211

212
    checkAllMemberTypes(predicate: (BscType) => boolean) {
UNCOV
213
        return this.types.reduce((acc, type) => {
×
UNCOV
214
            return acc && predicate(type);
×
215
        }, true);
216
    }
217

218
    isEqual(targetType: BscType): boolean {
219
        if (!isIntersectionType(targetType)) {
1!
UNCOV
220
            return false;
×
221
        }
222
        if (this === targetType) {
1!
223
            return true;
×
224
        }
225
        for (const type of this.types) {
1✔
226
            let foundMatch = false;
3✔
227
            for (const targetTypeInner of targetType.types) {
3✔
228
                if (type.isEqual(targetTypeInner)) {
6✔
229
                    foundMatch = true;
3✔
230
                    break;
3✔
231
                }
232
            }
233
            if (!foundMatch) {
3!
UNCOV
234
                return false;
×
235
            }
236
        }
237
        return true;
1✔
238
    }
239

240
    getMemberTable(): SymbolTable {
241
        const intersectionTable = new SymbolTable(this.__identifier + ' IntersectionTable');
10✔
242

243
        for (const type of this.types) {
10✔
244
            type.addBuiltInInterfaces();
20✔
245
            for (const symbol of type.getMemberTable().getAllSymbols(SymbolTypeFlag.runtime)) {
20✔
246
                const foundType = this.getMemberTypeFromInnerTypes(symbol.name, { flags: SymbolTypeFlag.runtime });
76✔
247
                intersectionTable.addSymbol(symbol.name, {}, foundType, SymbolTypeFlag.runtime);
76✔
248
            }
249
        }
250
        const firstType = this.types[0];
10✔
251
        if (!firstType) {
10!
UNCOV
252
            return intersectionTable;
×
253
        }
254
        firstType.addBuiltInInterfaces();
10✔
255
        for (const symbol of firstType.getMemberTable().getAllSymbols(SymbolTypeFlag.runtime)) {
10✔
256
            const foundType = this.getMemberTypeFromInnerTypes(symbol.name, { flags: SymbolTypeFlag.runtime });
13✔
257
            intersectionTable.addSymbol(symbol.name, {}, foundType, SymbolTypeFlag.runtime);
13✔
258
        }
259
        return intersectionTable;
10✔
260
    }
261

262

263
    private _hasMemberTypeWithDefaultDynamicMember: boolean = undefined;
159✔
264
    get hasMemberTypeWithDefaultDynamicMember(): boolean {
265
        if (this._hasMemberTypeWithDefaultDynamicMember !== undefined) {
223✔
266
            return this._hasMemberTypeWithDefaultDynamicMember;
210✔
267
        }
268
        this._hasMemberTypeWithDefaultDynamicMember = false;
13✔
269

270
        for (const type of this.types) {
13✔
271
            if (isTypeWithPotentialDefaultDynamicMember(type)) {
25✔
272
                this._hasMemberTypeWithDefaultDynamicMember = true;
6✔
273
                break;
6✔
274
            }
275
        }
276
        return this._hasMemberTypeWithDefaultDynamicMember;
13✔
277
    }
278
}
279

280
BuiltInInterfaceAdder.intersectionTypeFactory = (types: BscType[]) => {
1✔
UNCOV
281
    return new IntersectionType(types);
×
282
};
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