Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop reassigning .valueDeclaration to avoid replacing earlier declarations with late ones #60857

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13198,9 +13198,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
symbol.declarations.push(member);
}
if (symbolFlags & SymbolFlags.Value) {
if (!symbol.valueDeclaration || symbol.valueDeclaration.kind !== member.kind) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the original logic trying to preserve the somewhat-sketchy logic in the binder around which type of declaration "wins" out?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sure looks like it, but there's a separate utility function for that now: setValueDeclaration, which is more complicated*. Specifically, the kind check is only for namespaces there, which wouldn't apply to this property assignments.

I think the better fix to try is

if (symbolFlags & SymbolFlags.Value) {
  setValueDeclaration(symbol, member)
}

In other words, what the binder does in addDeclarationToSymbol.

*It also has a 3rd case for function property assignments in .d.ts files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed out this change. Could you take another look?

symbol.valueDeclaration = member;
}
setValueDeclaration(symbol, member);
}
}

Expand Down
61 changes: 61 additions & 0 deletions tests/baselines/reference/lateBoundAssignmentCandidateJS1.js
Original file line number Diff line number Diff line change
@@ -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;
}
41 changes: 41 additions & 0 deletions tests/baselines/reference/lateBoundAssignmentCandidateJS1.symbols
Original file line number Diff line number Diff line change
@@ -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))
}
}

64 changes: 64 additions & 0 deletions tests/baselines/reference/lateBoundAssignmentCandidateJS1.types
Original file line number Diff line number Diff line change
@@ -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
> : ^^^^^^^^^^^^^
}
}

40 changes: 40 additions & 0 deletions tests/baselines/reference/lateBoundAssignmentCandidateJS2.js
Original file line number Diff line number Diff line change
@@ -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;
}
24 changes: 24 additions & 0 deletions tests/baselines/reference/lateBoundAssignmentCandidateJS2.symbols
Original file line number Diff line number Diff line change
@@ -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))
}

40 changes: 40 additions & 0 deletions tests/baselines/reference/lateBoundAssignmentCandidateJS2.types
Original file line number Diff line number Diff line change
@@ -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"
> : ^^^^^
}

Original file line number Diff line number Diff line change
@@ -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';
}

40 changes: 40 additions & 0 deletions tests/baselines/reference/lateBoundAssignmentCandidateJS3.js
Original file line number Diff line number Diff line change
@@ -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;
}
23 changes: 23 additions & 0 deletions tests/baselines/reference/lateBoundAssignmentCandidateJS3.symbols
Original file line number Diff line number Diff line change
@@ -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))
}

Loading
Loading