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

rokucommunity / brighterscript / #13615

14 Jan 2025 06:19PM UTC coverage: 86.812%. Remained the same
#13615

push

web-flow
Merge 05a55830c into 7fb92fff2

12436 of 15140 branches covered (82.14%)

Branch coverage included in aggregate %.

409 of 435 new or added lines in 36 files covered. (94.02%)

264 existing lines in 24 files now uncovered.

13334 of 14545 relevant lines covered (91.67%)

34016.38 hits per line

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

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

32
                if (propName === '__reflection') {
522,667✔
33
                    // Cheeky way to get `isReferenceType` reflection to work
34
                    return this.__reflection;
462,870✔
35
                }
36
                if (propName === '__identifier') {
59,797✔
37
                    // Cheeky way to get `isReferenceType` reflection to work
38
                    return this.__identifier;
13✔
39
                }
40
                if (propName === 'fullName') {
59,784✔
41
                    return this.fullName;
783✔
42
                }
43
                if (propName === 'isResolvable') {
59,001✔
44
                    return () => {
8,963✔
45
                        let resultSoFar = this.resolve();
8,963✔
46
                        while (resultSoFar && isReferenceType(resultSoFar)) {
8,963✔
47
                            resultSoFar = (resultSoFar as any).getTarget?.();
×
48
                        }
49
                        return !!resultSoFar;
8,963✔
50
                    };
51
                }
52
                if (propName === 'getTarget') {
50,038✔
53
                    return () => {
9,627✔
54
                        return this.resolve();
9,627✔
55
                    };
56
                }
57
                if (propName === 'tableProvider') {
40,411✔
58
                    return this.tableProvider;
22✔
59
                }
60
                if (propName === 'isEqual') {
40,389✔
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) => {
38✔
64
                        if (!targetType) {
38!
65
                            return false;
×
66
                        }
67
                        const resolvedType = this.resolve();
38✔
68
                        let equal = false;
38✔
69
                        if (resolvedType && !isReferenceType(resolvedType)) {
38✔
70
                            equal = resolvedType.isEqual(targetType, data);
6✔
71
                        } else if (isReferenceType(targetType)) {
32✔
72
                            equal = this.fullName.toLowerCase() === targetType.fullName.toLowerCase() &&
28!
73
                                (this.tableProvider === targetType.tableProvider ||
74
                                    this.tableProvider().name === targetType.tableProvider().name);
75
                        } else {
76
                            equal = targetType.isEqual(this, data);
4✔
77
                        }
78
                        return equal;
38✔
79
                    };
80
                }
81
                if (propName === 'isTypeCompatible') {
40,351✔
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,467✔
85
                        if (!targetType) {
2,467!
86
                            return false;
×
87
                        }
88
                        if (isDynamicType(targetType)) {
2,467!
89
                            return true;
×
90
                        }
91
                        const resolvedType = this.resolve();
2,467✔
92
                        if (resolvedType && !isReferenceType(resolvedType)) {
2,467✔
93
                            return resolvedType.isTypeCompatible(targetType, data);
2,466✔
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();
37,884✔
107

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

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

124
                            }
125
                            memberTypeReference = new ReferenceType(memberName, this.makeMemberFullName(memberName), options.flags, this.futureMemberTableProvider);
970✔
126
                            this.memberTypeReferences.set(refLookUp, memberTypeReference);
970✔
127
                            return memberTypeReference;
970✔
128
                        };
129
                    } else if (propName === 'getCallFuncType') {
25,502✔
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') {
25,494✔
148
                        // This type was never found
149
                        // For diagnostics, we should return the expected name of of the type
150
                        return () => this.fullName;
5,896✔
151
                    } else if (propName === 'toTypeString') {
19,598!
152
                        // For transpilation, we should 'dynamic'
153
                        return () => 'dynamic';
×
154
                    } else if (propName === 'returnType') {
19,598✔
155
                        let propRefType = this.propertyTypeReference.get(propName);
183✔
156
                        if (!propRefType) {
183✔
157
                            propRefType = new TypePropertyReferenceType(this, propName);
51✔
158
                            this.propertyTypeReference.set(propName, propRefType);
51✔
159
                        }
160
                        return propRefType;
183✔
161
                    } else if (propName === 'memberTable') {
19,415✔
162
                        return this.memberTable;
97✔
163
                    } else if (propName === 'getMemberTable') {
19,318✔
164
                        return () => {
27✔
165
                            return this.memberTable;
27✔
166
                        };
167
                    } else if (propName === 'callFuncTable') {
19,291!
168
                        return (this as any).callFuncMemberTable;
×
169
                    } else if (propName === 'getCallFuncTable') {
19,291!
170
                        return () => {
×
171
                            return (this as any).callFuncMemberTable;
×
172
                        };
173
                    } else if (propName === 'isTypeCompatible') {
19,291!
174
                        return (targetType: BscType) => {
×
175
                            return isDynamicType(targetType);
×
176
                        };
177
                    } else if (propName === 'isEqual') {
19,291!
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') {
19,291✔
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') {
19,249!
190
                        // this is an unknown type. There is no use in adding built in interfaces
191
                        return true;
×
192
                    } else if (propName === 'isBuiltIn') {
19,249✔
193
                        return false;
23✔
194
                    }
195
                }
196

197
                if (!innerType) {
30,612✔
198
                    innerType = DynamicType.instance;
19,226✔
199
                }
200
                const result = Reflect.get(innerType, propName, innerType);
30,612✔
201
                return result;
30,612✔
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();
496✔
209

210
                // Look for circular references
211
                if (!innerType || this.referenceChain.has(innerType)) {
496!
NEW
212
                    console.log(`Proxy set error`, name, value, innerType);
×
NEW
213
                    const error = new Error();
×
NEW
214
                    console.log(error.stack);
×
UNCOV
215
                    return false;
×
216
                }
217
                const result = Reflect.set(innerType, name, value, innerType);
496✔
218
                this.referenceChain.clear();
496✔
219
                return result;
496✔
220
            }
221
        });
222
    }
223

224
    public readonly kind = BscTypeKind.ReferenceType;
220,749✔
225

226
    getTarget: () => BscType;
227

228
    /**
229
     * Resolves the type based on the original name and the table provider
230
     */
231
    private resolve(): BscType {
232
        const symbolTable = this.tableProvider();
74,252✔
233
        if (!symbolTable) {
74,252✔
234
            return;
10✔
235
        }
236
        // Look for circular references
237
        let resolvedType = symbolTable.getSymbolType(this.memberKey, { flags: this.flags, onlyCacheResolvedTypes: true });
74,242✔
238
        if (!resolvedType) {
74,242✔
239
            // could not find this member
240
            return;
42,540✔
241
        }
242
        if (isAnyReferenceType(resolvedType)) {
31,702✔
243
            // If this is a referenceType, keep digging down until we have a non reference Type.
244
            while (resolvedType && isAnyReferenceType(resolvedType)) {
1,676✔
245
                if (this.referenceChain.has(resolvedType)) {
1,676✔
246
                    // this is a circular reference
247
                    this.circRefCount++;
944✔
248
                }
249
                if (this.circRefCount > 1) {
1,676✔
250
                    //It is possible that we could properly resolve the case that one reference points to itself
251
                    //see test: '[Scope][symbolTable lookups with enhanced typing][finds correct class field type with default value enums are used]
252
                    return;
897✔
253
                }
254
                this.referenceChain.add(resolvedType);
779✔
255
                resolvedType = (resolvedType as any)?.getTarget?.();
779!
256
            }
257
            this.tableProvider().setCachedType(this.memberKey, { type: resolvedType }, { flags: this.flags });
779✔
258
        }
259

260
        if (resolvedType && !isAnyReferenceType(resolvedType)) {
30,805✔
261
            this.circRefCount = 0;
30,030✔
262
            this.referenceChain.clear();
30,030✔
263
        }
264
        return resolvedType;
30,805✔
265
    }
266

267
    get __reflection() {
268
        return { name: 'ReferenceType' };
463,077✔
269
    }
270

271
    makeMemberFullName(memberName: string) {
272
        return this.fullName + '.' + memberName;
978✔
273
    }
274
    private circRefCount = 0;
220,749✔
275

276
    private referenceChain = new Set<BscType>();
220,749✔
277

278
    private propertyTypeReference = new Map<string, TypePropertyReferenceType>();
220,749✔
279

280
    private memberTypeReferences = new Map<string, ReferenceType>();
220,749✔
281
    private callFuncMemberTypeReferences = new Map<string, ReferenceType>();
220,749✔
282

283
    private futureMemberTableProvider = () => {
220,749✔
284
        return {
13,465✔
285
            name: `FutureMemberTableProvider: '${this.__identifier}'`,
286
            getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
287
                const resolvedType = this.resolve();
12,780✔
288
                if (resolvedType) {
12,780✔
289
                    return resolvedType.getMemberType(innerName, innerOptions);
7,432✔
290
                }
291
            },
292
            setCachedType: (innerName: string, innerResolvedTypeCacheEntry: TypeChainEntry, options: GetSymbolTypeOptions) => {
293
                const resolvedType = this.resolve();
685✔
294
                if (resolvedType) {
685!
295
                    resolvedType.memberTable.setCachedType(innerName, innerResolvedTypeCacheEntry, options);
685✔
296
                }
297
            },
298
            addSibling: (symbolTable: SymbolTable) => {
NEW
299
                const resolvedType = this.resolve();
×
NEW
300
                if (resolvedType) {
×
NEW
301
                    resolvedType.memberTable?.addSibling?.(symbolTable);
×
302
                }
303
            }
304
        };
305
    };
306

307
    private futureCallFuncMemberTableProvider = () => {
220,749✔
308
        return {
308✔
309
            name: `FutureCallFuncMemberTableProvider: '${this.__identifier}'`,
310
            getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
311
                const resolvedType = this.resolve();
308✔
312
                if (isComponentType(resolvedType)) {
308✔
313
                    return resolvedType.getCallFuncType(innerName, innerOptions);
204✔
314
                }
315
            },
316
            setCachedType: (innerName: string, innerResolvedTypeCacheEntry: TypeChainEntry, options: GetSymbolTypeOptions) => {
UNCOV
317
                const resolvedType = this.resolve();
×
UNCOV
318
                if (isComponentType(resolvedType)) {
×
UNCOV
319
                    resolvedType.getCallFuncTable().setCachedType(innerName, innerResolvedTypeCacheEntry, options);
×
320
                }
321
            },
322
            addSibling: (symbolTable: SymbolTable) => {
NEW
323
                const resolvedType = this.resolve();
×
NEW
324
                if (isComponentType(resolvedType)) {
×
NEW
325
                    resolvedType.getCallFuncTable()?.addSibling?.(symbolTable);
×
326
                }
327
            }
328
        };
329
    };
330
}
331

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

350
                if (propName === '__reflection') {
1,022✔
351
                    // Cheeky way to get `isTypePropertyReferenceType` reflection to work
352
                    return { name: 'TypePropertyReferenceType' };
173✔
353
                }
354

355
                if (propName === 'outerType') {
849!
UNCOV
356
                    return outerType;
×
357
                }
358

359
                if (isAnyReferenceType(this.outerType) && !this.outerType.isResolvable()) {
849✔
360
                    if (propName === 'getMemberType') {
170✔
361
                        //If we're calling `getMemberType()`, we need it to proxy to using the actual symbol table
362
                        //So if that symbol is ever populated, the correct type is passed through
363
                        return (memberName: string, options: GetSymbolTypeOptions) => {
16✔
364
                            const fullMemberName = this.outerType.toString() + '.' + memberName;
16✔
365
                            return new ReferenceType(memberName, fullMemberName, options.flags, () => {
16✔
366
                                return {
44✔
367
                                    name: `TypePropertyReferenceType : '${fullMemberName}'`,
368
                                    getSymbolType: (innerName: string, innerOptions: GetTypeOptions) => {
369
                                        return this.outerType?.[this.propertyName]?.getMemberType(innerName, innerOptions);
44!
370
                                    },
371
                                    setCachedType: (innerName: string, innerTypeCacheEntry: TypeChainEntry, innerOptions: GetTypeOptions) => {
UNCOV
372
                                        return this.outerType?.[this.propertyName]?.memberTable.setCachedType(innerName, innerTypeCacheEntry, innerOptions);
×
373
                                    },
374
                                    addSibling: (symbolTable: SymbolTable) => {
NEW
375
                                        return this.outerType?.[this.propertyName]?.memberTable?.addSibling?.(symbolTable);
×
376
                                    }
377
                                };
378
                            });
379
                        };
380
                    }
381
                    if (propName === 'isResolvable') {
154✔
382
                        return () => false;
21✔
383
                    }
384
                }
385
                let inner = this.outerType?.[this.propertyName];
812✔
386

387
                if (!inner) {
812✔
388
                    inner = DynamicType.instance;
208✔
389
                }
390

391
                if (inner) {
812!
392
                    const result = Reflect.get(inner, propName, inner);
812✔
393
                    return result;
812✔
394
                }
395
            },
396
            set: (target, name, value, receiver) => {
397
                //There may be some need to specifically set members on ReferenceType in the future
398
                // eg: if (Reflect.has(target, name)) {
399
                //   return Reflect.set(target, name, value, receiver);
400

401
                let inner = this.outerType[this.propertyName];
12✔
402

403
                if (inner) {
12!
404
                    const result = Reflect.set(inner, name, value, inner);
12✔
405
                    return result;
12✔
406
                }
407
            }
408
        });
409
    }
410

411
    getTarget: () => BscType;
412

413
    tableProvider: SymbolTableProvider;
414
}
415

416

417
/**
418
 * Use this class for when there is a binary operator and either the left hand side and/or the right hand side
419
 * are ReferenceTypes
420
 */
421
export class BinaryOperatorReferenceType extends BscType {
1✔
422
    cachedType: BscType;
423

424
    constructor(public leftType: BscType, public operator: Token, public rightType: BscType, binaryOpResolver: (lType: BscType, operator: Token, rType: BscType) => BscType) {
34✔
425
        super(operator.text);
34✔
426
        // eslint-disable-next-line no-constructor-return
427
        return new Proxy(this, {
34✔
428
            get: (target, propName, receiver) => {
429

430
                if (propName === '__reflection') {
576✔
431
                    // Cheeky way to get `BinaryOperatorReferenceType` reflection to work
432
                    return { name: 'BinaryOperatorReferenceType' };
200✔
433
                }
434

435
                if (propName === 'leftType') {
376✔
436
                    return leftType;
6✔
437
                }
438

439
                if (propName === 'rightType') {
370✔
440
                    return rightType;
6✔
441
                }
442

443
                let resultType: BscType = this.cachedType ?? DynamicType.instance;
364✔
444
                if (!this.cachedType) {
364✔
445
                    if ((isAnyReferenceType(this.leftType) && !this.leftType.isResolvable()) ||
102✔
446
                        (isAnyReferenceType(this.rightType) && !this.rightType.isResolvable())
447
                    ) {
448
                        if (propName === 'isResolvable') {
97✔
449
                            return () => false;
68✔
450
                        }
451
                        if (propName === 'getTarget') {
29✔
452
                            return () => undefined;
2✔
453
                        }
454
                    } else {
455
                        resultType = binaryOpResolver(this.leftType, this.operator, this.rightType) ?? DynamicType.instance;
5!
456
                        this.cachedType = resultType;
5✔
457
                    }
458

459
                }
460
                if (resultType) {
294!
461
                    const result = Reflect.get(resultType, propName, resultType);
294✔
462
                    return result;
294✔
463
                }
464
            }
465
        });
466
    }
467

468
    getTarget: () => BscType;
469

470
    tableProvider: SymbolTableProvider;
471
}
472

473

474
/**
475
 * Use this class for when there is a presumable array type that is a referenceType
476
 */
477
export class ArrayDefaultTypeReferenceType extends BscType {
1✔
478
    cachedType: BscType;
479

480
    constructor(public objType: BscType) {
2✔
481
        super('ArrayDefaultType');
2✔
482
        // eslint-disable-next-line no-constructor-return
483
        return new Proxy(this, {
2✔
484
            get: (target, propName, receiver) => {
485

486
                if (propName === '__reflection') {
30✔
487
                    // Cheeky way to get `ArrayDefaultTypeReferenceType` reflection to work
488
                    return { name: 'ArrayDefaultTypeReferenceType' };
19✔
489
                }
490

491
                if (propName === 'objType') {
11!
UNCOV
492
                    return objType;
×
493
                }
494

495
                if (propName === 'getTarget') {
11!
UNCOV
496
                    return () => {
×
UNCOV
497
                        if (this.cachedType) {
×
UNCOV
498
                            return this.cachedType;
×
499
                        }
UNCOV
500
                        if (isReferenceType(this.objType)) {
×
UNCOV
501
                            (this.objType as any).getTarget();
×
502
                        }
UNCOV
503
                        return this.objType;
×
504
                    };
505
                }
506

507
                let resultType: BscType = this.cachedType ?? DynamicType.instance;
11✔
508
                if (!this.cachedType) {
11✔
509
                    if ((isAnyReferenceType(this.objType) && !this.objType.isResolvable())
4✔
510
                    ) {
511
                        if (propName === 'isResolvable') {
2✔
512
                            return () => false;
1✔
513
                        }
514
                        if (propName === 'getTarget') {
1!
UNCOV
515
                            return () => undefined;
×
516
                        }
517
                    } else {
518
                        if (isArrayType(this.objType)) {
2!
519
                            resultType = this.objType.defaultType;
2✔
520
                        } else {
UNCOV
521
                            resultType = DynamicType.instance;
×
522
                        }
523
                        this.cachedType = resultType;
2✔
524
                    }
525

526
                }
527
                if (resultType) {
10!
528
                    const result = Reflect.get(resultType, propName, resultType);
10✔
529
                    return result;
10✔
530
                }
531
            }
532
        });
533
    }
534

535
    getTarget: () => BscType;
536

537
    tableProvider: SymbolTableProvider;
538
}
539

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

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

559
                if (propName === 'objType') {
2,338!
UNCOV
560
                    return objType;
×
561
                }
562

563
                if (propName === 'getTarget') {
2,338✔
564
                    return () => {
3✔
565
                        if (this.cachedType) {
3!
566
                            return this.cachedType;
3✔
567
                        }
UNCOV
568
                        if (isReferenceType(this.objType)) {
×
UNCOV
569
                            (this.objType as any).getTarget();
×
570
                        }
UNCOV
571
                        return this.objType;
×
572
                    };
573
                }
574

575
                let resultType: BscType = this.cachedType ?? DynamicType.instance;
2,335✔
576
                if (!this.cachedType) {
2,335✔
577
                    if ((isAnyReferenceType(this.objType) && !this.objType.isResolvable())
987✔
578
                    ) {
579
                        if (propName === 'isResolvable') {
866✔
580
                            return () => false;
4✔
581
                        }
582
                        if (propName === 'getTarget') {
862!
UNCOV
583
                            return () => undefined;
×
584
                        }
585
                    } else {
586
                        resultType = util.getDefaultTypeFromValueType(this.objType);
121✔
587
                        this.cachedType = resultType;
121✔
588
                    }
589

590
                }
591
                if (resultType) {
2,331!
592
                    const result = Reflect.get(resultType, propName, resultType);
2,331✔
593
                    return result;
2,331✔
594
                }
595
            }
596
        });
597
    }
598
}
599

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

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

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