From 78fe4f4fc5ec1f9b5cfdae1b68b960ae0433682f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 26 Jun 2023 14:29:56 +0200 Subject: [PATCH 1/6] Prevent readonly unique symbols from widening --- src/compiler/checker.ts | 8 +- tests/baselines/reference/uniqueSymbols.types | 28 +- .../uniqueSymbolsDeclarations.errors.txt | 247 ++++++++++++++++++ .../reference/uniqueSymbolsDeclarations.js | 135 ---------- .../reference/uniqueSymbolsDeclarations.types | 28 +- 5 files changed, 281 insertions(+), 165 deletions(-) create mode 100644 tests/baselines/reference/uniqueSymbolsDeclarations.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ee86ae50306c7..b9c5b46c2c421 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11055,8 +11055,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reportErrorsFromWidening(declaration, type); } - // always widen a 'unique symbol' type if the type was created for a different declaration. - if (type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) && type.symbol !== getSymbolOfDeclaration(declaration)) { + // always widen a 'unique symbol' type if the type was created for a different declaration and if it's assigned to something mutable + if (type.flags & TypeFlags.UniqueESSymbol && + (isBindingElement(declaration) || !declaration.type) && + !isDeclarationReadonly(declaration) && !(isVariableDeclaration(declaration) && isVarConstLike(declaration)) && !isConstContext(declaration) && + type.symbol !== getSymbolOfDeclaration(declaration) + ) { type = esSymbolType; } diff --git a/tests/baselines/reference/uniqueSymbols.types b/tests/baselines/reference/uniqueSymbols.types index 37e1d29fcc38f..bbe57cba5483e 100644 --- a/tests/baselines/reference/uniqueSymbols.types +++ b/tests/baselines/reference/uniqueSymbols.types @@ -29,7 +29,7 @@ const constTypeAndCall: unique symbol = Symbol(); // declaration from initializer const constInitToConstCall = constCall; ->constInitToConstCall : symbol +>constInitToConstCall : unique symbol >constCall : unique symbol const constInitToLetCall = letCall; @@ -41,7 +41,7 @@ const constInitToVarCall = varCall; >varCall : symbol const constInitToConstDeclAmbient = constType; ->constInitToConstDeclAmbient : symbol +>constInitToConstDeclAmbient : unique symbol >constType : unique symbol let letInitToConstCall = constCall; @@ -201,19 +201,19 @@ declare const c: C; >c : C const constInitToCReadonlyStaticCall = C.readonlyStaticCall; ->constInitToCReadonlyStaticCall : symbol +>constInitToCReadonlyStaticCall : unique symbol >C.readonlyStaticCall : unique symbol >C : typeof C >readonlyStaticCall : unique symbol const constInitToCReadonlyStaticType = C.readonlyStaticType; ->constInitToCReadonlyStaticType : symbol +>constInitToCReadonlyStaticType : unique symbol >C.readonlyStaticType : unique symbol >C : typeof C >readonlyStaticType : unique symbol const constInitToCReadonlyStaticTypeAndCall = C.readonlyStaticTypeAndCall; ->constInitToCReadonlyStaticTypeAndCall : symbol +>constInitToCReadonlyStaticTypeAndCall : unique symbol >C.readonlyStaticTypeAndCall : unique symbol >C : typeof C >readonlyStaticTypeAndCall : unique symbol @@ -311,7 +311,7 @@ declare const i: I; >i : I const constInitToIReadonlyType = i.readonlyType; ->constInitToIReadonlyType : symbol +>constInitToIReadonlyType : unique symbol >i.readonlyType : unique symbol >i : I >readonlyType : unique symbol @@ -349,13 +349,13 @@ declare const l: L; >l : L const constInitToLReadonlyType = l.readonlyType; ->constInitToLReadonlyType : symbol +>constInitToLReadonlyType : unique symbol >l.readonlyType : unique symbol >l : L >readonlyType : unique symbol const constInitToLReadonlyNestedType = l.nested.readonlyNestedType; ->constInitToLReadonlyNestedType : symbol +>constInitToLReadonlyNestedType : unique symbol >l.nested.readonlyNestedType : unique symbol >l.nested : { readonly readonlyNestedType: unique symbol; } >l : L @@ -536,17 +536,17 @@ class C0 { >C0 : C0 static readonly a = s; ->a : symbol +>a : unique symbol >s : unique symbol static readonly b = N.s; ->b : symbol +>b : unique symbol >N.s : unique symbol >N : typeof N >s : unique symbol static readonly c = N["s"]; ->c : symbol +>c : unique symbol >N["s"] : unique symbol >N : typeof N >"s" : "s" @@ -568,17 +568,17 @@ class C0 { >"s" : "s" readonly a = s; ->a : symbol +>a : unique symbol >s : unique symbol readonly b = N.s; ->b : symbol +>b : unique symbol >N.s : unique symbol >N : typeof N >s : unique symbol readonly c = N["s"]; ->c : symbol +>c : unique symbol >N["s"] : unique symbol >N : typeof N >"s" : "s" diff --git a/tests/baselines/reference/uniqueSymbolsDeclarations.errors.txt b/tests/baselines/reference/uniqueSymbolsDeclarations.errors.txt new file mode 100644 index 0000000000000..90fae715c43f6 --- /dev/null +++ b/tests/baselines/reference/uniqueSymbolsDeclarations.errors.txt @@ -0,0 +1,247 @@ +uniqueSymbolsDeclarations.ts(104,7): error TS2527: The inferred type of 'constInitToLReadonlyType' references an inaccessible 'unique symbol' type. A type annotation is necessary. +uniqueSymbolsDeclarations.ts(105,7): error TS2527: The inferred type of 'constInitToLReadonlyNestedType' references an inaccessible 'unique symbol' type. A type annotation is necessary. + + +==== uniqueSymbolsDeclarations.ts (2 errors) ==== + // declarations with call initializer + const constCall = Symbol(); + let letCall = Symbol(); + var varCall = Symbol(); + + // ambient declaration with type + declare const constType: unique symbol; + + // declaration with type and call initializer + const constTypeAndCall: unique symbol = Symbol(); + + // declaration from initializer + const constInitToConstCall = constCall; + const constInitToLetCall = letCall; + const constInitToVarCall = varCall; + const constInitToConstDeclAmbient = constType; + let letInitToConstCall = constCall; + let letInitToLetCall = letCall; + let letInitToVarCall = varCall; + let letInitToConstDeclAmbient = constType; + var varInitToConstCall = constCall; + var varInitToLetCall = letCall; + var varInitToVarCall = varCall; + var varInitToConstDeclAmbient = constType; + + // declaration from initializer with type query + const constInitToConstCallWithTypeQuery: typeof constCall = constCall; + const constInitToConstDeclAmbientWithTypeQuery: typeof constType = constType; + + // function return inference + function funcReturnConstCall() { return constCall; } + function funcReturnLetCall() { return letCall; } + function funcReturnVarCall() { return varCall; } + + // function return value with type query + function funcReturnConstCallWithTypeQuery(): typeof constCall { return constCall; } + + // generator function yield inference + function* genFuncYieldConstCall() { yield constCall; } + function* genFuncYieldLetCall() { yield letCall; } + function* genFuncYieldVarCall() { yield varCall; } + + // generator function yield with return type query + function* genFuncYieldConstCallWithTypeQuery(): IterableIterator { yield constCall; } + + // async function return inference + async function asyncFuncReturnConstCall() { return constCall; } + async function asyncFuncReturnLetCall() { return letCall; } + async function asyncFuncReturnVarCall() { return varCall; } + + // async generator function yield inference + async function* asyncGenFuncYieldConstCall() { yield constCall; } + async function* asyncGenFuncYieldLetCall() { yield letCall; } + async function* asyncGenFuncYieldVarCall() { yield varCall; } + + // classes + class C { + static readonly readonlyStaticCall = Symbol(); + static readonly readonlyStaticType: unique symbol; + static readonly readonlyStaticTypeAndCall: unique symbol = Symbol(); + static readwriteStaticCall = Symbol(); + + readonly readonlyCall = Symbol(); + readwriteCall = Symbol(); + } + declare const c: C; + + const constInitToCReadonlyStaticCall = C.readonlyStaticCall; + const constInitToCReadonlyStaticType = C.readonlyStaticType; + const constInitToCReadonlyStaticTypeAndCall = C.readonlyStaticTypeAndCall; + const constInitToCReadwriteStaticCall = C.readwriteStaticCall; + + const constInitToCReadonlyStaticCallWithTypeQuery: typeof C.readonlyStaticCall = C.readonlyStaticCall; + const constInitToCReadonlyStaticTypeWithTypeQuery: typeof C.readonlyStaticType = C.readonlyStaticType; + const constInitToCReadonlyStaticTypeAndCallWithTypeQuery: typeof C.readonlyStaticTypeAndCall = C.readonlyStaticTypeAndCall; + const constInitToCReadwriteStaticCallWithTypeQuery: typeof C.readwriteStaticCall = C.readwriteStaticCall; + + const constInitToCReadonlyCall = c.readonlyCall; + const constInitToCReadwriteCall = c.readwriteCall; + const constInitToCReadonlyCallWithTypeQuery: typeof c.readonlyCall = c.readonlyCall; + const constInitToCReadwriteCallWithTypeQuery: typeof c.readwriteCall = c.readwriteCall; + const constInitToCReadonlyCallWithIndexedAccess: C["readonlyCall"] = c.readonlyCall; + const constInitToCReadwriteCallWithIndexedAccess: C["readwriteCall"] = c.readwriteCall; + + // interfaces + interface I { + readonly readonlyType: unique symbol; + } + declare const i: I; + + const constInitToIReadonlyType = i.readonlyType; + const constInitToIReadonlyTypeWithTypeQuery: typeof i.readonlyType = i.readonlyType; + const constInitToIReadonlyTypeWithIndexedAccess: I["readonlyType"] = i.readonlyType; + + // type literals + type L = { + readonly readonlyType: unique symbol; + nested: { + readonly readonlyNestedType: unique symbol; + } + }; + declare const l: L; + + const constInitToLReadonlyType = l.readonlyType; + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2527: The inferred type of 'constInitToLReadonlyType' references an inaccessible 'unique symbol' type. A type annotation is necessary. + const constInitToLReadonlyNestedType = l.nested.readonlyNestedType; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2527: The inferred type of 'constInitToLReadonlyNestedType' references an inaccessible 'unique symbol' type. A type annotation is necessary. + const constInitToLReadonlyTypeWithTypeQuery: typeof l.readonlyType = l.readonlyType; + const constInitToLReadonlyNestedTypeWithTypeQuery: typeof l.nested.readonlyNestedType = l.nested.readonlyNestedType; + const constInitToLReadonlyTypeWithIndexedAccess: L["readonlyType"] = l.readonlyType; + const constInitToLReadonlyNestedTypeWithIndexedAccess: L["nested"]["readonlyNestedType"] = l.nested.readonlyNestedType; + + // type argument inference + const promiseForConstCall = Promise.resolve(constCall); + const arrayOfConstCall = [constCall]; + + // unique symbol widening in expressions + declare const s: unique symbol; + declare namespace N { const s: unique symbol; } + declare const o: { [s]: "a", [N.s]: "b" }; + declare function f(x: T): T; + declare function g(x: typeof s): void; + declare function g(x: typeof N.s): void; + + // widening positions + + // argument inference + f(s); + f(N.s); + f(N["s"]); + + // array literal elements + [s]; + [N.s]; + [N["s"]]; + + // property assignments/methods + const o2 = { + a: s, + b: N.s, + c: N["s"], + + method1() { return s; }, + async method2() { return s; }, + async * method3() { yield s; }, + * method4() { yield s; }, + method5(p = s) { return p; } + }; + + // property initializers + class C0 { + static readonly a = s; + static readonly b = N.s; + static readonly c = N["s"]; + + static d = s; + static e = N.s; + static f = N["s"]; + + readonly a = s; + readonly b = N.s; + readonly c = N["s"]; + + d = s; + e = N.s; + f = N["s"]; + + method1() { return s; } + async method2() { return s; } + async * method3() { yield s; } + * method4() { yield s; } + method5(p = s) { return p; } + } + + // non-widening positions + + // element access + o[s]; + o[N.s]; + o[N["s"]]; + + // arguments (no-inference) + f(s); + f(N.s); + f(N["s"]); + g(s); + g(N.s); + g(N["s"]); + + // falsy expressions + s || ""; + N.s || ""; + N["s"] || ""; + + // conditionals + Math.random() * 2 ? s : "a"; + Math.random() * 2 ? N.s : "a"; + Math.random() * 2 ? N["s"] : "a"; + + // computed property names + ({ + [s]: "a", + [N.s]: "b", + }); + + class C1 { + static [s]: "a"; + static [N.s]: "b"; + + [s]: "a"; + [N.s]: "b"; + } + + // contextual types + + interface Context { + method1(): typeof s; + method2(): Promise; + method3(): AsyncIterableIterator; + method4(): IterableIterator; + method5(p?: typeof s): typeof s; + } + + const o4: Context = { + method1() { + return s; // return type should not widen due to contextual type + }, + async method2() { + return s; // return type should not widen due to contextual type + }, + async * method3() { + yield s; // yield type should not widen due to contextual type + }, + * method4() { + yield s; // yield type should not widen due to contextual type + }, + method5(p = s) { // parameter should not widen due to contextual type + return p; + } + }; \ No newline at end of file diff --git a/tests/baselines/reference/uniqueSymbolsDeclarations.js b/tests/baselines/reference/uniqueSymbolsDeclarations.js index 01d07f1d9f1d5..bf0120fc106c8 100644 --- a/tests/baselines/reference/uniqueSymbolsDeclarations.js +++ b/tests/baselines/reference/uniqueSymbolsDeclarations.js @@ -406,138 +406,3 @@ const o4 = { return p; } }; - - -//// [uniqueSymbolsDeclarations.d.ts] -declare const constCall: unique symbol; -declare let letCall: symbol; -declare var varCall: symbol; -declare const constType: unique symbol; -declare const constTypeAndCall: unique symbol; -declare const constInitToConstCall: symbol; -declare const constInitToLetCall: symbol; -declare const constInitToVarCall: symbol; -declare const constInitToConstDeclAmbient: symbol; -declare let letInitToConstCall: symbol; -declare let letInitToLetCall: symbol; -declare let letInitToVarCall: symbol; -declare let letInitToConstDeclAmbient: symbol; -declare var varInitToConstCall: symbol; -declare var varInitToLetCall: symbol; -declare var varInitToVarCall: symbol; -declare var varInitToConstDeclAmbient: symbol; -declare const constInitToConstCallWithTypeQuery: typeof constCall; -declare const constInitToConstDeclAmbientWithTypeQuery: typeof constType; -declare function funcReturnConstCall(): symbol; -declare function funcReturnLetCall(): symbol; -declare function funcReturnVarCall(): symbol; -declare function funcReturnConstCallWithTypeQuery(): typeof constCall; -declare function genFuncYieldConstCall(): Generator; -declare function genFuncYieldLetCall(): Generator; -declare function genFuncYieldVarCall(): Generator; -declare function genFuncYieldConstCallWithTypeQuery(): IterableIterator; -declare function asyncFuncReturnConstCall(): Promise; -declare function asyncFuncReturnLetCall(): Promise; -declare function asyncFuncReturnVarCall(): Promise; -declare function asyncGenFuncYieldConstCall(): AsyncGenerator; -declare function asyncGenFuncYieldLetCall(): AsyncGenerator; -declare function asyncGenFuncYieldVarCall(): AsyncGenerator; -declare class C { - static readonly readonlyStaticCall: unique symbol; - static readonly readonlyStaticType: unique symbol; - static readonly readonlyStaticTypeAndCall: unique symbol; - static readwriteStaticCall: symbol; - readonly readonlyCall: symbol; - readwriteCall: symbol; -} -declare const c: C; -declare const constInitToCReadonlyStaticCall: symbol; -declare const constInitToCReadonlyStaticType: symbol; -declare const constInitToCReadonlyStaticTypeAndCall: symbol; -declare const constInitToCReadwriteStaticCall: symbol; -declare const constInitToCReadonlyStaticCallWithTypeQuery: typeof C.readonlyStaticCall; -declare const constInitToCReadonlyStaticTypeWithTypeQuery: typeof C.readonlyStaticType; -declare const constInitToCReadonlyStaticTypeAndCallWithTypeQuery: typeof C.readonlyStaticTypeAndCall; -declare const constInitToCReadwriteStaticCallWithTypeQuery: typeof C.readwriteStaticCall; -declare const constInitToCReadonlyCall: symbol; -declare const constInitToCReadwriteCall: symbol; -declare const constInitToCReadonlyCallWithTypeQuery: typeof c.readonlyCall; -declare const constInitToCReadwriteCallWithTypeQuery: typeof c.readwriteCall; -declare const constInitToCReadonlyCallWithIndexedAccess: C["readonlyCall"]; -declare const constInitToCReadwriteCallWithIndexedAccess: C["readwriteCall"]; -interface I { - readonly readonlyType: unique symbol; -} -declare const i: I; -declare const constInitToIReadonlyType: symbol; -declare const constInitToIReadonlyTypeWithTypeQuery: typeof i.readonlyType; -declare const constInitToIReadonlyTypeWithIndexedAccess: I["readonlyType"]; -type L = { - readonly readonlyType: unique symbol; - nested: { - readonly readonlyNestedType: unique symbol; - }; -}; -declare const l: L; -declare const constInitToLReadonlyType: symbol; -declare const constInitToLReadonlyNestedType: symbol; -declare const constInitToLReadonlyTypeWithTypeQuery: typeof l.readonlyType; -declare const constInitToLReadonlyNestedTypeWithTypeQuery: typeof l.nested.readonlyNestedType; -declare const constInitToLReadonlyTypeWithIndexedAccess: L["readonlyType"]; -declare const constInitToLReadonlyNestedTypeWithIndexedAccess: L["nested"]["readonlyNestedType"]; -declare const promiseForConstCall: Promise; -declare const arrayOfConstCall: symbol[]; -declare const s: unique symbol; -declare namespace N { - const s: unique symbol; -} -declare const o: { - [s]: "a"; - [N.s]: "b"; -}; -declare function f(x: T): T; -declare function g(x: typeof s): void; -declare function g(x: typeof N.s): void; -declare const o2: { - a: symbol; - b: symbol; - c: symbol; - method1(): symbol; - method2(): Promise; - method3(): AsyncGenerator; - method4(): Generator; - method5(p?: symbol): symbol; -}; -declare class C0 { - static readonly a: symbol; - static readonly b: symbol; - static readonly c: symbol; - static d: symbol; - static e: symbol; - static f: symbol; - readonly a: symbol; - readonly b: symbol; - readonly c: symbol; - d: symbol; - e: symbol; - f: symbol; - method1(): symbol; - method2(): Promise; - method3(): AsyncGenerator; - method4(): Generator; - method5(p?: symbol): symbol; -} -declare class C1 { - static [s]: "a"; - static [N.s]: "b"; - [s]: "a"; - [N.s]: "b"; -} -interface Context { - method1(): typeof s; - method2(): Promise; - method3(): AsyncIterableIterator; - method4(): IterableIterator; - method5(p?: typeof s): typeof s; -} -declare const o4: Context; diff --git a/tests/baselines/reference/uniqueSymbolsDeclarations.types b/tests/baselines/reference/uniqueSymbolsDeclarations.types index b22c81175916e..8986ddfb8ac32 100644 --- a/tests/baselines/reference/uniqueSymbolsDeclarations.types +++ b/tests/baselines/reference/uniqueSymbolsDeclarations.types @@ -29,7 +29,7 @@ const constTypeAndCall: unique symbol = Symbol(); // declaration from initializer const constInitToConstCall = constCall; ->constInitToConstCall : symbol +>constInitToConstCall : unique symbol >constCall : unique symbol const constInitToLetCall = letCall; @@ -41,7 +41,7 @@ const constInitToVarCall = varCall; >varCall : symbol const constInitToConstDeclAmbient = constType; ->constInitToConstDeclAmbient : symbol +>constInitToConstDeclAmbient : unique symbol >constType : unique symbol let letInitToConstCall = constCall; @@ -194,19 +194,19 @@ declare const c: C; >c : C const constInitToCReadonlyStaticCall = C.readonlyStaticCall; ->constInitToCReadonlyStaticCall : symbol +>constInitToCReadonlyStaticCall : unique symbol >C.readonlyStaticCall : unique symbol >C : typeof C >readonlyStaticCall : unique symbol const constInitToCReadonlyStaticType = C.readonlyStaticType; ->constInitToCReadonlyStaticType : symbol +>constInitToCReadonlyStaticType : unique symbol >C.readonlyStaticType : unique symbol >C : typeof C >readonlyStaticType : unique symbol const constInitToCReadonlyStaticTypeAndCall = C.readonlyStaticTypeAndCall; ->constInitToCReadonlyStaticTypeAndCall : symbol +>constInitToCReadonlyStaticTypeAndCall : unique symbol >C.readonlyStaticTypeAndCall : unique symbol >C : typeof C >readonlyStaticTypeAndCall : unique symbol @@ -304,7 +304,7 @@ declare const i: I; >i : I const constInitToIReadonlyType = i.readonlyType; ->constInitToIReadonlyType : symbol +>constInitToIReadonlyType : unique symbol >i.readonlyType : unique symbol >i : I >readonlyType : unique symbol @@ -342,13 +342,13 @@ declare const l: L; >l : L const constInitToLReadonlyType = l.readonlyType; ->constInitToLReadonlyType : symbol +>constInitToLReadonlyType : unique symbol >l.readonlyType : unique symbol >l : L >readonlyType : unique symbol const constInitToLReadonlyNestedType = l.nested.readonlyNestedType; ->constInitToLReadonlyNestedType : symbol +>constInitToLReadonlyNestedType : unique symbol >l.nested.readonlyNestedType : unique symbol >l.nested : { readonly readonlyNestedType: unique symbol; } >l : L @@ -529,17 +529,17 @@ class C0 { >C0 : C0 static readonly a = s; ->a : symbol +>a : unique symbol >s : unique symbol static readonly b = N.s; ->b : symbol +>b : unique symbol >N.s : unique symbol >N : typeof N >s : unique symbol static readonly c = N["s"]; ->c : symbol +>c : unique symbol >N["s"] : unique symbol >N : typeof N >"s" : "s" @@ -561,17 +561,17 @@ class C0 { >"s" : "s" readonly a = s; ->a : symbol +>a : unique symbol >s : unique symbol readonly b = N.s; ->b : symbol +>b : unique symbol >N.s : unique symbol >N : typeof N >s : unique symbol readonly c = N["s"]; ->c : symbol +>c : unique symbol >N["s"] : unique symbol >N : typeof N >"s" : "s" From 203ba19fe8b8fef479b5c6b0845dbdc2a563fa20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 26 Jun 2023 14:36:24 +0200 Subject: [PATCH 2/6] Widen symbols in mutable locations early --- src/compiler/checker.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b9c5b46c2c421..0b7db182c7a87 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11055,15 +11055,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reportErrorsFromWidening(declaration, type); } - // always widen a 'unique symbol' type if the type was created for a different declaration and if it's assigned to something mutable - if (type.flags & TypeFlags.UniqueESSymbol && - (isBindingElement(declaration) || !declaration.type) && - !isDeclarationReadonly(declaration) && !(isVariableDeclaration(declaration) && isVarConstLike(declaration)) && !isConstContext(declaration) && - type.symbol !== getSymbolOfDeclaration(declaration) - ) { - type = esSymbolType; - } - return getWidenedType(type); } @@ -37574,7 +37565,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function widenTypeInferredFromInitializer(declaration: HasExpressionInitializer, type: Type) { - const widened = getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant || isDeclarationReadonly(declaration) ? type : getWidenedLiteralType(type); + const widened = getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant || isDeclarationReadonly(declaration) ? type : getWidenedUniqueESSymbolType(getWidenedLiteralType(type)); if (isInJSFile(declaration)) { if (isEmptyLiteralType(widened)) { reportImplicitAny(declaration, anyType); From 1994e6cc5aef5e7bcacf25c7e8b1ea4972c83554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 26 Jun 2023 14:45:39 +0200 Subject: [PATCH 3/6] Bring back symbol widening if the type is not accessible --- src/compiler/checker.ts | 5 + tests/baselines/reference/uniqueSymbols.types | 4 +- .../uniqueSymbolsDeclarations.errors.txt | 247 ------------------ .../reference/uniqueSymbolsDeclarations.js | 135 ++++++++++ .../reference/uniqueSymbolsDeclarations.types | 4 +- 5 files changed, 144 insertions(+), 251 deletions(-) delete mode 100644 tests/baselines/reference/uniqueSymbolsDeclarations.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0b7db182c7a87..36a7bee0aef69 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11055,6 +11055,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reportErrorsFromWidening(declaration, type); } + // always widen a 'unique symbol' type if the type was created for a different declaration and if it isn't accessible + if (type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) && type.symbol !== getSymbolOfDeclaration(declaration) && !isValueSymbolAccessible(type.symbol, declaration)) { + type = esSymbolType; + } + return getWidenedType(type); } diff --git a/tests/baselines/reference/uniqueSymbols.types b/tests/baselines/reference/uniqueSymbols.types index bbe57cba5483e..f5611658f4470 100644 --- a/tests/baselines/reference/uniqueSymbols.types +++ b/tests/baselines/reference/uniqueSymbols.types @@ -349,13 +349,13 @@ declare const l: L; >l : L const constInitToLReadonlyType = l.readonlyType; ->constInitToLReadonlyType : unique symbol +>constInitToLReadonlyType : symbol >l.readonlyType : unique symbol >l : L >readonlyType : unique symbol const constInitToLReadonlyNestedType = l.nested.readonlyNestedType; ->constInitToLReadonlyNestedType : unique symbol +>constInitToLReadonlyNestedType : symbol >l.nested.readonlyNestedType : unique symbol >l.nested : { readonly readonlyNestedType: unique symbol; } >l : L diff --git a/tests/baselines/reference/uniqueSymbolsDeclarations.errors.txt b/tests/baselines/reference/uniqueSymbolsDeclarations.errors.txt deleted file mode 100644 index 90fae715c43f6..0000000000000 --- a/tests/baselines/reference/uniqueSymbolsDeclarations.errors.txt +++ /dev/null @@ -1,247 +0,0 @@ -uniqueSymbolsDeclarations.ts(104,7): error TS2527: The inferred type of 'constInitToLReadonlyType' references an inaccessible 'unique symbol' type. A type annotation is necessary. -uniqueSymbolsDeclarations.ts(105,7): error TS2527: The inferred type of 'constInitToLReadonlyNestedType' references an inaccessible 'unique symbol' type. A type annotation is necessary. - - -==== uniqueSymbolsDeclarations.ts (2 errors) ==== - // declarations with call initializer - const constCall = Symbol(); - let letCall = Symbol(); - var varCall = Symbol(); - - // ambient declaration with type - declare const constType: unique symbol; - - // declaration with type and call initializer - const constTypeAndCall: unique symbol = Symbol(); - - // declaration from initializer - const constInitToConstCall = constCall; - const constInitToLetCall = letCall; - const constInitToVarCall = varCall; - const constInitToConstDeclAmbient = constType; - let letInitToConstCall = constCall; - let letInitToLetCall = letCall; - let letInitToVarCall = varCall; - let letInitToConstDeclAmbient = constType; - var varInitToConstCall = constCall; - var varInitToLetCall = letCall; - var varInitToVarCall = varCall; - var varInitToConstDeclAmbient = constType; - - // declaration from initializer with type query - const constInitToConstCallWithTypeQuery: typeof constCall = constCall; - const constInitToConstDeclAmbientWithTypeQuery: typeof constType = constType; - - // function return inference - function funcReturnConstCall() { return constCall; } - function funcReturnLetCall() { return letCall; } - function funcReturnVarCall() { return varCall; } - - // function return value with type query - function funcReturnConstCallWithTypeQuery(): typeof constCall { return constCall; } - - // generator function yield inference - function* genFuncYieldConstCall() { yield constCall; } - function* genFuncYieldLetCall() { yield letCall; } - function* genFuncYieldVarCall() { yield varCall; } - - // generator function yield with return type query - function* genFuncYieldConstCallWithTypeQuery(): IterableIterator { yield constCall; } - - // async function return inference - async function asyncFuncReturnConstCall() { return constCall; } - async function asyncFuncReturnLetCall() { return letCall; } - async function asyncFuncReturnVarCall() { return varCall; } - - // async generator function yield inference - async function* asyncGenFuncYieldConstCall() { yield constCall; } - async function* asyncGenFuncYieldLetCall() { yield letCall; } - async function* asyncGenFuncYieldVarCall() { yield varCall; } - - // classes - class C { - static readonly readonlyStaticCall = Symbol(); - static readonly readonlyStaticType: unique symbol; - static readonly readonlyStaticTypeAndCall: unique symbol = Symbol(); - static readwriteStaticCall = Symbol(); - - readonly readonlyCall = Symbol(); - readwriteCall = Symbol(); - } - declare const c: C; - - const constInitToCReadonlyStaticCall = C.readonlyStaticCall; - const constInitToCReadonlyStaticType = C.readonlyStaticType; - const constInitToCReadonlyStaticTypeAndCall = C.readonlyStaticTypeAndCall; - const constInitToCReadwriteStaticCall = C.readwriteStaticCall; - - const constInitToCReadonlyStaticCallWithTypeQuery: typeof C.readonlyStaticCall = C.readonlyStaticCall; - const constInitToCReadonlyStaticTypeWithTypeQuery: typeof C.readonlyStaticType = C.readonlyStaticType; - const constInitToCReadonlyStaticTypeAndCallWithTypeQuery: typeof C.readonlyStaticTypeAndCall = C.readonlyStaticTypeAndCall; - const constInitToCReadwriteStaticCallWithTypeQuery: typeof C.readwriteStaticCall = C.readwriteStaticCall; - - const constInitToCReadonlyCall = c.readonlyCall; - const constInitToCReadwriteCall = c.readwriteCall; - const constInitToCReadonlyCallWithTypeQuery: typeof c.readonlyCall = c.readonlyCall; - const constInitToCReadwriteCallWithTypeQuery: typeof c.readwriteCall = c.readwriteCall; - const constInitToCReadonlyCallWithIndexedAccess: C["readonlyCall"] = c.readonlyCall; - const constInitToCReadwriteCallWithIndexedAccess: C["readwriteCall"] = c.readwriteCall; - - // interfaces - interface I { - readonly readonlyType: unique symbol; - } - declare const i: I; - - const constInitToIReadonlyType = i.readonlyType; - const constInitToIReadonlyTypeWithTypeQuery: typeof i.readonlyType = i.readonlyType; - const constInitToIReadonlyTypeWithIndexedAccess: I["readonlyType"] = i.readonlyType; - - // type literals - type L = { - readonly readonlyType: unique symbol; - nested: { - readonly readonlyNestedType: unique symbol; - } - }; - declare const l: L; - - const constInitToLReadonlyType = l.readonlyType; - ~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2527: The inferred type of 'constInitToLReadonlyType' references an inaccessible 'unique symbol' type. A type annotation is necessary. - const constInitToLReadonlyNestedType = l.nested.readonlyNestedType; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2527: The inferred type of 'constInitToLReadonlyNestedType' references an inaccessible 'unique symbol' type. A type annotation is necessary. - const constInitToLReadonlyTypeWithTypeQuery: typeof l.readonlyType = l.readonlyType; - const constInitToLReadonlyNestedTypeWithTypeQuery: typeof l.nested.readonlyNestedType = l.nested.readonlyNestedType; - const constInitToLReadonlyTypeWithIndexedAccess: L["readonlyType"] = l.readonlyType; - const constInitToLReadonlyNestedTypeWithIndexedAccess: L["nested"]["readonlyNestedType"] = l.nested.readonlyNestedType; - - // type argument inference - const promiseForConstCall = Promise.resolve(constCall); - const arrayOfConstCall = [constCall]; - - // unique symbol widening in expressions - declare const s: unique symbol; - declare namespace N { const s: unique symbol; } - declare const o: { [s]: "a", [N.s]: "b" }; - declare function f(x: T): T; - declare function g(x: typeof s): void; - declare function g(x: typeof N.s): void; - - // widening positions - - // argument inference - f(s); - f(N.s); - f(N["s"]); - - // array literal elements - [s]; - [N.s]; - [N["s"]]; - - // property assignments/methods - const o2 = { - a: s, - b: N.s, - c: N["s"], - - method1() { return s; }, - async method2() { return s; }, - async * method3() { yield s; }, - * method4() { yield s; }, - method5(p = s) { return p; } - }; - - // property initializers - class C0 { - static readonly a = s; - static readonly b = N.s; - static readonly c = N["s"]; - - static d = s; - static e = N.s; - static f = N["s"]; - - readonly a = s; - readonly b = N.s; - readonly c = N["s"]; - - d = s; - e = N.s; - f = N["s"]; - - method1() { return s; } - async method2() { return s; } - async * method3() { yield s; } - * method4() { yield s; } - method5(p = s) { return p; } - } - - // non-widening positions - - // element access - o[s]; - o[N.s]; - o[N["s"]]; - - // arguments (no-inference) - f(s); - f(N.s); - f(N["s"]); - g(s); - g(N.s); - g(N["s"]); - - // falsy expressions - s || ""; - N.s || ""; - N["s"] || ""; - - // conditionals - Math.random() * 2 ? s : "a"; - Math.random() * 2 ? N.s : "a"; - Math.random() * 2 ? N["s"] : "a"; - - // computed property names - ({ - [s]: "a", - [N.s]: "b", - }); - - class C1 { - static [s]: "a"; - static [N.s]: "b"; - - [s]: "a"; - [N.s]: "b"; - } - - // contextual types - - interface Context { - method1(): typeof s; - method2(): Promise; - method3(): AsyncIterableIterator; - method4(): IterableIterator; - method5(p?: typeof s): typeof s; - } - - const o4: Context = { - method1() { - return s; // return type should not widen due to contextual type - }, - async method2() { - return s; // return type should not widen due to contextual type - }, - async * method3() { - yield s; // yield type should not widen due to contextual type - }, - * method4() { - yield s; // yield type should not widen due to contextual type - }, - method5(p = s) { // parameter should not widen due to contextual type - return p; - } - }; \ No newline at end of file diff --git a/tests/baselines/reference/uniqueSymbolsDeclarations.js b/tests/baselines/reference/uniqueSymbolsDeclarations.js index bf0120fc106c8..6d2e7229e6056 100644 --- a/tests/baselines/reference/uniqueSymbolsDeclarations.js +++ b/tests/baselines/reference/uniqueSymbolsDeclarations.js @@ -406,3 +406,138 @@ const o4 = { return p; } }; + + +//// [uniqueSymbolsDeclarations.d.ts] +declare const constCall: unique symbol; +declare let letCall: symbol; +declare var varCall: symbol; +declare const constType: unique symbol; +declare const constTypeAndCall: unique symbol; +declare const constInitToConstCall: typeof constCall; +declare const constInitToLetCall: symbol; +declare const constInitToVarCall: symbol; +declare const constInitToConstDeclAmbient: typeof constType; +declare let letInitToConstCall: symbol; +declare let letInitToLetCall: symbol; +declare let letInitToVarCall: symbol; +declare let letInitToConstDeclAmbient: symbol; +declare var varInitToConstCall: symbol; +declare var varInitToLetCall: symbol; +declare var varInitToVarCall: symbol; +declare var varInitToConstDeclAmbient: symbol; +declare const constInitToConstCallWithTypeQuery: typeof constCall; +declare const constInitToConstDeclAmbientWithTypeQuery: typeof constType; +declare function funcReturnConstCall(): symbol; +declare function funcReturnLetCall(): symbol; +declare function funcReturnVarCall(): symbol; +declare function funcReturnConstCallWithTypeQuery(): typeof constCall; +declare function genFuncYieldConstCall(): Generator; +declare function genFuncYieldLetCall(): Generator; +declare function genFuncYieldVarCall(): Generator; +declare function genFuncYieldConstCallWithTypeQuery(): IterableIterator; +declare function asyncFuncReturnConstCall(): Promise; +declare function asyncFuncReturnLetCall(): Promise; +declare function asyncFuncReturnVarCall(): Promise; +declare function asyncGenFuncYieldConstCall(): AsyncGenerator; +declare function asyncGenFuncYieldLetCall(): AsyncGenerator; +declare function asyncGenFuncYieldVarCall(): AsyncGenerator; +declare class C { + static readonly readonlyStaticCall: unique symbol; + static readonly readonlyStaticType: unique symbol; + static readonly readonlyStaticTypeAndCall: unique symbol; + static readwriteStaticCall: symbol; + readonly readonlyCall: symbol; + readwriteCall: symbol; +} +declare const c: C; +declare const constInitToCReadonlyStaticCall: typeof C.readonlyStaticCall; +declare const constInitToCReadonlyStaticType: typeof C.readonlyStaticType; +declare const constInitToCReadonlyStaticTypeAndCall: typeof C.readonlyStaticTypeAndCall; +declare const constInitToCReadwriteStaticCall: symbol; +declare const constInitToCReadonlyStaticCallWithTypeQuery: typeof C.readonlyStaticCall; +declare const constInitToCReadonlyStaticTypeWithTypeQuery: typeof C.readonlyStaticType; +declare const constInitToCReadonlyStaticTypeAndCallWithTypeQuery: typeof C.readonlyStaticTypeAndCall; +declare const constInitToCReadwriteStaticCallWithTypeQuery: typeof C.readwriteStaticCall; +declare const constInitToCReadonlyCall: symbol; +declare const constInitToCReadwriteCall: symbol; +declare const constInitToCReadonlyCallWithTypeQuery: typeof c.readonlyCall; +declare const constInitToCReadwriteCallWithTypeQuery: typeof c.readwriteCall; +declare const constInitToCReadonlyCallWithIndexedAccess: C["readonlyCall"]; +declare const constInitToCReadwriteCallWithIndexedAccess: C["readwriteCall"]; +interface I { + readonly readonlyType: unique symbol; +} +declare const i: I; +declare const constInitToIReadonlyType: typeof i.readonlyType; +declare const constInitToIReadonlyTypeWithTypeQuery: typeof i.readonlyType; +declare const constInitToIReadonlyTypeWithIndexedAccess: I["readonlyType"]; +type L = { + readonly readonlyType: unique symbol; + nested: { + readonly readonlyNestedType: unique symbol; + }; +}; +declare const l: L; +declare const constInitToLReadonlyType: symbol; +declare const constInitToLReadonlyNestedType: symbol; +declare const constInitToLReadonlyTypeWithTypeQuery: typeof l.readonlyType; +declare const constInitToLReadonlyNestedTypeWithTypeQuery: typeof l.nested.readonlyNestedType; +declare const constInitToLReadonlyTypeWithIndexedAccess: L["readonlyType"]; +declare const constInitToLReadonlyNestedTypeWithIndexedAccess: L["nested"]["readonlyNestedType"]; +declare const promiseForConstCall: Promise; +declare const arrayOfConstCall: symbol[]; +declare const s: unique symbol; +declare namespace N { + const s: unique symbol; +} +declare const o: { + [s]: "a"; + [N.s]: "b"; +}; +declare function f(x: T): T; +declare function g(x: typeof s): void; +declare function g(x: typeof N.s): void; +declare const o2: { + a: symbol; + b: symbol; + c: symbol; + method1(): symbol; + method2(): Promise; + method3(): AsyncGenerator; + method4(): Generator; + method5(p?: symbol): symbol; +}; +declare class C0 { + static readonly a: typeof s; + static readonly b: typeof N.s; + static readonly c: typeof N.s; + static d: symbol; + static e: symbol; + static f: symbol; + readonly a: typeof s; + readonly b: typeof N.s; + readonly c: typeof N.s; + d: symbol; + e: symbol; + f: symbol; + method1(): symbol; + method2(): Promise; + method3(): AsyncGenerator; + method4(): Generator; + method5(p?: symbol): symbol; +} +declare class C1 { + static [s]: "a"; + static [N.s]: "b"; + [s]: "a"; + [N.s]: "b"; +} +interface Context { + method1(): typeof s; + method2(): Promise; + method3(): AsyncIterableIterator; + method4(): IterableIterator; + method5(p?: typeof s): typeof s; +} +declare const o4: Context; diff --git a/tests/baselines/reference/uniqueSymbolsDeclarations.types b/tests/baselines/reference/uniqueSymbolsDeclarations.types index 8986ddfb8ac32..9abca24e2a3b1 100644 --- a/tests/baselines/reference/uniqueSymbolsDeclarations.types +++ b/tests/baselines/reference/uniqueSymbolsDeclarations.types @@ -342,13 +342,13 @@ declare const l: L; >l : L const constInitToLReadonlyType = l.readonlyType; ->constInitToLReadonlyType : unique symbol +>constInitToLReadonlyType : symbol >l.readonlyType : unique symbol >l : L >readonlyType : unique symbol const constInitToLReadonlyNestedType = l.nested.readonlyNestedType; ->constInitToLReadonlyNestedType : unique symbol +>constInitToLReadonlyNestedType : symbol >l.nested.readonlyNestedType : unique symbol >l.nested : { readonly readonlyNestedType: unique symbol; } >l : L From 16456d7300aa3bce1cc604c745fee8ada439d5f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 26 Jun 2023 15:16:03 +0200 Subject: [PATCH 4/6] Use `type.symbol.valueDeclaration` to compute visibility --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 36a7bee0aef69..a0b74d7e2dc8b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11056,7 +11056,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // always widen a 'unique symbol' type if the type was created for a different declaration and if it isn't accessible - if (type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) && type.symbol !== getSymbolOfDeclaration(declaration) && !isValueSymbolAccessible(type.symbol, declaration)) { + if (type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) && type.symbol !== getSymbolOfDeclaration(declaration) && !isValueSymbolAccessible(type.symbol, type.symbol.valueDeclaration)) { type = esSymbolType; } From 87dbb90c77010e22fdf522d07205e548cb5fb205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 26 Jun 2023 15:21:07 +0200 Subject: [PATCH 5/6] Add a new test case for the fixed case --- .../indirectUniqueSymbolDeclarationEmit2.js | 36 +++++++++++++++++++ ...directUniqueSymbolDeclarationEmit2.symbols | 24 +++++++++++++ ...indirectUniqueSymbolDeclarationEmit2.types | 28 +++++++++++++++ .../indirectUniqueSymbolDeclarationEmit2.ts | 13 +++++++ 4 files changed, 101 insertions(+) create mode 100644 tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.js create mode 100644 tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.symbols create mode 100644 tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.types create mode 100644 tests/cases/compiler/indirectUniqueSymbolDeclarationEmit2.ts diff --git a/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.js b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.js new file mode 100644 index 0000000000000..ade471c432477 --- /dev/null +++ b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.js @@ -0,0 +1,36 @@ +//// [tests/cases/compiler/indirectUniqueSymbolDeclarationEmit2.ts] //// + +//// [indirectUniqueSymbolDeclarationEmit2.ts] +// repro from https://github.com/microsoft/TypeScript/issues/53276 + +export const a = Symbol.toStringTag; + +export class F { + [a](){ return "" } +} + +export const b = (new F())[a]; + + +//// [indirectUniqueSymbolDeclarationEmit2.js] +"use strict"; +// repro from https://github.com/microsoft/TypeScript/issues/53276 +Object.defineProperty(exports, "__esModule", { value: true }); +exports.b = exports.F = exports.a = void 0; +exports.a = Symbol.toStringTag; +var F = /** @class */ (function () { + function F() { + } + F.prototype[exports.a] = function () { return ""; }; + return F; +}()); +exports.F = F; +exports.b = (new F())[exports.a]; + + +//// [indirectUniqueSymbolDeclarationEmit2.d.ts] +export declare const a: typeof Symbol.toStringTag; +export declare class F { + [a](): string; +} +export declare const b: () => string; diff --git a/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.symbols b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.symbols new file mode 100644 index 0000000000000..aafb4036487f4 --- /dev/null +++ b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.symbols @@ -0,0 +1,24 @@ +//// [tests/cases/compiler/indirectUniqueSymbolDeclarationEmit2.ts] //// + +=== indirectUniqueSymbolDeclarationEmit2.ts === +// repro from https://github.com/microsoft/TypeScript/issues/53276 + +export const a = Symbol.toStringTag; +>a : Symbol(a, Decl(indirectUniqueSymbolDeclarationEmit2.ts, 2, 12)) +>Symbol.toStringTag : Symbol(SymbolConstructor.toStringTag, Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>toStringTag : Symbol(SymbolConstructor.toStringTag, Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) + +export class F { +>F : Symbol(F, Decl(indirectUniqueSymbolDeclarationEmit2.ts, 2, 36)) + + [a](){ return "" } +>[a] : Symbol(F[a], Decl(indirectUniqueSymbolDeclarationEmit2.ts, 4, 16)) +>a : Symbol(a, Decl(indirectUniqueSymbolDeclarationEmit2.ts, 2, 12)) +} + +export const b = (new F())[a]; +>b : Symbol(b, Decl(indirectUniqueSymbolDeclarationEmit2.ts, 8, 12)) +>F : Symbol(F, Decl(indirectUniqueSymbolDeclarationEmit2.ts, 2, 36)) +>a : Symbol(a, Decl(indirectUniqueSymbolDeclarationEmit2.ts, 2, 12)) + diff --git a/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.types b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.types new file mode 100644 index 0000000000000..896a01c36c2b3 --- /dev/null +++ b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit2.types @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/indirectUniqueSymbolDeclarationEmit2.ts] //// + +=== indirectUniqueSymbolDeclarationEmit2.ts === +// repro from https://github.com/microsoft/TypeScript/issues/53276 + +export const a = Symbol.toStringTag; +>a : unique symbol +>Symbol.toStringTag : unique symbol +>Symbol : SymbolConstructor +>toStringTag : unique symbol + +export class F { +>F : F + + [a](){ return "" } +>[a] : () => string +>a : unique symbol +>"" : "" +} + +export const b = (new F())[a]; +>b : () => string +>(new F())[a] : () => string +>(new F()) : F +>new F() : F +>F : typeof F +>a : unique symbol + diff --git a/tests/cases/compiler/indirectUniqueSymbolDeclarationEmit2.ts b/tests/cases/compiler/indirectUniqueSymbolDeclarationEmit2.ts new file mode 100644 index 0000000000000..ba8abf37f0ec6 --- /dev/null +++ b/tests/cases/compiler/indirectUniqueSymbolDeclarationEmit2.ts @@ -0,0 +1,13 @@ +// @strict: true +// @lib: esnext +// @declaration: true + +// repro from https://github.com/microsoft/TypeScript/issues/53276 + +export const a = Symbol.toStringTag; + +export class F { + [a](){ return "" } +} + +export const b = (new F())[a]; From d7dc3f98fb0cd67f09d68a9ab36e91c6429340d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 26 Jun 2023 15:54:11 +0200 Subject: [PATCH 6/6] Remove a redundant check --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a0b74d7e2dc8b..78acaad7d2011 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11056,7 +11056,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // always widen a 'unique symbol' type if the type was created for a different declaration and if it isn't accessible - if (type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) && type.symbol !== getSymbolOfDeclaration(declaration) && !isValueSymbolAccessible(type.symbol, type.symbol.valueDeclaration)) { + if (type.flags & TypeFlags.UniqueESSymbol && !declaration.type && type.symbol !== getSymbolOfDeclaration(declaration) && !isValueSymbolAccessible(type.symbol, type.symbol.valueDeclaration)) { type = esSymbolType; }