From 338f3c031221ee381031f88f9e80e51d55c09a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 26 Dec 2024 11:36:09 +0100 Subject: [PATCH 1/3] Don't merge late bound assignment members with pre-existing symbols --- src/compiler/checker.ts | 15 +++-- .../lateBoundAssignmentCandidateJS1.js | 61 ++++++++++++++++++ .../lateBoundAssignmentCandidateJS1.symbols | 41 ++++++++++++ .../lateBoundAssignmentCandidateJS1.types | 64 +++++++++++++++++++ .../lateBoundAssignmentCandidateJS2.js | 40 ++++++++++++ .../lateBoundAssignmentCandidateJS2.symbols | 24 +++++++ .../lateBoundAssignmentCandidateJS2.types | 40 ++++++++++++ ...lateBoundAssignmentCandidateJS3.errors.txt | 20 ++++++ .../lateBoundAssignmentCandidateJS3.js | 40 ++++++++++++ .../lateBoundAssignmentCandidateJS3.symbols | 23 +++++++ .../lateBoundAssignmentCandidateJS3.types | 38 +++++++++++ .../lateBoundMethodNameAssigmentJS.js | 2 +- .../lateBoundMethodNameAssigmentJS.symbols | 2 + .../lateBoundMethodNameAssigmentJS.types | 23 ++++--- .../lateBoundAssignmentCandidateJS1.ts | 31 +++++++++ .../lateBoundAssignmentCandidateJS2.ts | 23 +++++++ .../lateBoundAssignmentCandidateJS3.ts | 23 +++++++ 17 files changed, 493 insertions(+), 17 deletions(-) create mode 100644 tests/baselines/reference/lateBoundAssignmentCandidateJS1.js create mode 100644 tests/baselines/reference/lateBoundAssignmentCandidateJS1.symbols create mode 100644 tests/baselines/reference/lateBoundAssignmentCandidateJS1.types create mode 100644 tests/baselines/reference/lateBoundAssignmentCandidateJS2.js create mode 100644 tests/baselines/reference/lateBoundAssignmentCandidateJS2.symbols create mode 100644 tests/baselines/reference/lateBoundAssignmentCandidateJS2.types create mode 100644 tests/baselines/reference/lateBoundAssignmentCandidateJS3.errors.txt create mode 100644 tests/baselines/reference/lateBoundAssignmentCandidateJS3.js create mode 100644 tests/baselines/reference/lateBoundAssignmentCandidateJS3.symbols create mode 100644 tests/baselines/reference/lateBoundAssignmentCandidateJS3.types create mode 100644 tests/cases/compiler/lateBoundAssignmentCandidateJS1.ts create mode 100644 tests/cases/compiler/lateBoundAssignmentCandidateJS2.ts create mode 100644 tests/cases/compiler/lateBoundAssignmentCandidateJS3.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 80b61edd3657a..583854149f886 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13197,10 +13197,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (!member.symbol.isReplaceableByMethod) { symbol.declarations.push(member); } - if (symbolFlags & SymbolFlags.Value) { - if (!symbol.valueDeclaration || symbol.valueDeclaration.kind !== member.kind) { - symbol.valueDeclaration = member; - } + if (symbolFlags & SymbolFlags.Value && !symbol.valueDeclaration) { + symbol.valueDeclaration = member; } } @@ -13232,7 +13230,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param lateSymbols The late-bound symbols of the parent. * @param decl The member to bind. */ - function lateBindMember(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: Map<__String, TransientSymbol>, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration) { + function lateBindMember(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: Map<__String, TransientSymbol>, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration, isFromAssignmentDeclarationMember = false) { Debug.assert(!!decl.symbol, "The member is expected to have a symbol."); const links = getNodeLinks(decl); if (!links.resolvedSymbol) { @@ -13247,10 +13245,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Get or add a late-bound symbol for the member. This allows us to merge late-bound accessor declarations. let lateSymbol = lateSymbols.get(memberName); + if (isFromAssignmentDeclarationMember && lateSymbol) { + return links.resolvedSymbol = lateSymbol; + } if (!lateSymbol) lateSymbols.set(memberName, lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late)); // Report an error if there's a symbol declaration with the same name and conflicting flags. - const earlySymbol = earlySymbols && earlySymbols.get(memberName); + const earlySymbol = earlySymbols?.get(memberName); // Duplicate property declarations of classes are checked in checkClassForDuplicateDeclarations. if (!(parent.flags & SymbolFlags.Class) && lateSymbol.flags & getExcludedSymbolFlags(symbolFlags)) { // If we have an existing early-bound member, combine its declarations so that we can @@ -13342,7 +13343,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { || assignmentKind === AssignmentDeclarationKind.Prototype; // A straight `Prototype` assignment probably can never have a computed name if (isStatic === !isInstanceMember) { if (hasLateBindableName(member)) { - lateBindMember(symbol, earlySymbols, lateSymbols, member); + lateBindMember(symbol, earlySymbols, lateSymbols, member, /*isFromAssignmentDeclarationMember*/ true); } } } diff --git a/tests/baselines/reference/lateBoundAssignmentCandidateJS1.js b/tests/baselines/reference/lateBoundAssignmentCandidateJS1.js new file mode 100644 index 0000000000000..8770ffab7a640 --- /dev/null +++ b/tests/baselines/reference/lateBoundAssignmentCandidateJS1.js @@ -0,0 +1,61 @@ +//// [tests/cases/compiler/lateBoundAssignmentCandidateJS1.ts] //// + +//// [index.js] +// https://github.com/microsoft/TypeScript/issues/60590 + +export const kBar = Symbol("bar"); + +export class foo0 { + /** + * @protected + * @type {null | string} + */ + [kBar] = null; + + get bar() { + return this[kBar]; + } + /** + * @type {string} + */ + set bar(value) { + this[kBar] = value; + } +} + + +//// [index.js] +// https://github.com/microsoft/TypeScript/issues/60590 +export const kBar = Symbol("bar"); +export class foo0 { + /** + * @protected + * @type {null | string} + */ + [kBar] = null; + get bar() { + return this[kBar]; + } + /** + * @type {string} + */ + set bar(value) { + this[kBar] = value; + } +} + + +//// [index.d.ts] +export const kBar: unique symbol; +export class foo0 { + /** + * @type {string} + */ + set bar(value: string | null); + get bar(): string | null; + /** + * @protected + * @type {null | string} + */ + protected [kBar]: null | string; +} diff --git a/tests/baselines/reference/lateBoundAssignmentCandidateJS1.symbols b/tests/baselines/reference/lateBoundAssignmentCandidateJS1.symbols new file mode 100644 index 0000000000000..02d82bb513812 --- /dev/null +++ b/tests/baselines/reference/lateBoundAssignmentCandidateJS1.symbols @@ -0,0 +1,41 @@ +//// [tests/cases/compiler/lateBoundAssignmentCandidateJS1.ts] //// + +=== index.js === +// https://github.com/microsoft/TypeScript/issues/60590 + +export const kBar = Symbol("bar"); +>kBar : Symbol(kBar, Decl(index.js, 2, 12)) +>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, --, --)) + +export class foo0 { +>foo0 : Symbol(foo0, Decl(index.js, 2, 34)) + + /** + * @protected + * @type {null | string} + */ + [kBar] = null; +>[kBar] : Symbol(foo0[kBar], Decl(index.js, 4, 19)) +>kBar : Symbol(kBar, Decl(index.js, 2, 12)) + + get bar() { +>bar : Symbol(foo0.bar, Decl(index.js, 9, 18), Decl(index.js, 13, 5)) + + return this[kBar]; +>this : Symbol(foo0, Decl(index.js, 2, 34)) +>kBar : Symbol(kBar, Decl(index.js, 2, 12)) + } + /** + * @type {string} + */ + set bar(value) { +>bar : Symbol(foo0.bar, Decl(index.js, 9, 18), Decl(index.js, 13, 5)) +>value : Symbol(value, Decl(index.js, 17, 12)) + + this[kBar] = value; +>this : Symbol(foo0, Decl(index.js, 2, 34)) +>kBar : Symbol(kBar, Decl(index.js, 2, 12)) +>value : Symbol(value, Decl(index.js, 17, 12)) + } +} + diff --git a/tests/baselines/reference/lateBoundAssignmentCandidateJS1.types b/tests/baselines/reference/lateBoundAssignmentCandidateJS1.types new file mode 100644 index 0000000000000..6f8c1eabcea21 --- /dev/null +++ b/tests/baselines/reference/lateBoundAssignmentCandidateJS1.types @@ -0,0 +1,64 @@ +//// [tests/cases/compiler/lateBoundAssignmentCandidateJS1.ts] //// + +=== index.js === +// https://github.com/microsoft/TypeScript/issues/60590 + +export const kBar = Symbol("bar"); +>kBar : unique symbol +> : ^^^^^^^^^^^^^ +>Symbol("bar") : unique symbol +> : ^^^^^^^^^^^^^ +>Symbol : SymbolConstructor +> : ^^^^^^^^^^^^^^^^^ +>"bar" : "bar" +> : ^^^^^ + +export class foo0 { +>foo0 : foo0 +> : ^^^^ + + /** + * @protected + * @type {null | string} + */ + [kBar] = null; +>[kBar] : string | null +> : ^^^^^^^^^^^^^ +>kBar : unique symbol +> : ^^^^^^^^^^^^^ + + get bar() { +>bar : string | null +> : ^^^^^^^^^^^^^ + + return this[kBar]; +>this[kBar] : string | null +> : ^^^^^^^^^^^^^ +>this : this +> : ^^^^ +>kBar : unique symbol +> : ^^^^^^^^^^^^^ + } + /** + * @type {string} + */ + set bar(value) { +>bar : string | null +> : ^^^^^^^^^^^^^ +>value : string | null +> : ^^^^^^^^^^^^^ + + this[kBar] = value; +>this[kBar] = value : string | null +> : ^^^^^^^^^^^^^ +>this[kBar] : string | null +> : ^^^^^^^^^^^^^ +>this : this +> : ^^^^ +>kBar : unique symbol +> : ^^^^^^^^^^^^^ +>value : string | null +> : ^^^^^^^^^^^^^ + } +} + diff --git a/tests/baselines/reference/lateBoundAssignmentCandidateJS2.js b/tests/baselines/reference/lateBoundAssignmentCandidateJS2.js new file mode 100644 index 0000000000000..64e2b120dd252 --- /dev/null +++ b/tests/baselines/reference/lateBoundAssignmentCandidateJS2.js @@ -0,0 +1,40 @@ +//// [tests/cases/compiler/lateBoundAssignmentCandidateJS2.ts] //// + +//// [index.js] +const prop = 'prop'; + +export class foo1 { + constructor() { + this[prop] = 'bar' + } + + /** + * @protected + * @type {string} + */ + [prop] = 'baz'; +} + + +//// [index.js] +const prop = 'prop'; +export class foo1 { + constructor() { + this[prop] = 'bar'; + } + /** + * @protected + * @type {string} + */ + [prop] = 'baz'; +} + + +//// [index.d.ts] +export class foo1 { + /** + * @protected + * @type {string} + */ + protected prop: string; +} diff --git a/tests/baselines/reference/lateBoundAssignmentCandidateJS2.symbols b/tests/baselines/reference/lateBoundAssignmentCandidateJS2.symbols new file mode 100644 index 0000000000000..554262a106f56 --- /dev/null +++ b/tests/baselines/reference/lateBoundAssignmentCandidateJS2.symbols @@ -0,0 +1,24 @@ +//// [tests/cases/compiler/lateBoundAssignmentCandidateJS2.ts] //// + +=== index.js === +const prop = 'prop'; +>prop : Symbol(prop, Decl(index.js, 0, 5)) + +export class foo1 { +>foo1 : Symbol(foo1, Decl(index.js, 0, 20)) + + constructor() { + this[prop] = 'bar' +>this : Symbol(foo1, Decl(index.js, 0, 20)) +>prop : Symbol(prop, Decl(index.js, 0, 5)) + } + + /** + * @protected + * @type {string} + */ + [prop] = 'baz'; +>[prop] : Symbol(foo1[prop], Decl(index.js, 5, 5)) +>prop : Symbol(prop, Decl(index.js, 0, 5)) +} + diff --git a/tests/baselines/reference/lateBoundAssignmentCandidateJS2.types b/tests/baselines/reference/lateBoundAssignmentCandidateJS2.types new file mode 100644 index 0000000000000..1cef472319cba --- /dev/null +++ b/tests/baselines/reference/lateBoundAssignmentCandidateJS2.types @@ -0,0 +1,40 @@ +//// [tests/cases/compiler/lateBoundAssignmentCandidateJS2.ts] //// + +=== index.js === +const prop = 'prop'; +>prop : "prop" +> : ^^^^^^ +>'prop' : "prop" +> : ^^^^^^ + +export class foo1 { +>foo1 : foo1 +> : ^^^^ + + constructor() { + this[prop] = 'bar' +>this[prop] = 'bar' : "bar" +> : ^^^^^ +>this[prop] : string +> : ^^^^^^ +>this : this +> : ^^^^ +>prop : "prop" +> : ^^^^^^ +>'bar' : "bar" +> : ^^^^^ + } + + /** + * @protected + * @type {string} + */ + [prop] = 'baz'; +>[prop] : string +> : ^^^^^^ +>prop : "prop" +> : ^^^^^^ +>'baz' : "baz" +> : ^^^^^ +} + diff --git a/tests/baselines/reference/lateBoundAssignmentCandidateJS3.errors.txt b/tests/baselines/reference/lateBoundAssignmentCandidateJS3.errors.txt new file mode 100644 index 0000000000000..5e5c1463e2d3c --- /dev/null +++ b/tests/baselines/reference/lateBoundAssignmentCandidateJS3.errors.txt @@ -0,0 +1,20 @@ +index.js(5,9): error TS2322: Type 'number' is not assignable to type 'string'. + + +==== index.js (1 errors) ==== + const prop = 'prop'; + + export class foo2 { + constructor() { + this[prop] = 12; + ~~~~~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + + /** + * @protected + * @type {string} + */ + prop = 'baz'; + } + \ No newline at end of file diff --git a/tests/baselines/reference/lateBoundAssignmentCandidateJS3.js b/tests/baselines/reference/lateBoundAssignmentCandidateJS3.js new file mode 100644 index 0000000000000..ccda0fbb4dd58 --- /dev/null +++ b/tests/baselines/reference/lateBoundAssignmentCandidateJS3.js @@ -0,0 +1,40 @@ +//// [tests/cases/compiler/lateBoundAssignmentCandidateJS3.ts] //// + +//// [index.js] +const prop = 'prop'; + +export class foo2 { + constructor() { + this[prop] = 12; + } + + /** + * @protected + * @type {string} + */ + prop = 'baz'; +} + + +//// [index.js] +const prop = 'prop'; +export class foo2 { + constructor() { + this[prop] = 12; + } + /** + * @protected + * @type {string} + */ + prop = 'baz'; +} + + +//// [index.d.ts] +export class foo2 { + /** + * @protected + * @type {string} + */ + protected prop: string; +} diff --git a/tests/baselines/reference/lateBoundAssignmentCandidateJS3.symbols b/tests/baselines/reference/lateBoundAssignmentCandidateJS3.symbols new file mode 100644 index 0000000000000..90d7466bdb7bd --- /dev/null +++ b/tests/baselines/reference/lateBoundAssignmentCandidateJS3.symbols @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/lateBoundAssignmentCandidateJS3.ts] //// + +=== index.js === +const prop = 'prop'; +>prop : Symbol(prop, Decl(index.js, 0, 5)) + +export class foo2 { +>foo2 : Symbol(foo2, Decl(index.js, 0, 20)) + + constructor() { + this[prop] = 12; +>this : Symbol(foo2, Decl(index.js, 0, 20)) +>prop : Symbol(prop, Decl(index.js, 0, 5)) + } + + /** + * @protected + * @type {string} + */ + prop = 'baz'; +>prop : Symbol(foo2.prop, Decl(index.js, 5, 5), Decl(index.js, 3, 19)) +} + diff --git a/tests/baselines/reference/lateBoundAssignmentCandidateJS3.types b/tests/baselines/reference/lateBoundAssignmentCandidateJS3.types new file mode 100644 index 0000000000000..4ab0adf2ccc4c --- /dev/null +++ b/tests/baselines/reference/lateBoundAssignmentCandidateJS3.types @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/lateBoundAssignmentCandidateJS3.ts] //// + +=== index.js === +const prop = 'prop'; +>prop : "prop" +> : ^^^^^^ +>'prop' : "prop" +> : ^^^^^^ + +export class foo2 { +>foo2 : foo2 +> : ^^^^ + + constructor() { + this[prop] = 12; +>this[prop] = 12 : 12 +> : ^^ +>this[prop] : string +> : ^^^^^^ +>this : this +> : ^^^^ +>prop : "prop" +> : ^^^^^^ +>12 : 12 +> : ^^ + } + + /** + * @protected + * @type {string} + */ + prop = 'baz'; +>prop : string +> : ^^^^^^ +>'baz' : "baz" +> : ^^^^^ +} + diff --git a/tests/baselines/reference/lateBoundMethodNameAssigmentJS.js b/tests/baselines/reference/lateBoundMethodNameAssigmentJS.js index 6dca9a46baa0c..8124f724c81ee 100644 --- a/tests/baselines/reference/lateBoundMethodNameAssigmentJS.js +++ b/tests/baselines/reference/lateBoundMethodNameAssigmentJS.js @@ -14,7 +14,7 @@ export class MyClass { //// [lateBoundMethodNameAssigmentJS.d.ts] export class MyClass { - [_symbol]: any; + [_symbol](): Promise; } declare const _symbol: unique symbol; export {}; diff --git a/tests/baselines/reference/lateBoundMethodNameAssigmentJS.symbols b/tests/baselines/reference/lateBoundMethodNameAssigmentJS.symbols index 0715b876e7f55..ec3323721f749 100644 --- a/tests/baselines/reference/lateBoundMethodNameAssigmentJS.symbols +++ b/tests/baselines/reference/lateBoundMethodNameAssigmentJS.symbols @@ -12,8 +12,10 @@ export class MyClass { this[_symbol] = this[_symbol].bind(this); >this : Symbol(MyClass, Decl(lateBoundMethodNameAssigmentJS.js, 0, 31)) >_symbol : Symbol(_symbol, Decl(lateBoundMethodNameAssigmentJS.js, 0, 5)) +>this[_symbol].bind : Symbol(CallableFunction.bind, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >this : Symbol(MyClass, Decl(lateBoundMethodNameAssigmentJS.js, 0, 31)) >_symbol : Symbol(_symbol, Decl(lateBoundMethodNameAssigmentJS.js, 0, 5)) +>bind : Symbol(CallableFunction.bind, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >this : Symbol(MyClass, Decl(lateBoundMethodNameAssigmentJS.js, 0, 31)) } diff --git a/tests/baselines/reference/lateBoundMethodNameAssigmentJS.types b/tests/baselines/reference/lateBoundMethodNameAssigmentJS.types index 5b27e8e4813e9..59fd7fecaccec 100644 --- a/tests/baselines/reference/lateBoundMethodNameAssigmentJS.types +++ b/tests/baselines/reference/lateBoundMethodNameAssigmentJS.types @@ -17,28 +17,33 @@ export class MyClass { constructor() { this[_symbol] = this[_symbol].bind(this); ->this[_symbol] = this[_symbol].bind(this) : error ->this[_symbol] : error +>this[_symbol] = this[_symbol].bind(this) : () => Promise +> : ^^^^^^^^^^^^^^^^^^^ +>this[_symbol] : () => Promise +> : ^^^^^^^^^^^^^^^^^^^ >this : this > : ^^^^ >_symbol : unique symbol > : ^^^^^^^^^^^^^ ->this[_symbol].bind(this) : error ->this[_symbol].bind : error ->this[_symbol] : any -> : ^^^ +>this[_symbol].bind(this) : () => Promise +> : ^^^^^^^^^^^^^^^^^^^ +>this[_symbol].bind : { (this: T, thisArg: ThisParameterType): OmitThisParameter; (this: (this: T, ...args: [...A, ...B]) => R, thisArg: T, ...args: A): (...args: B) => R; } +> : ^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^ ^^^ +>this[_symbol] : () => Promise +> : ^^^^^^^^^^^^^^^^^^^ >this : this > : ^^^^ >_symbol : unique symbol > : ^^^^^^^^^^^^^ ->bind : any -> : ^^^ +>bind : { (this: T, thisArg: ThisParameterType): OmitThisParameter; (this: (this: T, ...args: [...A, ...B]) => R, thisArg: T, ...args: A): (...args: B) => R; } +> : ^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^ ^^^ >this : this > : ^^^^ } async [_symbol]() { } ->[_symbol] : error +>[_symbol] : () => Promise +> : ^^^^^^^^^^^^^^^^^^^ >_symbol : unique symbol > : ^^^^^^^^^^^^^ } diff --git a/tests/cases/compiler/lateBoundAssignmentCandidateJS1.ts b/tests/cases/compiler/lateBoundAssignmentCandidateJS1.ts new file mode 100644 index 0000000000000..be2747421ff75 --- /dev/null +++ b/tests/cases/compiler/lateBoundAssignmentCandidateJS1.ts @@ -0,0 +1,31 @@ +// @strict: true +// @target: esnext +// @lib: esnext +// @declaration: true +// @outDir: dist +// @checkJs: true +// @allowJs: true + +// @filename: index.js + +// https://github.com/microsoft/TypeScript/issues/60590 + +export const kBar = Symbol("bar"); + +export class foo0 { + /** + * @protected + * @type {null | string} + */ + [kBar] = null; + + get bar() { + return this[kBar]; + } + /** + * @type {string} + */ + set bar(value) { + this[kBar] = value; + } +} diff --git a/tests/cases/compiler/lateBoundAssignmentCandidateJS2.ts b/tests/cases/compiler/lateBoundAssignmentCandidateJS2.ts new file mode 100644 index 0000000000000..079dbbc40b983 --- /dev/null +++ b/tests/cases/compiler/lateBoundAssignmentCandidateJS2.ts @@ -0,0 +1,23 @@ +// @strict: true +// @target: esnext +// @lib: esnext +// @declaration: true +// @outDir: dist +// @checkJs: true +// @allowJs: true + +// @filename: index.js + +const prop = 'prop'; + +export class foo1 { + constructor() { + this[prop] = 'bar' + } + + /** + * @protected + * @type {string} + */ + [prop] = 'baz'; +} diff --git a/tests/cases/compiler/lateBoundAssignmentCandidateJS3.ts b/tests/cases/compiler/lateBoundAssignmentCandidateJS3.ts new file mode 100644 index 0000000000000..598cff13fb1f8 --- /dev/null +++ b/tests/cases/compiler/lateBoundAssignmentCandidateJS3.ts @@ -0,0 +1,23 @@ +// @strict: true +// @target: esnext +// @lib: esnext +// @declaration: true +// @outDir: dist +// @checkJs: true +// @allowJs: true + +// @filename: index.js + +const prop = 'prop'; + +export class foo2 { + constructor() { + this[prop] = 12; + } + + /** + * @protected + * @type {string} + */ + prop = 'baz'; +} From e3c947f6c82fc40f8df309c64f28b0c70c6e0174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 26 Dec 2024 12:34:39 +0100 Subject: [PATCH 2/3] Just dont reassign valueDeclaration --- src/compiler/checker.ts | 9 +++------ .../reference/lateBoundMethodNameAssigmentJS.js | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 583854149f886..e581d6f2d55b1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13230,7 +13230,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param lateSymbols The late-bound symbols of the parent. * @param decl The member to bind. */ - function lateBindMember(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: Map<__String, TransientSymbol>, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration, isFromAssignmentDeclarationMember = false) { + function lateBindMember(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: Map<__String, TransientSymbol>, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration) { Debug.assert(!!decl.symbol, "The member is expected to have a symbol."); const links = getNodeLinks(decl); if (!links.resolvedSymbol) { @@ -13245,13 +13245,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Get or add a late-bound symbol for the member. This allows us to merge late-bound accessor declarations. let lateSymbol = lateSymbols.get(memberName); - if (isFromAssignmentDeclarationMember && lateSymbol) { - return links.resolvedSymbol = lateSymbol; - } if (!lateSymbol) lateSymbols.set(memberName, lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late)); // Report an error if there's a symbol declaration with the same name and conflicting flags. - const earlySymbol = earlySymbols?.get(memberName); + const earlySymbol = earlySymbols && earlySymbols.get(memberName); // Duplicate property declarations of classes are checked in checkClassForDuplicateDeclarations. if (!(parent.flags & SymbolFlags.Class) && lateSymbol.flags & getExcludedSymbolFlags(symbolFlags)) { // If we have an existing early-bound member, combine its declarations so that we can @@ -13343,7 +13340,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { || assignmentKind === AssignmentDeclarationKind.Prototype; // A straight `Prototype` assignment probably can never have a computed name if (isStatic === !isInstanceMember) { if (hasLateBindableName(member)) { - lateBindMember(symbol, earlySymbols, lateSymbols, member, /*isFromAssignmentDeclarationMember*/ true); + lateBindMember(symbol, earlySymbols, lateSymbols, member); } } } diff --git a/tests/baselines/reference/lateBoundMethodNameAssigmentJS.js b/tests/baselines/reference/lateBoundMethodNameAssigmentJS.js index 8124f724c81ee..fa537a6cb9b75 100644 --- a/tests/baselines/reference/lateBoundMethodNameAssigmentJS.js +++ b/tests/baselines/reference/lateBoundMethodNameAssigmentJS.js @@ -14,7 +14,7 @@ export class MyClass { //// [lateBoundMethodNameAssigmentJS.d.ts] export class MyClass { - [_symbol](): Promise; + [_symbol]: () => Promise; } declare const _symbol: unique symbol; export {}; From 1b675ca85b421c0a8accd8ec3c519c45ecf47a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 7 Jan 2025 11:42:06 +0100 Subject: [PATCH 3/3] improve fix --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e581d6f2d55b1..94afa20680322 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13197,8 +13197,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (!member.symbol.isReplaceableByMethod) { symbol.declarations.push(member); } - if (symbolFlags & SymbolFlags.Value && !symbol.valueDeclaration) { - symbol.valueDeclaration = member; + if (symbolFlags & SymbolFlags.Value) { + setValueDeclaration(symbol, member); } }