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

rokucommunity / brighterscript / #14427

23 May 2025 01:53PM UTC coverage: 87.0% (+0.01%) from 86.989%
#14427

push

web-flow
Merge 12c748f28 into ce167b8d3

13883 of 16865 branches covered (82.32%)

Branch coverage included in aggregate %.

18 of 19 new or added lines in 3 files covered. (94.74%)

1 existing line in 1 file now uncovered.

14734 of 16028 relevant lines covered (91.93%)

21964.04 hits per line

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

71.82
/src/types/ReferenceType.ts
1
import type { GetTypeOptions, TypeChainEntry, TypeCompatibilityData } from '../interfaces';
2
import type { GetSymbolTypeOptions, SymbolTable, SymbolTableProvider, SymbolTypeGetterProvider } from '../SymbolTable';
3
import type { SymbolTypeFlag } from '../SymbolTypeFlag';
4
import { isAnyReferenceType, isArrayDefaultTypeReferenceType, isArrayType, isBinaryOperatorReferenceType, isComponentType, isDynamicType, isParamTypeFromValueReferenceType, isReferenceType, isTypePropertyReferenceType } from '../astUtils/reflection';
1✔
5
import { BscType } from './BscType';
1✔
6
import { DynamicType } from './DynamicType';
1✔
7
import { BscTypeKind } from './BscTypeKind';
1✔
8
import type { Token } from '../lexer/Token';
9
import { util } from '../util';
1✔
10

11
export type AnyReferenceType = ReferenceType | TypePropertyReferenceType | BinaryOperatorReferenceType | ArrayDefaultTypeReferenceType;
12

13
export function referenceTypeFactory(memberKey: string, fullName, flags: SymbolTypeFlag, tableProvider: SymbolTypeGetterProvider) {
1✔
14
    return new ReferenceType(memberKey, fullName, flags, tableProvider);
119,673✔
15
}
16

17
export class ReferenceType extends BscType {
1✔
18

19
    /**
20
     * ReferenceTypes are used when the actual type may be resolved later from a Symbol table
21
     * @param memberKey which key do we use to look up this type in the given table?
22
     * @param fullName the full/display name for this type
23
     * @param flags is this type available at typetime, runtime, etc.
24
     * @param tableProvider function that returns a SymbolTable that we use for the lookup.
25
     */
26
    constructor(public memberKey: string, public fullName, public flags: SymbolTypeFlag, public tableProvider: SymbolTypeGetterProvider) {
121,129✔
27
        super(memberKey);
121,129✔
28
        // eslint-disable-next-line no-constructor-return
29
        return new Proxy(this, {
121,129✔
30
            get: (target, propName, receiver) => {
31

32
                if (propName === '__reflection') {
334,243✔
33
                    // Cheeky way to get `isReferenceType` reflection to work
34
                    return this.__reflection;
268,565✔
35
                }
36
                if (propName === '__identifier') {
65,678✔
37
                    // Cheeky way to get `isReferenceType` reflection to work
38
                    return this.__identifier;
13✔
39
                }
40
                if (propName === 'fullName') {
65,665✔
41
                    return this.fullName;
874✔
42
                }
43
                if (propName === 'isResolvable') {
64,791✔
44
                    return () => {
9,428✔
45
                        let resultSoFar = this.resolve();
9,428✔
46
                        while (resultSoFar && isReferenceType(resultSoFar)) {
9,428✔
47
                            resultSoFar = (resultSoFar as any).getTarget?.();
×
48
                        }
49
                        return !!resultSoFar;
9,428✔
50
                    };
51
                }
52
                if (propName === 'getTarget') {
55,363✔
53
                    return () => {
10,805✔
54
                        return this.resolve();
10,805✔
55
                    };
56
                }
57
                if (propName === 'tableProvider') {
44,558✔
58
                    return this.tableProvider;
36✔
59
                }
60
                if (propName === 'isEqual') {
44,522✔
61
                    //Need to be able to check equality without resolution, because resolution need to check equality
62
                    //To see if you need to make a UnionType
63
                    return (targetType: BscType, data?: TypeCompatibilityData) => {
53✔
64
                        if (!targetType) {
53!
65
                            return false;
×
66
                        }
67
                        const resolvedType = this.resolve();
53✔
68
                        let equal = false;
53✔
69
                        if (resolvedType && !isReferenceType(resolvedType)) {
53✔
70
                            equal = resolvedType.isEqual(targetType, data);
6✔
71
                        } else if (isReferenceType(targetType)) {
47✔
72
                            equal = this.fullName.toLowerCase() === targetType.fullName.toLowerCase() &&
45!
73
                                (this.tableProvider === targetType.tableProvider ||
74
                                    this.tableProvider().name === targetType.tableProvider().name);
75
                        } else {
76
                            equal = targetType.isEqual(this, data);
2✔
77
                        }
78
                        return equal;
53✔
79
                    };
80
                }
81
                if (propName === 'isTypeCompatible') {
44,469✔
82
                    //Need to be able to check equality without resolution, because resolution need to check equality
83
                    //To see if you need to make a UnionType
84
                    return (targetType: BscType, data?: TypeCompatibilityData) => {
2,579✔
85
                        if (!targetType) {
2,579!
86
                            return false;
×
87
                        }
88
                        if (isDynamicType(targetType)) {
2,579!
UNCOV
89
                            return true;
×
90
                        }
91
                        const resolvedType = this.resolve();
2,579✔
92
                        if (resolvedType && !isReferenceType(resolvedType)) {
2,579✔
93
                            return resolvedType.isTypeCompatible(targetType, data);
2,578✔
94
                        } else if (isReferenceType(targetType)) {
1!
95
                            return this.fullName.toLowerCase() === targetType.fullName.toLowerCase() &&
×
96
                                this.tableProvider === targetType.tableProvider;
97
                        }
98
                        return targetType.isTypeCompatible(this, data);
1✔
99
                    };
100
                }
101

102
                //There may be some need to specifically get members on ReferenceType in the future
103
                // eg: if (Reflect.has(target, name)) {
104
                //   return Reflect.get(target, propName, receiver);
105

106
                let innerType = this.resolve();
41,890✔
107

108
                if (!innerType) {
41,890✔
109
                    // No real BscType found - we may need to handle some specific cases
110

111
                    if (propName === 'getMemberType') {
28,785✔
112
                        // We're looking for a member of a reference type
113
                        // Since we don't know what type this is, yet, return ReferenceType
114
                        return (memberName: string, options: GetTypeOptions) => {
1,040✔
115
                            const resolvedType = this.resolve();
1,040✔
116
                            if (resolvedType) {
1,040!
117
                                return resolvedType.getMemberType(memberName, options);
×
118
                            }
119
                            const refLookUp = `${memberName.toLowerCase()}-${options?.flags}`;
1,040!
120
                            let memberTypeReference = this.memberTypeReferences.get(refLookUp);
1,040✔
121
                            if (memberTypeReference) {
1,040✔
122
                                return memberTypeReference;
27✔
123

124
                            }
125
                            memberTypeReference = new ReferenceType(memberName, this.makeMemberFullName(memberName), options.flags, this.futureMemberTableProvider);
1,013✔
126
                            this.memberTypeReferences.set(refLookUp, memberTypeReference);
1,013✔
127
                            return memberTypeReference;
1,013✔
128
                        };
129
                    } else if (propName === 'getCallFuncType') {
27,745✔
130
                        // We're looking for a callfunc member of a reference type
131
                        // Since we don't know what type this is, yet, return ReferenceType
132
                        return (memberName: string, options: GetTypeOptions) => {
8✔
133
                            const resolvedType = this.resolve();
8✔
134
                            if (isComponentType(resolvedType)) {
8!
135
                                return resolvedType.getCallFuncType(memberName, options);
×
136
                            }
137
                            const refLookUp = `${memberName.toLowerCase()}-${options.flags}-callfunc`;
8✔
138
                            let callFuncMemberTypeReference = this.callFuncMemberTypeReferences.get(refLookUp);
8✔
139
                            if (callFuncMemberTypeReference) {
8!
140
                                return callFuncMemberTypeReference;
×
141

142
                            }
143
                            callFuncMemberTypeReference = new ReferenceType(memberName, this.makeMemberFullName(memberName), options.flags, this.futureCallFuncMemberTableProvider);
8✔
144
                            this.callFuncMemberTypeReferences.set(refLookUp, callFuncMemberTypeReference);
8✔
145
                            return callFuncMemberTypeReference;
8✔
146
                        };
147
                    } else if (propName === 'toString') {
27,737✔
148
                        // This type was never found
149
                        // For diagnostics, we should return the expected name of of the type
150
                        return () => this.fullName;
2,414✔
151
                    } else if (propName === 'toTypeString') {
25,323!
152
                        // For transpilation, we should 'dynamic'
153
                        return () => 'dynamic';
×
154
                    } else if (propName === 'returnType') {
25,323✔
155
                        let propRefType = this.propertyTypeReference.get(propName);
62✔
156
                        if (!propRefType) {
62✔
157
                            propRefType = new TypePropertyReferenceType(this, propName);
24✔
158
                            this.propertyTypeReference.set(propName, propRefType);
24✔
159
                        }
160
                        return propRefType;
62✔
161
                    } else if (propName === 'memberTable') {
25,261✔
162
                        return this.memberTable;
99✔
163
                    } else if (propName === 'getMemberTable') {
25,162✔
164
                        return () => {
27✔
165
                            return this.memberTable;
27✔
166
                        };
167
                    } else if (propName === 'callFuncTable') {
25,135!
168
                        return (this as any).callFuncMemberTable;
×
169
                    } else if (propName === 'getCallFuncTable') {
25,135!
170
                        return () => {
×
171
                            return (this as any).callFuncMemberTable;
×
172
                        };
173
                    } else if (propName === 'isTypeCompatible') {
25,135!
174
                        return (targetType: BscType) => {
×
175
                            return isDynamicType(targetType);
×
176
                        };
177
                    } else if (propName === 'isEqual') {
25,135!
178
                        return (targetType: BscType) => {
×
179
                            if (isReferenceType(targetType)) {
×
180
                                return this.fullName.toLowerCase() === targetType.toString().toLowerCase() &&
×
181
                                    this.tableProvider() === targetType.tableProvider();
182
                            }
183
                            return false;
×
184
                        };
185
                    } else if (propName === 'addBuiltInInterfaces') {
25,135✔
186
                        // this is an unknown type. There is no use in adding built in interfaces
187
                        // return no-op function
188
                        return () => { };
42✔
189
                    } else if (propName === 'hasAddedBuiltInInterfaces') {
25,093!
190
                        // this is an unknown type. There is no use in adding built in interfaces
191
                        return true;
×
192
                    } else if (propName === 'isBuiltIn') {
25,093✔
193
                        return false;
23✔
194
                    }
195
                }
196

197
                if (!innerType) {
38,175✔
198
                    innerType = DynamicType.instance;
25,070✔
199
                }
200
                const result = Reflect.get(innerType, propName, innerType);
38,175✔
201
                return result;
38,175✔
202
            },
203
            set: (target, name, value, receiver) => {
204
                //There may be some need to specifically set members on ReferenceType in the future
205
                // eg: if (Reflect.has(target, name)) {
206
                //   return Reflect.set(target, name, value, receiver);
207

208
                let innerType = this.resolve();
516✔
209

210
                // Look for circular references
211
                if (!innerType || this.referenceChain.has(innerType)) {
516!
212
                    if (name === 'hasAddedBuiltInInterfaces') {
×
213
                        // ignore this
214
                        return true;
×
215
                    }
216
                    console.log(`Proxy set error`, name, value, innerType);
×
217
                    const error = new Error(`Reference Type Proxy set error: ${{ memberKey: memberKey, name: name, value: value }}`);
×
218
                    console.log(error.stack);
×
219
                    return false;
×
220
                }
221
                const result = Reflect.set(innerType, name, value, innerType);
516✔
222
                this.referenceChain.clear();
516✔
223
                return result;
516✔
224
            }
225
        });
226
    }
227

228
    public readonly kind = BscTypeKind.ReferenceType;
121,129✔
229

230
    getTarget() {
231
        return this.resolve();
166✔
232
    }
233

234
    /**
235
     * Resolves the type based on the original name and the table provider
236
     */
237
    private resolve(): BscType {
238
        const symbolTable = this.tableProvider();
81,838✔
239
        if (!symbolTable) {
81,838✔
240
            return;
12✔
241
        }
242
        // Look for circular references
243
        let resolvedType = symbolTable.getSymbolType(this.memberKey, { flags: this.flags, onlyCacheResolvedTypes: true });
81,826✔
244
        if (!resolvedType) {
81,826✔
245
            // could not find this member
246
            return;
46,309✔
247
        }
248
        if (isAnyReferenceType(resolvedType)) {
35,517✔
249
            // If this is a referenceType, keep digging down until we have a non reference Type.
250
            while (resolvedType && isAnyReferenceType(resolvedType)) {
2,072✔
251
                if (this.referenceChain.has(resolvedType)) {
2,072✔
252
                    // this is a circular reference
253
                    this.circRefCount++;
1,310✔
254
                }
255
                if (this.circRefCount > 1) {
2,072✔
256
                    //It is possible that we could properly resolve the case that one reference points to itself
257
                    //see test: '[Scope][symbolTable lookups with enhanced typing][finds correct class field type with default value enums are used]
258
                    return;
1,251✔
259
                }
260
                this.referenceChain.add(resolvedType);
821✔
261
                resolvedType = (resolvedType as any)?.getTarget?.();
821!
262
            }
263
            this.tableProvider().setCachedType(this.memberKey, { type: resolvedType }, { flags: this.flags });
821✔
264
        }
265

266
        if (resolvedType && !isAnyReferenceType(resolvedType)) {
34,266✔
267
            this.circRefCount = 0;
33,449✔
268
            this.referenceChain.clear();
33,449✔
269
        }
270
        return resolvedType;
34,266✔
271
    }
272

273
    get __reflection() {
274
        return { name: 'ReferenceType' };
268,877✔
275
    }
276

277
    makeMemberFullName(memberName: string) {
278
        return this.fullName + '.' + memberName;
1,021✔
279
    }
280
    private circRefCount = 0;
121,129✔
281

282
    private referenceChain = new Set<BscType>();
121,129✔
283

284
    private propertyTypeReference = new Map<string, TypePropertyReferenceType>();
121,129✔
285

286
    private memberTypeReferences = new Map<string, ReferenceType>();
121,129✔
287
    private callFuncMemberTypeReferences = new Map<string, ReferenceType>();
121,129✔
288

289
    private futureMemberTableProvider = () => {
121,129✔
290
        return {
15,007✔
291
            name: `FutureMemberTableProvider: '${this.__identifier}'`,
292
            getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
293
                const resolvedType = this.resolve();
14,304✔
294
                if (resolvedType) {
14,304✔
295
                    return resolvedType.getMemberType(innerName, innerOptions);
7,890✔
296
                }
297
            },
298
            setCachedType: (innerName: string, innerResolvedTypeCacheEntry: TypeChainEntry, options: GetSymbolTypeOptions) => {
299
                const resolvedType = this.resolve();
703✔
300
                if (resolvedType) {
703!
301
                    resolvedType.memberTable.setCachedType(innerName, innerResolvedTypeCacheEntry, options);
703✔
302
                }
303
            },
304
            addSibling: (symbolTable: SymbolTable) => {
305
                const resolvedType = this.resolve();
×
306
                if (resolvedType) {
×
307
                    resolvedType.memberTable?.addSibling?.(symbolTable);
×
308
                }
309
            }
310
        };
311
    };
312

313
    private futureCallFuncMemberTableProvider = () => {
121,129✔
314
        return {
346✔
315
            name: `FutureCallFuncMemberTableProvider: '${this.__identifier}'`,
316
            getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
317
                const resolvedType = this.resolve();
346✔
318
                if (isComponentType(resolvedType)) {
346✔
319
                    return resolvedType.getCallFuncType(innerName, innerOptions);
199✔
320
                }
321
            },
322
            setCachedType: (innerName: string, innerResolvedTypeCacheEntry: TypeChainEntry, options: GetSymbolTypeOptions) => {
323
                const resolvedType = this.resolve();
×
324
                if (isComponentType(resolvedType)) {
×
325
                    resolvedType.getCallFuncTable().setCachedType(innerName, innerResolvedTypeCacheEntry, options);
×
326
                }
327
            },
328
            addSibling: (symbolTable: SymbolTable) => {
329
                const resolvedType = this.resolve();
×
330
                if (isComponentType(resolvedType)) {
×
331
                    resolvedType.getCallFuncTable()?.addSibling?.(symbolTable);
×
332
                }
333
            }
334
        };
335
    };
336
}
337

338
/**
339
 * Use this class for when you need to reference a property of a BscType, and that property is also a BscType,
340
 * Especially when the instance with the property may not have been instantiated/discovered yet
341
 *
342
 * For Example, FunctionType.returnType --- if the FunctionExpression has not been walked yet, it will be a ReferenceType
343
 * if we just access .returnType on a ReferenceType that doesn't have access to an actual FunctionType yet, .returnType will be undefined
344
 * So when we use this class, it maintains that reference to a potential ReferenceType, and this class will change from
345
 * returning undefined to the ACTUAL .returnType when the ReferenceType can be resolved.
346
 *
347
 * This is really cool. It's like programming with time-travel.
348
 */
349
export class TypePropertyReferenceType extends BscType {
1✔
350
    constructor(public outerType: BscType, public propertyName: string) {
89✔
351
        super(propertyName);
89✔
352
        // eslint-disable-next-line no-constructor-return
353
        return new Proxy(this, {
89✔
354
            get: (target, propName, receiver) => {
355

356
                if (propName === '__reflection') {
1,165✔
357
                    // Cheeky way to get `isTypePropertyReferenceType` reflection to work
358
                    return { name: 'TypePropertyReferenceType' };
269✔
359
                }
360

361
                if (propName === 'outerType') {
896!
362
                    return outerType;
×
363
                }
364

365
                if (propName === 'isResolvable') {
896✔
366
                    return () => {
107✔
367
                        return !!(isAnyReferenceType(this.outerType) ? (this.outerType as any).getTarget() : this.outerType?.isResolvable());
107!
368
                    };
369
                }
370

371
                if (isAnyReferenceType(this.outerType) && !this.outerType.isResolvable()) {
789✔
372
                    if (propName === 'getMemberType') {
116✔
373
                        //If we're calling `getMemberType()`, we need it to proxy to using the actual symbol table
374
                        //So if that symbol is ever populated, the correct type is passed through
375
                        return (memberName: string, options: GetSymbolTypeOptions) => {
16✔
376
                            const fullMemberName = this.outerType.toString() + '.' + memberName;
16✔
377
                            return new ReferenceType(memberName, fullMemberName, options.flags, () => {
16✔
378
                                return {
52✔
379
                                    name: `TypePropertyReferenceType : '${fullMemberName}'`,
380
                                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
381
                                        return this.outerType?.[this.propertyName]?.getMemberType(innerName, innerOptions);
52!
382
                                    },
383
                                    setCachedType: (innerName: string, innerTypeCacheEntry: TypeChainEntry, innerOptions: GetTypeOptions) => {
384
                                        return this.outerType?.[this.propertyName]?.memberTable.setCachedType(innerName, innerTypeCacheEntry, innerOptions);
×
385
                                    },
386
                                    addSibling: (symbolTable: SymbolTable) => {
387
                                        return this.outerType?.[this.propertyName]?.memberTable?.addSibling?.(symbolTable);
×
388
                                    }
389
                                };
390
                            });
391
                        };
392
                    }
393
                    if (propName === 'isResolvable') {
100!
394
                        return () => false;
×
395
                    }
396
                }
397
                let inner = (isAnyReferenceType(this.outerType) ? (this.outerType as ReferenceType).getTarget() : this.outerType)?.[this.propertyName];
773✔
398

399
                if (!inner) {
773✔
400
                    inner = DynamicType.instance;
213✔
401
                }
402

403
                if (inner) {
773!
404
                    const result = Reflect.get(inner, propName, inner);
773✔
405
                    return result;
773✔
406
                }
407
            },
408
            set: (target, name, value, receiver) => {
409
                //There may be some need to specifically set members on ReferenceType in the future
410
                // eg: if (Reflect.has(target, name)) {
411
                //   return Reflect.set(target, name, value, receiver);
412

413
                let inner = this.outerType[this.propertyName];
8✔
414

415
                if (inner) {
8!
416
                    const result = Reflect.set(inner, name, value, inner);
8✔
417
                    return result;
8✔
418
                }
419
            }
420
        });
421
    }
422

423
    getTarget: () => BscType;
424

425
    tableProvider: SymbolTableProvider;
426
}
427

428

429
/**
430
 * Use this class for when there is a binary operator and either the left hand side and/or the right hand side
431
 * are ReferenceTypes
432
 */
433
export class BinaryOperatorReferenceType extends BscType {
1✔
434
    cachedType: BscType;
435

436
    constructor(public leftType: BscType, public operator: Token, public rightType: BscType, binaryOpResolver: (lType: BscType, operator: Token, rType: BscType) => BscType) {
34✔
437
        super(operator.text);
34✔
438
        // eslint-disable-next-line no-constructor-return
439
        return new Proxy(this, {
34✔
440
            get: (target, propName, receiver) => {
441

442
                if (propName === '__reflection') {
661✔
443
                    // Cheeky way to get `BinaryOperatorReferenceType` reflection to work
444
                    return { name: 'BinaryOperatorReferenceType' };
200✔
445
                }
446

447
                if (propName === 'leftType') {
461✔
448
                    return leftType;
6✔
449
                }
450

451
                if (propName === 'rightType') {
455✔
452
                    return rightType;
6✔
453
                }
454

455
                let resultType: BscType = this.cachedType ?? DynamicType.instance;
449✔
456
                if (!this.cachedType) {
449✔
457
                    if ((isAnyReferenceType(this.leftType) && !this.leftType.isResolvable()) ||
113✔
458
                        (isAnyReferenceType(this.rightType) && !this.rightType.isResolvable())
459
                    ) {
460
                        if (propName === 'isResolvable') {
108✔
461
                            return () => false;
68✔
462
                        }
463
                        if (propName === 'getTarget') {
40✔
464
                            return () => undefined;
2✔
465
                        }
466
                    } else {
467
                        resultType = binaryOpResolver(this.leftType, this.operator, this.rightType) ?? DynamicType.instance;
5!
468
                        this.cachedType = resultType;
5✔
469
                    }
470

471
                }
472
                if (resultType) {
379!
473
                    const result = Reflect.get(resultType, propName, resultType);
379✔
474
                    return result;
379✔
475
                }
476
            }
477
        });
478
    }
479

480
    getTarget: () => BscType;
481

482
    tableProvider: SymbolTableProvider;
483
}
484

485

486
/**
487
 * Use this class for when there is a presumable array type that is a referenceType
488
 */
489
export class ArrayDefaultTypeReferenceType extends BscType {
1✔
490
    constructor(public objType: BscType) {
28✔
491
        super('ArrayDefaultType');
28✔
492
        // eslint-disable-next-line no-constructor-return
493
        return new Proxy(this, {
28✔
494
            get: (target, propName, receiver) => {
495

496
                if (propName === '__reflection') {
988✔
497
                    // Cheeky way to get `ArrayDefaultTypeReferenceType` reflection to work
498
                    return { name: 'ArrayDefaultTypeReferenceType' };
395✔
499
                }
500

501
                if (propName === 'objType') {
593!
502
                    return objType;
×
503
                }
504

505
                if (propName === 'getTarget') {
593!
506
                    return () => {
×
507
                        if (isReferenceType(this.objType)) {
×
508
                            (this.objType as any).getTarget();
×
509
                        }
510
                        return this.objType;
×
511
                    };
512
                }
513

514
                let resultType: BscType = DynamicType.instance;
593✔
515
                if ((isAnyReferenceType(this.objType) && !this.objType.isResolvable())
593✔
516
                ) {
517
                    if (propName === 'isResolvable') {
2✔
518
                        return () => false;
1✔
519
                    }
520
                    if (propName === 'getTarget') {
1!
NEW
521
                        return () => undefined;
×
522
                    }
523
                } else {
524
                    if (isArrayType(this.objType)) {
591✔
525
                        resultType = this.objType.defaultType;
466✔
526
                    } else {
527
                        resultType = DynamicType.instance;
125✔
528
                    }
529
                }
530

531
                if (resultType) {
592!
532
                    const result = Reflect.get(resultType, propName, resultType);
592✔
533
                    return result;
592✔
534
                }
535
            }
536
        });
537
    }
538

539
    getTarget: () => BscType;
540

541
    tableProvider: SymbolTableProvider;
542
}
543

544
/**
545
 * Used for when a Param's initial value is unresolved
546
 * Generally, this will be resolved later *except* for Enum
547
 * Enum Types will have an initial value of an EnumMemberType, but the param
548
 * should be an EnumType
549
 */
550
export class ParamTypeFromValueReferenceType extends BscType {
1✔
551
    cachedType: BscType;
552

553
    constructor(public objType: BscType) {
445✔
554
        super('ParamInitialValueType');
445✔
555
        // eslint-disable-next-line no-constructor-return
556
        return new Proxy(this, {
445✔
557
            get: (target, propName, receiver) => {
558
                if (propName === '__reflection') {
3,350✔
559
                    // Cheeky way to get reflection to work
560
                    return { name: 'ParamTypeFromValueReferenceType' };
929✔
561
                }
562

563
                if (propName === 'objType') {
2,421!
564
                    return objType;
×
565
                }
566

567
                if (propName === 'getTarget') {
2,421✔
568
                    return () => {
3✔
569
                        if (this.cachedType) {
3!
570
                            return this.cachedType;
3✔
571
                        }
572
                        if (isReferenceType(this.objType)) {
×
573
                            (this.objType as any).getTarget();
×
574
                        }
575
                        return this.objType;
×
576
                    };
577
                }
578

579
                let resultType: BscType = this.cachedType ?? DynamicType.instance;
2,418✔
580
                if (!this.cachedType) {
2,418✔
581
                    if ((isAnyReferenceType(this.objType) && !this.objType.isResolvable())
992✔
582
                    ) {
583
                        if (propName === 'isResolvable') {
871✔
584
                            return () => false;
7✔
585
                        }
586
                        if (propName === 'getTarget') {
864!
587
                            return () => undefined;
×
588
                        }
589
                    } else {
590
                        resultType = util.getDefaultTypeFromValueType(this.objType);
121✔
591
                        this.cachedType = resultType;
121✔
592
                    }
593

594
                }
595
                if (resultType) {
2,411!
596
                    const result = Reflect.get(resultType, propName, resultType);
2,411✔
597
                    return result;
2,411✔
598
                }
599
            }
600
        });
601
    }
602
}
603

604
/**
605
 * Gives an array of all the symbol names that need to be resolved to make the given reference type be resolved
606
 */
607
export function getAllRequiredSymbolNames(refType: BscType, namespaceLower?: string): Array<{ name: string; namespacedName?: string }> {
1✔
608
    if (refType.isResolvable()) {
75✔
609
        return [];
6✔
610
    }
611
    if (isReferenceType(refType)) {
69✔
612
        return [{ name: refType.fullName, namespacedName: namespaceLower ? `${namespaceLower}.${refType.fullName}` : null }];
63✔
613
    }
614
    if (isTypePropertyReferenceType(refType)) {
6!
615
        const outer = refType.outerType;
×
616
        if (isAnyReferenceType(outer)) {
×
617
            return getAllRequiredSymbolNames(outer);
×
618
        } else {
619
            return [];
×
620
        }
621

622
    }
623
    if (isArrayDefaultTypeReferenceType(refType)) {
6!
624
        const objType = refType.objType;
×
625
        if (isAnyReferenceType(objType)) {
×
626
            return getAllRequiredSymbolNames(objType);
×
627
        } else {
628
            return [];
×
629
        }
630
    }
631
    if (isBinaryOperatorReferenceType(refType)) {
6!
632
        const left = refType.leftType;
6✔
633
        const right = refType.rightType;
6✔
634
        const result = [];
6✔
635
        if (isAnyReferenceType(left)) {
6✔
636
            result.push(...getAllRequiredSymbolNames(left, namespaceLower));
4✔
637
        }
638
        if (isAnyReferenceType(right)) {
6!
639
            result.push(...getAllRequiredSymbolNames(right, namespaceLower));
6✔
640

641
        }
642
        return result;
6✔
643
    }
644
    if (isParamTypeFromValueReferenceType(refType)) {
×
645
        const objType = refType.objType;
×
646
        if (isAnyReferenceType(objType)) {
×
647
            return getAllRequiredSymbolNames(objType);
×
648
        } else {
649
            return [];
×
650
        }
651
    }
652
    return [];
×
653
}
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