• 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

90.24
/src/types/UnionType.ts
1
import type { GetTypeOptions, TypeCompatibilityData } from '../interfaces';
2
import { isDynamicType, isObjectType, isTypedFunctionType, isUnionType } from '../astUtils/reflection';
1✔
3
import { BscType } from './BscType';
1✔
4
import { ReferenceType } from './ReferenceType';
1✔
5
import { addAssociatedTypesTableAsSiblingToMemberTable, findTypeUnion, findTypeUnionDeepCheck, getAllTypesFromComplexType, 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);
144,173✔
15
}
16

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

25
    public readonly kind = BscTypeKind.UnionType;
144,435✔
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) {
212✔
35
            if (!type.isResolvable()) {
419✔
36
                return false;
12✔
37
            }
38
        }
39
        return true;
200✔
40
    }
41

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

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

50
    getMemberType(name: string, options: GetTypeOptions) {
51
        const innerTypesMemberTypes = this.getMemberTypeFromInnerTypes(name, options);
58✔
52
        if (!innerTypesMemberTypes || innerTypesMemberTypes.includes(undefined)) {
58✔
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 {
132✔
57
                    name: `UnionType MemberTable: '${this.__identifier}'`,
58
                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
59
                        const referenceTypeInnerMemberTypes = this.getMemberTypeFromInnerTypes(name, options);
132✔
60
                        if (!referenceTypeInnerMemberTypes || referenceTypeInnerMemberTypes.includes(undefined)) {
132!
61
                            return undefined;
132✔
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);
51✔
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 {
14✔
84
                    name: `UnionType CallFunc MemberTable: '${this.__identifier}'`,
85
                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
86
                        const referenceTypeInnerMemberTypes = this.getCallFuncFromInnerTypes(name, options);
14✔
87
                        if (!referenceTypeInnerMemberTypes || referenceTypeInnerMemberTypes.includes(undefined)) {
14!
88
                            return undefined;
14✔
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);
5✔
116
    }
117

118

119
    isTypeCompatible(targetType: BscType, data?: TypeCompatibilityData): boolean {
120
        if (isDynamicType(targetType) || isObjectType(targetType) || this === targetType) {
111✔
121
            return true;
72✔
122
        }
123
        if (isEnumTypeCompatible(this, targetType, data)) {
39!
124
            return true;
×
125
        }
126
        if (isUnionType(targetType)) {
39✔
127
            // check if this set of inner types is a SUPERSET of targetTypes's inner types
128
            for (const targetInnerType of targetType.types) {
4✔
129
                if (!this.isTypeCompatible(targetInnerType, data)) {
12✔
130
                    return false;
2✔
131
                }
132
            }
133
            return true;
2✔
134
        }
135
        for (const innerType of this.types) {
35✔
136
            const foundCompatibleInnerType = innerType.isTypeCompatible(targetType, data);
58✔
137
            if (foundCompatibleInnerType) {
58✔
138
                return true;
31✔
139
            }
140
        }
141

142
        return false;
4✔
143
    }
144
    toString(): string {
145
        return joinTypesString(this.types, 'or', BscTypeKind.UnionType);
480✔
146
    }
147

148
    /**
149
     * Used for transpilation
150
     */
151
    toTypeString(): string {
152
        const uniqueTypeStrings = new Set<string>(getAllTypesFromComplexType(this).map(t => t.toTypeString()));
51✔
153

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

160
    checkAllMemberTypes(predicate: (BscType) => boolean) {
161
        return this.types.reduce((acc, type) => {
×
162
            return acc && predicate(type);
×
163
        }, true);
164
    }
165

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

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

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

205
            if (!allResolvableTypes) {
251✔
206
                continue;
148✔
207
            }
208
            const uniqueType = getUniqueType(findTypeUnion(foundType), unionTypeFactory);
103✔
209
            unionTable.addSymbol(symbol.name, {}, uniqueType, SymbolTypeFlag.runtime);
103✔
210
        }
211
        return unionTable;
26✔
212
    }
213
}
214

215

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