From 0fe88c9cfa5de6b913ae5448c990b9d8332d63a0 Mon Sep 17 00:00:00 2001 From: Eli Barzilay Date: Thu, 25 Feb 2021 00:52:33 +0000 Subject: [PATCH] Cherry-pick PR #42766 into release-4.2 Component commits: ed2681639c 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 --- src/compiler/checker.ts | 17 ++++++++------ .../moduleExportsAliasLoop1.errors.txt | 9 ++++++++ .../reference/moduleExportsAliasLoop1.symbols | 12 ++++++++++ .../reference/moduleExportsAliasLoop1.types | 16 ++++++++++++++ .../moduleExportsAliasLoop2.errors.txt | 10 +++++++++ .../reference/moduleExportsAliasLoop2.symbols | 16 ++++++++++++++ .../reference/moduleExportsAliasLoop2.types | 22 +++++++++++++++++++ .../salsa/moduleExportsAliasLoop1.ts | 6 +++++ .../salsa/moduleExportsAliasLoop2.ts | 7 ++++++ 9 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/moduleExportsAliasLoop1.errors.txt create mode 100644 tests/baselines/reference/moduleExportsAliasLoop1.symbols create mode 100644 tests/baselines/reference/moduleExportsAliasLoop1.types create mode 100644 tests/baselines/reference/moduleExportsAliasLoop2.errors.txt create mode 100644 tests/baselines/reference/moduleExportsAliasLoop2.symbols create mode 100644 tests/baselines/reference/moduleExportsAliasLoop2.types create mode 100644 tests/cases/conformance/salsa/moduleExportsAliasLoop1.ts create mode 100644 tests/cases/conformance/salsa/moduleExportsAliasLoop2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d3274fc1c881e..aaaefc6f316ce 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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 { - (type).members = members; - (type).properties = members === emptySymbols ? emptyArray : getNamedMembers(members); - (type).callSignatures = callSignatures; - (type).constructSignatures = constructSignatures; - (type).stringIndexInfo = stringIndexInfo; - (type).numberIndexInfo = numberIndexInfo; - return type; + const resolved = 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 { diff --git a/tests/baselines/reference/moduleExportsAliasLoop1.errors.txt b/tests/baselines/reference/moduleExportsAliasLoop1.errors.txt new file mode 100644 index 0000000000000..7975da40a1e02 --- /dev/null +++ b/tests/baselines/reference/moduleExportsAliasLoop1.errors.txt @@ -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; + \ No newline at end of file diff --git a/tests/baselines/reference/moduleExportsAliasLoop1.symbols b/tests/baselines/reference/moduleExportsAliasLoop1.symbols new file mode 100644 index 0000000000000..7668de62d30dd --- /dev/null +++ b/tests/baselines/reference/moduleExportsAliasLoop1.symbols @@ -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, --, --)) + diff --git a/tests/baselines/reference/moduleExportsAliasLoop1.types b/tests/baselines/reference/moduleExportsAliasLoop1.types new file mode 100644 index 0000000000000..126a0d7de4943 --- /dev/null +++ b/tests/baselines/reference/moduleExportsAliasLoop1.types @@ -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 + diff --git a/tests/baselines/reference/moduleExportsAliasLoop2.errors.txt b/tests/baselines/reference/moduleExportsAliasLoop2.errors.txt new file mode 100644 index 0000000000000..ae57d97560be4 --- /dev/null +++ b/tests/baselines/reference/moduleExportsAliasLoop2.errors.txt @@ -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; + \ No newline at end of file diff --git a/tests/baselines/reference/moduleExportsAliasLoop2.symbols b/tests/baselines/reference/moduleExportsAliasLoop2.symbols new file mode 100644 index 0000000000000..e19f3f24a5f31 --- /dev/null +++ b/tests/baselines/reference/moduleExportsAliasLoop2.symbols @@ -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)) + diff --git a/tests/baselines/reference/moduleExportsAliasLoop2.types b/tests/baselines/reference/moduleExportsAliasLoop2.types new file mode 100644 index 0000000000000..458fc64e8a59b --- /dev/null +++ b/tests/baselines/reference/moduleExportsAliasLoop2.types @@ -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 + diff --git a/tests/cases/conformance/salsa/moduleExportsAliasLoop1.ts b/tests/cases/conformance/salsa/moduleExportsAliasLoop1.ts new file mode 100644 index 0000000000000..7a4dd7015a4cc --- /dev/null +++ b/tests/cases/conformance/salsa/moduleExportsAliasLoop1.ts @@ -0,0 +1,6 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @filename: x.js +exports.fn1(); +exports.fn2 = Math.min; diff --git a/tests/cases/conformance/salsa/moduleExportsAliasLoop2.ts b/tests/cases/conformance/salsa/moduleExportsAliasLoop2.ts new file mode 100644 index 0000000000000..233266bccce80 --- /dev/null +++ b/tests/cases/conformance/salsa/moduleExportsAliasLoop2.ts @@ -0,0 +1,7 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @filename: x.js +const Foo = { min: 3 }; +exports.fn1(); +exports.fn2 = Foo.min;