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

rokucommunity / brighterscript / #15035

15 Dec 2025 08:42PM UTC coverage: 86.889%. Remained the same
#15035

push

web-flow
Merge a60226157 into 2ea4d2108

14466 of 17575 branches covered (82.31%)

Branch coverage included in aggregate %.

113 of 217 new or added lines in 8 files covered. (52.07%)

116 existing lines in 6 files now uncovered.

15185 of 16550 relevant lines covered (91.75%)

24075.2 hits per line

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

36.47
/src/types/IntersectionType.ts
1
import type { GetTypeOptions, TypeCompatibilityData } from '../interfaces';
2
import { 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

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

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

25
    public readonly kind = BscTypeKind.IntersectionType;
12✔
26

27
    public readonly callFuncAssociatedTypesTable: SymbolTable;
28

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

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

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

49
        if (filteredTypes.length === 0) {
8!
NEW
50
            return undefined;
×
51
        } else if (filteredTypes.length === 1) {
8✔
52
            return filteredTypes[0];
4✔
53
        }
54
        return new IntersectionType(filteredTypes);
4✔
55
    }
56

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

NEW
60
        if (typeFromMembers.length === 0) {
×
NEW
61
            return undefined;
×
NEW
62
        } else if (typeFromMembers.length === 1) {
×
NEW
63
            return typeFromMembers[0];
×
64
        }
NEW
65
        return new IntersectionType(typeFromMembers);
×
66
    }
67

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

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

NEW
120
        if (isTypedFunctionType(resultCallFuncType)) {
×
NEW
121
            const typesToCheck = [...resultCallFuncType.params.map(p => p.type), resultCallFuncType.returnType];
×
122

NEW
123
            for (const type of typesToCheck) {
×
NEW
124
                addAssociatedTypesTableAsSiblingToMemberTable(type, this.callFuncAssociatedTypesTable, SymbolTypeFlag.runtime);
×
125
            }
126
        }
NEW
127
        return resultCallFuncType;
×
128
    }
129

130
    get returnType() {
NEW
131
        return util.getReturnTypeOfIntersectionOfFunctions(this);
×
132
    }
133

134

135
    isTypeCompatible(targetType: BscType, data?: TypeCompatibilityData): boolean {
136
        if (isDynamicType(targetType) || isObjectType(targetType) || this === targetType) {
2!
NEW
137
            return true;
×
138
        }
139
        if (isEnumTypeCompatible(this, targetType, data)) {
2!
NEW
140
            return true;
×
141
        }
142
        if (isIntersectionType(targetType)) {
2!
143
            // check if this all the types of this type are in the target (eg, target is a super set of this types)
144
            for (const memberType of this.types) {
2✔
145
                let foundCompatibleInnerType = false;
5✔
146
                for (const targetInnerType of targetType.types) {
5✔
147
                    if (memberType.isTypeCompatible(targetInnerType, data)) {
12✔
148
                        foundCompatibleInnerType = true;
4✔
149
                        continue;
4✔
150
                    }
151
                }
152
                if (!foundCompatibleInnerType) {
5✔
153
                    return false;
1✔
154
                }
155
            }
156
            return true;
1✔
157
        }
NEW
158
        for (const innerType of this.types) {
×
NEW
159
            const foundCompatibleInnerType = innerType.isTypeCompatible(targetType, data);
×
NEW
160
            if (foundCompatibleInnerType) {
×
NEW
161
                return true;
×
162
            }
163
        }
164

NEW
165
        return false;
×
166
    }
167
    toString(): string {
168
        return joinTypesString(this.types, 'and', BscTypeKind.IntersectionType);
1✔
169
    }
170

171
    /**
172
     * Used for transpilation
173
     */
174
    toTypeString(): string {
NEW
175
        const uniqueTypeStrings = new Set<string>(getAllTypesFromComplexType(this).map(t => t.toTypeString()));
×
176

NEW
177
        if (uniqueTypeStrings.size === 1) {
×
NEW
178
            return uniqueTypeStrings.values().next().value;
×
179
        }
NEW
180
        return 'dynamic';
×
181
    }
182

183
    checkAllMemberTypes(predicate: (BscType) => boolean) {
NEW
184
        return this.types.reduce((acc, type) => {
×
NEW
185
            return acc && predicate(type);
×
186
        }, true);
187
    }
188

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

211
    getMemberTable(): SymbolTable {
NEW
212
        const intersectionTable = new SymbolTable(this.__identifier + ' IntersectionTable');
×
213

NEW
214
        for (const type of this.types) {
×
NEW
215
            type.addBuiltInInterfaces();
×
NEW
216
            for (const symbol of type.getMemberTable().getAllSymbols(SymbolTypeFlag.runtime)) {
×
NEW
217
                const foundType = this.getMemberTypeFromInnerTypes(symbol.name, { flags: SymbolTypeFlag.runtime });
×
218
                /*
219

220
                const allResolvableTypes = foundType.reduce((acc, curType) => {
221
                    return acc && curType?.isResolvable();
222
                }, true);
223

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

242
             if (!allResolvableTypes) {
243
                 continue;
244
             }
245
             const uniqueType = getUniqueType(findTypeUnion(foundType), unionTypeFactory);*/
NEW
246
            intersectionTable.addSymbol(symbol.name, {}, foundType, SymbolTypeFlag.runtime);
×
247
        }
NEW
248
        return intersectionTable;
×
249
    }
250
}
251

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

© 2025 Coveralls, Inc