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

rokucommunity / brighterscript / #15038

17 Dec 2025 01:49PM UTC coverage: 87.035% (+0.01%) from 87.023%
#15038

push

web-flow
Merge 723b94596 into 2ea4d2108

14488 of 17585 branches covered (82.39%)

Branch coverage included in aggregate %.

161 of 231 new or added lines in 11 files covered. (69.7%)

134 existing lines in 8 files now uncovered.

15231 of 16561 relevant lines covered (91.97%)

24122.14 hits per line

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

63.43
/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[]
38✔
21
    ) {
22
        super(joinTypesString(types, 'and', BscTypeKind.IntersectionType));
38✔
23
        this.callFuncAssociatedTypesTable = new SymbolTable(`Intersection: CallFuncAssociatedTypes`);
38✔
24
    }
25

26
    public readonly kind = BscTypeKind.IntersectionType;
38✔
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) {
20✔
36
            // resolvable if any inner type is resolvable
37
            if (type.isResolvable()) {
23✔
38
                return true;
17✔
39
            }
40
        }
41
        return false;
3✔
42
    }
43

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

50
        if (filteredTypes.length === 0) {
126✔
51
            if (this.types.some(isAssociativeArrayType)) {
38!
NEW
52
                return DynamicType.instance;
×
53
            }
54
            return undefined;
38✔
55
        } else if (filteredTypes.length === 1) {
88✔
56
            return filteredTypes[0];
85✔
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);
45✔
74
        if (!innerTypesMemberType) {
45✔
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;
36✔
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) {
7!
NEW
141
            return true;
×
142
        }
143
        if (isEnumTypeCompatible(this, targetType, data)) {
7!
NEW
144
            return true;
×
145
        }
146
        if (isIntersectionType(targetType)) {
7✔
147
            // check if this all the types of this type are in the target (eg, target is a super set of this types)
148
            for (const memberType of this.types) {
6✔
149
                let foundCompatibleInnerType = false;
11✔
150
                for (const targetInnerType of targetType.types) {
11✔
151
                    if (memberType.isTypeCompatible(targetInnerType, data)) {
26✔
152
                        foundCompatibleInnerType = true;
8✔
153
                        continue;
8✔
154
                    }
155
                }
156
                if (!foundCompatibleInnerType) {
11✔
157
                    return false;
3✔
158
                }
159
            }
160
            return true;
3✔
161
        }
162
        for (const innerType of this.types) {
1✔
163
            const foundCompatibleInnerType = innerType.isTypeCompatible(targetType, data);
1✔
164
            if (foundCompatibleInnerType) {
1!
165
                return true;
1✔
166
            }
167
        }
168

NEW
169
        return false;
×
170
    }
171
    toString(): string {
172
        return joinTypesString(this.types, 'and', BscTypeKind.IntersectionType);
1✔
173
    }
174

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

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

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

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

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

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

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

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

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

256
BuiltInInterfaceAdder.intersectionTypeFactory = (types: BscType[]) => {
1✔
NEW
257
    return new IntersectionType(types);
×
258
};
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