Avoid getting undefined callSignatures/constructSignatures in getPropertyOfType

e350c357 (#40228) introduced a subtle bug: it switched the flags to an
alias, dropping `SymbolFlags.Property` --- and that makes
`symbolIsValue()` get to the `resolveAlias(symbol)` call, which leads to
`getPropertyOfType()` with`resolved.callSignatures`+`constructSignatures`
being `undefined`.  So initialize them in `setStructuredTypeMembers`
before calling `getNamedMembers()`.

Fixes #42350
This commit is contained in:
Eli Barzilay 2021-02-11 15:22:06 -05:00
parent a3ead92046
commit c7bac6f2e6
9 changed files with 108 additions and 7 deletions

View file

@ -3846,13 +3846,16 @@ namespace ts {
}
function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): ResolvedType {
(<ResolvedType>type).members = members;
(<ResolvedType>type).properties = members === emptySymbols ? emptyArray : getNamedMembers(members);
(<ResolvedType>type).callSignatures = callSignatures;
(<ResolvedType>type).constructSignatures = constructSignatures;
(<ResolvedType>type).stringIndexInfo = stringIndexInfo;
(<ResolvedType>type).numberIndexInfo = numberIndexInfo;
return <ResolvedType>type;
const resolved = <ResolvedType>type;
resolved.members = members;
resolved.properties = emptyArray;
resolved.callSignatures = callSignatures;
resolved.constructSignatures = constructSignatures;
resolved.stringIndexInfo = stringIndexInfo;
resolved.numberIndexInfo = numberIndexInfo;
// This can loop back to getPropertyOfType() which would crash if `callSignatures` & `constructSignatures` are not initialized.
if (members !== emptySymbols) resolved.properties = getNamedMembers(members);
return resolved;
}
function createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): ResolvedType {

View file

@ -0,0 +1,9 @@
tests/cases/conformance/salsa/x.js(1,9): error TS2339: Property 'fn1' does not exist on type 'typeof import("tests/cases/conformance/salsa/x")'.
==== tests/cases/conformance/salsa/x.js (1 errors) ====
exports.fn1();
~~~
!!! error TS2339: Property 'fn1' does not exist on type 'typeof import("tests/cases/conformance/salsa/x")'.
exports.fn2 = Math.min;

View file

@ -0,0 +1,12 @@
=== tests/cases/conformance/salsa/x.js ===
exports.fn1();
>exports : Symbol("tests/cases/conformance/salsa/x", Decl(x.js, 0, 0))
exports.fn2 = Math.min;
>exports.fn2 : Symbol(fn2, Decl(x.js, 0, 14))
>exports : Symbol(fn2, Decl(x.js, 0, 14))
>fn2 : Symbol(fn2, Decl(x.js, 0, 14))
>Math.min : Symbol(fn2, Decl(lib.es5.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>min : Symbol(fn2, Decl(lib.es5.d.ts, --, --))

View file

@ -0,0 +1,16 @@
=== tests/cases/conformance/salsa/x.js ===
exports.fn1();
>exports.fn1() : any
>exports.fn1 : any
>exports : typeof import("tests/cases/conformance/salsa/x")
>fn1 : any
exports.fn2 = Math.min;
>exports.fn2 = Math.min : (...values: number[]) => number
>exports.fn2 : (...values: number[]) => number
>exports : typeof import("tests/cases/conformance/salsa/x")
>fn2 : (...values: number[]) => number
>Math.min : (...values: number[]) => number
>Math : Math
>min : (...values: number[]) => number

View file

@ -0,0 +1,10 @@
tests/cases/conformance/salsa/x.js(2,9): error TS2339: Property 'fn1' does not exist on type 'typeof import("tests/cases/conformance/salsa/x")'.
==== tests/cases/conformance/salsa/x.js (1 errors) ====
const Foo = { min: 3 };
exports.fn1();
~~~
!!! error TS2339: Property 'fn1' does not exist on type 'typeof import("tests/cases/conformance/salsa/x")'.
exports.fn2 = Foo.min;

View file

@ -0,0 +1,16 @@
=== tests/cases/conformance/salsa/x.js ===
const Foo = { min: 3 };
>Foo : Symbol(Foo, Decl(x.js, 0, 5))
>min : Symbol(min, Decl(x.js, 0, 13))
exports.fn1();
>exports : Symbol("tests/cases/conformance/salsa/x", Decl(x.js, 0, 0))
exports.fn2 = Foo.min;
>exports.fn2 : Symbol(fn2, Decl(x.js, 1, 14))
>exports : Symbol(fn2, Decl(x.js, 1, 14))
>fn2 : Symbol(fn2, Decl(x.js, 1, 14))
>Foo.min : Symbol(fn2, Decl(x.js, 0, 13))
>Foo : Symbol(Foo, Decl(x.js, 0, 5))
>min : Symbol(fn2, Decl(x.js, 0, 13))

View file

@ -0,0 +1,22 @@
=== tests/cases/conformance/salsa/x.js ===
const Foo = { min: 3 };
>Foo : { min: number; }
>{ min: 3 } : { min: number; }
>min : number
>3 : 3
exports.fn1();
>exports.fn1() : any
>exports.fn1 : any
>exports : typeof import("tests/cases/conformance/salsa/x")
>fn1 : any
exports.fn2 = Foo.min;
>exports.fn2 = Foo.min : number
>exports.fn2 : number
>exports : typeof import("tests/cases/conformance/salsa/x")
>fn2 : number
>Foo.min : number
>Foo : { min: number; }
>min : number

View file

@ -0,0 +1,6 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @filename: x.js
exports.fn1();
exports.fn2 = Math.min;

View file

@ -0,0 +1,7 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @filename: x.js
const Foo = { min: 3 };
exports.fn1();
exports.fn2 = Foo.min;