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

rokucommunity / brighterscript / #15219

22 Feb 2026 02:27AM UTC coverage: 87.193% (-0.006%) from 87.199%
#15219

push

web-flow
Merge d0c9a16a7 into 1556715dd

14749 of 17875 branches covered (82.51%)

Branch coverage included in aggregate %.

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

161 existing lines in 16 files now uncovered.

15493 of 16809 relevant lines covered (92.17%)

25604.58 hits per line

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

90.36
/src/types/UnionType.ts
1
import type { GetTypeOptions, TypeCompatibilityData } from '../interfaces';
2
import { isDynamicType, isObjectType, isTypedFunctionType, isTypeStatementType, isUnionType } from '../astUtils/reflection';
1✔
3
import { BscType } from './BscType';
1✔
4
import { ReferenceType } from './ReferenceType';
1✔
5
import { addAssociatedTypesTableAsSiblingToMemberTable, findTypeUnion, findTypeUnionDeepCheck, getAllTypesFromCompoundType, getUniqueType, isEnumTypeCompatible, joinTypesString } 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 unionTypeFactory(types: BscType[]) {
1✔
14
    return new UnionType(types);
150,634✔
15
}
16

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

25
    public readonly kind = BscTypeKind.UnionType;
150,993✔
26

27
    public readonly callFuncAssociatedTypesTable: SymbolTable;
28

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

33
    isResolvable(): boolean {
34
        for (const type of this.types) {
249✔
35
            if (!type.isResolvable()) {
494✔
36
                return false;
12✔
37
            }
38
        }
39
        return true;
237✔
40
    }
41

42
    private getMemberTypeFromInnerTypes(name: string, options: GetTypeOptions) {
43
        return this.types.map((innerType) => innerType?.getMemberType(name, options));
861!
44
    }
45

46
    private getCallFuncFromInnerTypes(name: string, options: GetTypeOptions) {
47
        return this.types.map((innerType) => innerType?.getCallFuncType(name, options));
54!
48
    }
49

50
    getMemberType(name: string, options: GetTypeOptions) {
51
        const innerTypesMemberTypes = this.getMemberTypeFromInnerTypes(name, options);
70✔
52
        if (!innerTypesMemberTypes || innerTypesMemberTypes.includes(undefined)) {
70✔
53
            // We don't have any members of any inner types that match
54
            // so instead, create reference type that will
55
            return new ReferenceType(name, name, options.flags, () => {
7✔
56
                return {
162✔
57
                    name: `UnionType MemberTable: '${this.__identifier}'`,
58
                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
59
                        const referenceTypeInnerMemberTypes = this.getMemberTypeFromInnerTypes(name, options);
162✔
60
                        if (!referenceTypeInnerMemberTypes || referenceTypeInnerMemberTypes.includes(undefined)) {
162!
61
                            return undefined;
162✔
62
                        }
63
                        return getUniqueType(findTypeUnion(referenceTypeInnerMemberTypes), unionTypeFactory);
×
64
                    },
65
                    setCachedType: (innerName: string, innerCacheEntry: TypeCacheEntry, innerOptions: GetTypeOptions) => {
66
                        // TODO: is this even cachable? This is a NO-OP for now, and it shouldn't hurt anything
67
                    },
68
                    addSibling: (symbolTable: SymbolTable) => {
69
                        // TODO: I don't know what this means in this context?
70
                    }
71
                };
72
            });
73
        }
74
        return getUniqueType(findTypeUnion(innerTypesMemberTypes), unionTypeFactory);
63✔
75
    }
76

77
    getCallFuncType(name: string, options: GetTypeOptions) {
78
        const innerTypesMemberTypes = this.getCallFuncFromInnerTypes(name, options);
7✔
79
        if (!innerTypesMemberTypes || innerTypesMemberTypes.includes(undefined)) {
7✔
80
            // We don't have any members of any inner types that match
81
            // so instead, create reference type that will
82
            return new ReferenceType(name, name, options.flags, () => {
1✔
83
                return {
20✔
84
                    name: `UnionType CallFunc MemberTable: '${this.__identifier}'`,
85
                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
86
                        const referenceTypeInnerMemberTypes = this.getCallFuncFromInnerTypes(name, options);
20✔
87
                        if (!referenceTypeInnerMemberTypes || referenceTypeInnerMemberTypes.includes(undefined)) {
20!
88
                            return undefined;
20✔
89
                        }
90
                        return getUniqueType(findTypeUnionDeepCheck(referenceTypeInnerMemberTypes), unionTypeFactory);
×
91
                    },
92
                    setCachedType: (innerName: string, innerCacheEntry: TypeCacheEntry, innerOptions: GetTypeOptions) => {
93
                        // TODO: is this even cachable? This is a NO-OP for now, and it shouldn't hurt anything
94
                    },
95
                    addSibling: (symbolTable: SymbolTable) => {
96
                        // TODO: I don't know what this means in this context?
97
                    }
98
                };
99
            });
100
        }
101
        const resultCallFuncType = getUniqueType(findTypeUnionDeepCheck(innerTypesMemberTypes), unionTypeFactory, false);
6✔
102

103

104
        if (isTypedFunctionType(resultCallFuncType)) {
6✔
105
            const typesToCheck = [...resultCallFuncType.params.map(p => p.type), resultCallFuncType.returnType];
1✔
106

107
            for (const type of typesToCheck) {
1✔
108
                addAssociatedTypesTableAsSiblingToMemberTable(type, this.callFuncAssociatedTypesTable, SymbolTypeFlag.runtime);
1✔
109
            }
110
        }
111
        return resultCallFuncType;
6✔
112
    }
113

114
    get returnType() {
115
        return util.getReturnTypeOfUnionOfFunctions(this);
29✔
116
    }
117

118

119
    isTypeCompatible(targetType: BscType, data?: TypeCompatibilityData): boolean {
120
        while (isTypeStatementType(targetType)) {
61✔
121
            targetType = targetType.wrappedType;
1✔
122
        }
123
        if (isDynamicType(targetType) || isObjectType(targetType) || this === targetType) {
61✔
124
            return true;
6✔
125
        }
126
        if (isEnumTypeCompatible(this, targetType, data)) {
55!
UNCOV
127
            return true;
×
128
        }
129
        if (isUnionType(targetType)) {
55✔
130
            // check if this set of inner types is a SUPERSET of targetTypes's inner types
131
            for (const targetInnerType of targetType.types) {
7✔
132
                if (!this.isTypeCompatible(targetInnerType, data)) {
19✔
133
                    return false;
2✔
134
                }
135
            }
136
            return true;
5✔
137
        }
138
        for (const innerType of this.types) {
48✔
139
            const foundCompatibleInnerType = innerType.isTypeCompatible(targetType, data);
79✔
140
            if (foundCompatibleInnerType) {
79✔
141
                return true;
42✔
142
            }
143
        }
144

145
        return false;
6✔
146
    }
147
    toString(): string {
148
        return joinTypesString(this.types, 'or', BscTypeKind.UnionType);
495✔
149
    }
150

151
    /**
152
     * Used for transpilation
153
     */
154
    toTypeString(): string {
155
        const uniqueTypeStrings = new Set<string>(getAllTypesFromCompoundType(this).map(t => t.toTypeString()));
51✔
156

157
        if (uniqueTypeStrings.size === 1) {
21✔
158
            return uniqueTypeStrings.values().next().value;
9✔
159
        }
160
        return 'dynamic';
12✔
161
    }
162

163
    checkAllMemberTypes(predicate: (BscType) => boolean) {
UNCOV
164
        return this.types.reduce((acc, type) => {
×
UNCOV
165
            return acc && predicate(type);
×
166
        }, true);
167
    }
168

169
    isEqual(targetType: BscType): boolean {
170
        if (!isUnionType(targetType)) {
29✔
171
            return false;
8✔
172
        }
173
        if (this === targetType) {
21✔
174
            return true;
13✔
175
        }
176

177
        if (this.types.length !== targetType.types.length) {
8!
UNCOV
178
            return false;
×
179
        }
180
        for (const type of this.types) {
8✔
181
            let foundMatch = false;
11✔
182
            for (const targetTypeInner of targetType.types) {
11✔
183
                if (type.isEqual(targetTypeInner)) {
20✔
184
                    foundMatch = true;
5✔
185
                    break;
5✔
186
                }
187
            }
188
            if (!foundMatch) {
11✔
189
                return false;
6✔
190
            }
191
        }
192
        return true;
2✔
193
    }
194

195
    getMemberTable(): SymbolTable {
196
        const unionTable = new SymbolTable(this.__identifier + ' UnionTable');
26✔
197
        const firstType = this.types[0];
26✔
198
        if (!firstType) {
26!
UNCOV
199
            return unionTable;
×
200
        }
201
        firstType.addBuiltInInterfaces();
26✔
202
        for (const symbol of firstType.getMemberTable().getAllSymbols(SymbolTypeFlag.runtime)) {
26✔
203
            const foundType = this.getMemberTypeFromInnerTypes(symbol.name, { flags: SymbolTypeFlag.runtime });
196✔
204
            const allResolvableTypes = foundType.reduce((acc, curType) => {
196✔
205
                return acc && curType?.isResolvable();
397✔
206
            }, true);
207

208
            if (!allResolvableTypes) {
196✔
209
                continue;
99✔
210
            }
211
            const uniqueType = getUniqueType(findTypeUnion(foundType), unionTypeFactory);
97✔
212
            unionTable.addSymbol(symbol.name, {}, uniqueType, SymbolTypeFlag.runtime);
97✔
213
        }
214
        return unionTable;
26✔
215
    }
216
}
217

218

219
BuiltInInterfaceAdder.unionTypeFactory = (types: BscType[]) => {
1✔
220
    return new UnionType(types);
7✔
221
};
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