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

rokucommunity / brighterscript / #14385

09 May 2025 11:44AM UTC coverage: 87.032% (-2.0%) from 89.017%
#14385

push

web-flow
Merge a194c3925 into 489231ac7

13732 of 16677 branches covered (82.34%)

Branch coverage included in aggregate %.

8175 of 8874 new or added lines in 103 files covered. (92.12%)

84 existing lines in 22 files now uncovered.

14604 of 15881 relevant lines covered (91.96%)

20324.31 hits per line

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

71.72
/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,024✔
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) {
120,484✔
27
        super(memberKey);
120,484✔
28
        // eslint-disable-next-line no-constructor-return
29
        return new Proxy(this, {
120,484✔
30
            get: (target, propName, receiver) => {
31

32
                if (propName === '__reflection') {
331,892✔
33
                    // Cheeky way to get `isReferenceType` reflection to work
34
                    return this.__reflection;
267,185✔
35
                }
36
                if (propName === '__identifier') {
64,707✔
37
                    // Cheeky way to get `isReferenceType` reflection to work
38
                    return this.__identifier;
13✔
39
                }
40
                if (propName === 'fullName') {
64,694✔
41
                    return this.fullName;
883✔
42
                }
43
                if (propName === 'isResolvable') {
63,811✔
44
                    return () => {
9,588✔
45
                        let resultSoFar = this.resolve();
9,588✔
46
                        while (resultSoFar && isReferenceType(resultSoFar)) {
9,588✔
NEW
47
                            resultSoFar = (resultSoFar as any).getTarget?.();
×
48
                        }
49
                        return !!resultSoFar;
9,588✔
50
                    };
51
                }
52
                if (propName === 'getTarget') {
54,223✔
53
                    return () => {
10,997✔
54
                        return this.resolve();
10,997✔
55
                    };
56
                }
57
                if (propName === 'tableProvider') {
43,226✔
58
                    return this.tableProvider;
44✔
59
                }
60
                if (propName === 'isEqual') {
43,182✔
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) => {
65✔
64
                        if (!targetType) {
65!
NEW
65
                            return false;
×
66
                        }
67
                        const resolvedType = this.resolve();
65✔
68
                        let equal = false;
65✔
69
                        if (resolvedType && !isReferenceType(resolvedType)) {
65✔
70
                            equal = resolvedType.isEqual(targetType, data);
6✔
71
                        } else if (isReferenceType(targetType)) {
59✔
72
                            equal = this.fullName.toLowerCase() === targetType.fullName.toLowerCase() &&
57!
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;
65✔
79
                    };
80
                }
81
                if (propName === 'isTypeCompatible') {
43,117✔
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!
NEW
86
                            return false;
×
87
                        }
88
                        if (isDynamicType(targetType)) {
2,579✔
89
                            return true;
3✔
90
                        }
91
                        const resolvedType = this.resolve();
2,576✔
92
                        if (resolvedType && !isReferenceType(resolvedType)) {
2,576✔
93
                            return resolvedType.isTypeCompatible(targetType, data);
2,575✔
94
                        } else if (isReferenceType(targetType)) {
1!
NEW
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();
40,538✔
107

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

111
                    if (propName === 'getMemberType') {
27,992✔
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,038✔
115
                            const resolvedType = this.resolve();
1,038✔
116
                            if (resolvedType) {
1,038!
NEW
117
                                return resolvedType.getMemberType(memberName, options);
×
118
                            }
119
                            const refLookUp = `${memberName.toLowerCase()}-${options?.flags}`;
1,038!
120
                            let memberTypeReference = this.memberTypeReferences.get(refLookUp);
1,038✔
121
                            if (memberTypeReference) {
1,038✔
122
                                return memberTypeReference;
27✔
123

124
                            }
125
                            memberTypeReference = new ReferenceType(memberName, this.makeMemberFullName(memberName), options.flags, this.futureMemberTableProvider);
1,011✔
126
                            this.memberTypeReferences.set(refLookUp, memberTypeReference);
1,011✔
127
                            return memberTypeReference;
1,011✔
128
                        };
129
                    } else if (propName === 'getCallFuncType') {
26,954✔
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!
NEW
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!
NEW
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') {
26,946✔
148
                        // This type was never found
149
                        // For diagnostics, we should return the expected name of of the type
150
                        return () => this.fullName;
2,420✔
151
                    } else if (propName === 'toTypeString') {
24,526!
152
                        // For transpilation, we should 'dynamic'
NEW
153
                        return () => 'dynamic';
×
154
                    } else if (propName === 'returnType') {
24,526✔
155
                        let propRefType = this.propertyTypeReference.get(propName);
57✔
156
                        if (!propRefType) {
57✔
157
                            propRefType = new TypePropertyReferenceType(this, propName);
24✔
158
                            this.propertyTypeReference.set(propName, propRefType);
24✔
159
                        }
160
                        return propRefType;
57✔
161
                    } else if (propName === 'memberTable') {
24,469✔
162
                        return this.memberTable;
97✔
163
                    } else if (propName === 'getMemberTable') {
24,372✔
164
                        return () => {
27✔
165
                            return this.memberTable;
27✔
166
                        };
167
                    } else if (propName === 'callFuncTable') {
24,345!
NEW
168
                        return (this as any).callFuncMemberTable;
×
169
                    } else if (propName === 'getCallFuncTable') {
24,345!
NEW
170
                        return () => {
×
NEW
171
                            return (this as any).callFuncMemberTable;
×
172
                        };
173
                    } else if (propName === 'isTypeCompatible') {
24,345!
NEW
174
                        return (targetType: BscType) => {
×
NEW
175
                            return isDynamicType(targetType);
×
176
                        };
177
                    } else if (propName === 'isEqual') {
24,345!
NEW
178
                        return (targetType: BscType) => {
×
NEW
179
                            if (isReferenceType(targetType)) {
×
NEW
180
                                return this.fullName.toLowerCase() === targetType.toString().toLowerCase() &&
×
181
                                    this.tableProvider() === targetType.tableProvider();
182
                            }
NEW
183
                            return false;
×
184
                        };
185
                    } else if (propName === 'addBuiltInInterfaces') {
24,345✔
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') {
24,303!
190
                        // this is an unknown type. There is no use in adding built in interfaces
NEW
191
                        return true;
×
192
                    } else if (propName === 'isBuiltIn') {
24,303✔
193
                        return false;
23✔
194
                    }
195
                }
196

197
                if (!innerType) {
36,826✔
198
                    innerType = DynamicType.instance;
24,280✔
199
                }
200
                const result = Reflect.get(innerType, propName, innerType);
36,826✔
201
                return result;
36,826✔
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();
497✔
209

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

228
    public readonly kind = BscTypeKind.ReferenceType;
120,484✔
229

230
    getTarget() {
231
        return this.resolve();
161✔
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,066✔
239
        if (!symbolTable) {
81,066✔
240
            return;
12✔
241
        }
242
        // Look for circular references
243
        let resolvedType = symbolTable.getSymbolType(this.memberKey, { flags: this.flags, onlyCacheResolvedTypes: true });
81,054✔
244
        if (!resolvedType) {
81,054✔
245
            // could not find this member
246
            return;
45,728✔
247
        }
248
        if (isAnyReferenceType(resolvedType)) {
35,326✔
249
            // If this is a referenceType, keep digging down until we have a non reference Type.
250
            while (resolvedType && isAnyReferenceType(resolvedType)) {
1,963✔
251
                if (this.referenceChain.has(resolvedType)) {
1,963✔
252
                    // this is a circular reference
253
                    this.circRefCount++;
1,204✔
254
                }
255
                if (this.circRefCount > 1) {
1,963✔
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,145✔
259
                }
260
                this.referenceChain.add(resolvedType);
818✔
261
                resolvedType = (resolvedType as any)?.getTarget?.();
818!
262
            }
263
            this.tableProvider().setCachedType(this.memberKey, { type: resolvedType }, { flags: this.flags });
818✔
264
        }
265

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

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

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

282
    private referenceChain = new Set<BscType>();
120,484✔
283

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

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

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

313
    private futureCallFuncMemberTableProvider = () => {
120,484✔
314
        return {
342✔
315
            name: `FutureCallFuncMemberTableProvider: '${this.__identifier}'`,
316
            getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
317
                const resolvedType = this.resolve();
342✔
318
                if (isComponentType(resolvedType)) {
342✔
319
                    return resolvedType.getCallFuncType(innerName, innerOptions);
199✔
320
                }
321
            },
322
            setCachedType: (innerName: string, innerResolvedTypeCacheEntry: TypeChainEntry, options: GetSymbolTypeOptions) => {
NEW
323
                const resolvedType = this.resolve();
×
NEW
324
                if (isComponentType(resolvedType)) {
×
NEW
325
                    resolvedType.getCallFuncTable().setCachedType(innerName, innerResolvedTypeCacheEntry, options);
×
326
                }
327
            },
328
            addSibling: (symbolTable: SymbolTable) => {
NEW
329
                const resolvedType = this.resolve();
×
NEW
330
                if (isComponentType(resolvedType)) {
×
NEW
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) {
90✔
351
        super(propertyName);
90✔
352
        // eslint-disable-next-line no-constructor-return
353
        return new Proxy(this, {
90✔
354
            get: (target, propName, receiver) => {
355

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

361
                if (propName === 'outerType') {
1,101!
NEW
362
                    return outerType;
×
363
                }
364

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

371
                if (isAnyReferenceType(this.outerType) && !this.outerType.isResolvable()) {
980✔
372
                    if (propName === 'getMemberType') {
190✔
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 {
47✔
379
                                    name: `TypePropertyReferenceType : '${fullMemberName}'`,
380
                                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
381
                                        return this.outerType?.[this.propertyName]?.getMemberType(innerName, innerOptions);
47!
382
                                    },
383
                                    setCachedType: (innerName: string, innerTypeCacheEntry: TypeChainEntry, innerOptions: GetTypeOptions) => {
NEW
384
                                        return this.outerType?.[this.propertyName]?.memberTable.setCachedType(innerName, innerTypeCacheEntry, innerOptions);
×
385
                                    },
386
                                    addSibling: (symbolTable: SymbolTable) => {
NEW
387
                                        return this.outerType?.[this.propertyName]?.memberTable?.addSibling?.(symbolTable);
×
388
                                    }
389
                                };
390
                            });
391
                        };
392
                    }
393
                    if (propName === 'isResolvable') {
174!
NEW
394
                        return () => false;
×
395
                    }
396
                }
397
                let inner = (isAnyReferenceType(this.outerType) ? (this.outerType as ReferenceType).getTarget() : this.outerType)?.[this.propertyName];
964✔
398

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

403
                if (inner) {
964!
404
                    const result = Reflect.get(inner, propName, inner);
964✔
405
                    return result;
964✔
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];
12✔
414

415
                if (inner) {
12!
416
                    const result = Reflect.set(inner, name, value, inner);
12✔
417
                    return result;
12✔
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
    cachedType: BscType;
491

492
    constructor(public objType: BscType) {
2✔
493
        super('ArrayDefaultType');
2✔
494
        // eslint-disable-next-line no-constructor-return
495
        return new Proxy(this, {
2✔
496
            get: (target, propName, receiver) => {
497

498
                if (propName === '__reflection') {
30✔
499
                    // Cheeky way to get `ArrayDefaultTypeReferenceType` reflection to work
500
                    return { name: 'ArrayDefaultTypeReferenceType' };
19✔
501
                }
502

503
                if (propName === 'objType') {
11!
NEW
504
                    return objType;
×
505
                }
506

507
                if (propName === 'getTarget') {
11!
NEW
508
                    return () => {
×
NEW
509
                        if (this.cachedType) {
×
NEW
510
                            return this.cachedType;
×
511
                        }
NEW
512
                        if (isReferenceType(this.objType)) {
×
NEW
513
                            (this.objType as any).getTarget();
×
514
                        }
NEW
515
                        return this.objType;
×
516
                    };
517
                }
518

519
                let resultType: BscType = this.cachedType ?? DynamicType.instance;
11✔
520
                if (!this.cachedType) {
11✔
521
                    if ((isAnyReferenceType(this.objType) && !this.objType.isResolvable())
4✔
522
                    ) {
523
                        if (propName === 'isResolvable') {
2✔
524
                            return () => false;
1✔
525
                        }
526
                        if (propName === 'getTarget') {
1!
NEW
527
                            return () => undefined;
×
528
                        }
529
                    } else {
530
                        if (isArrayType(this.objType)) {
2!
531
                            resultType = this.objType.defaultType;
2✔
532
                        } else {
NEW
533
                            resultType = DynamicType.instance;
×
534
                        }
535
                        this.cachedType = resultType;
2✔
536
                    }
537

538
                }
539
                if (resultType) {
10!
540
                    const result = Reflect.get(resultType, propName, resultType);
10✔
541
                    return result;
10✔
542
                }
543
            }
544
        });
545
    }
546

547
    getTarget: () => BscType;
548

549
    tableProvider: SymbolTableProvider;
550
}
551

552
/**
553
 * Used for when a Param's initial value is unresolved
554
 * Generally, this will be resolved later *except* for Enum
555
 * Enum Types will have an initial value of an EnumMemberType, but the param
556
 * should be an EnumType
557
 */
558
export class ParamTypeFromValueReferenceType extends BscType {
1✔
559
    cachedType: BscType;
560

561
    constructor(public objType: BscType) {
443✔
562
        super('ParamInitialValueType');
443✔
563
        // eslint-disable-next-line no-constructor-return
564
        return new Proxy(this, {
443✔
565
            get: (target, propName, receiver) => {
566
                if (propName === '__reflection') {
3,329✔
567
                    // Cheeky way to get reflection to work
568
                    return { name: 'ParamTypeFromValueReferenceType' };
941✔
569
                }
570

571
                if (propName === 'objType') {
2,388!
NEW
572
                    return objType;
×
573
                }
574

575
                if (propName === 'getTarget') {
2,388✔
576
                    return () => {
3✔
577
                        if (this.cachedType) {
3!
578
                            return this.cachedType;
3✔
579
                        }
NEW
580
                        if (isReferenceType(this.objType)) {
×
NEW
581
                            (this.objType as any).getTarget();
×
582
                        }
NEW
583
                        return this.objType;
×
584
                    };
585
                }
586

587
                let resultType: BscType = this.cachedType ?? DynamicType.instance;
2,385✔
588
                if (!this.cachedType) {
2,385✔
589
                    if ((isAnyReferenceType(this.objType) && !this.objType.isResolvable())
987✔
590
                    ) {
591
                        if (propName === 'isResolvable') {
866✔
592
                            return () => false;
4✔
593
                        }
594
                        if (propName === 'getTarget') {
862!
NEW
595
                            return () => undefined;
×
596
                        }
597
                    } else {
598
                        resultType = util.getDefaultTypeFromValueType(this.objType);
121✔
599
                        this.cachedType = resultType;
121✔
600
                    }
601

602
                }
603
                if (resultType) {
2,381!
604
                    const result = Reflect.get(resultType, propName, resultType);
2,381✔
605
                    return result;
2,381✔
606
                }
607
            }
608
        });
609
    }
610
}
611

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

630
    }
631
    if (isArrayDefaultTypeReferenceType(refType)) {
6!
NEW
632
        const objType = refType.objType;
×
NEW
633
        if (isAnyReferenceType(objType)) {
×
NEW
634
            return getAllRequiredSymbolNames(objType);
×
635
        } else {
NEW
636
            return [];
×
637
        }
638
    }
639
    if (isBinaryOperatorReferenceType(refType)) {
6!
640
        const left = refType.leftType;
6✔
641
        const right = refType.rightType;
6✔
642
        const result = [];
6✔
643
        if (isAnyReferenceType(left)) {
6✔
644
            result.push(...getAllRequiredSymbolNames(left, namespaceLower));
4✔
645
        }
646
        if (isAnyReferenceType(right)) {
6!
647
            result.push(...getAllRequiredSymbolNames(right, namespaceLower));
6✔
648

649
        }
650
        return result;
6✔
651
    }
NEW
652
    if (isParamTypeFromValueReferenceType(refType)) {
×
NEW
653
        const objType = refType.objType;
×
NEW
654
        if (isAnyReferenceType(objType)) {
×
NEW
655
            return getAllRequiredSymbolNames(objType);
×
656
        } else {
NEW
657
            return [];
×
658
        }
659
    }
NEW
660
    return [];
×
661
}
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