Skip to content

fix(37791): Using object destructuring with ECMAScript's private field as computed property name leads to runtime error #38135

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

Merged
merged 1 commit into from
Jan 4, 2021
Merged
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/transformers/classFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,6 @@ namespace ts {
return visitPropertyDeclaration(node as PropertyDeclaration);
case SyntaxKind.VariableStatement:
return visitVariableStatement(node as VariableStatement);
case SyntaxKind.ComputedPropertyName:
return visitComputedPropertyName(node as ComputedPropertyName);
case SyntaxKind.PropertyAccessExpression:
return visitPropertyAccessExpression(node as PropertyAccessExpression);
case SyntaxKind.PrefixUnaryExpression:
Expand Down Expand Up @@ -184,7 +182,7 @@ namespace ts {
let node = visitEachChild(name, visitor, context);
if (some(pendingExpressions)) {
const expressions = pendingExpressions;
expressions.push(name.expression);
expressions.push(node.expression);
pendingExpressions = [];
node = factory.updateComputedPropertyName(
node,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//// [privateNameComputedPropertyName1.ts]
class A {
#a = 'a';
#b: string;

readonly #c = 'c';
readonly #d: string;

#e = '';

constructor() {
this.#b = 'b';
this.#d = 'd';
}

test() {
const data: Record<string, string> = { a: 'a', b: 'b', c: 'c', d: 'd', e: 'e' };
const {
[this.#a]: a,
[this.#b]: b,
[this.#c]: c,
[this.#d]: d,
[this.#e = 'e']: e,
} = data;
console.log(a, b, c, d, e);

const a1 = data[this.#a];
const b1 = data[this.#b];
const c1 = data[this.#c];
const d1 = data[this.#d];
const e1 = data[this.#e];
console.log(a1, b1, c1, d1);
}
}

new A().test();



//// [privateNameComputedPropertyName1.js]
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to set private field on non-instance");
}
privateMap.set(receiver, value);
return value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return privateMap.get(receiver);
};
var _a, _b, _c, _d, _e;
class A {
constructor() {
_a.set(this, 'a');
_b.set(this, void 0);
_c.set(this, 'c');
_d.set(this, void 0);
_e.set(this, '');
__classPrivateFieldSet(this, _b, 'b');
__classPrivateFieldSet(this, _d, 'd');
}
test() {
const data = { a: 'a', b: 'b', c: 'c', d: 'd', e: 'e' };
const { [__classPrivateFieldGet(this, _a)]: a, [__classPrivateFieldGet(this, _b)]: b, [__classPrivateFieldGet(this, _c)]: c, [__classPrivateFieldGet(this, _d)]: d, [__classPrivateFieldSet(this, _e, 'e')]: e, } = data;
console.log(a, b, c, d, e);
const a1 = data[__classPrivateFieldGet(this, _a)];
const b1 = data[__classPrivateFieldGet(this, _b)];
const c1 = data[__classPrivateFieldGet(this, _c)];
const d1 = data[__classPrivateFieldGet(this, _d)];
const e1 = data[__classPrivateFieldGet(this, _e)];
console.log(a1, b1, c1, d1);
}
}
_a = new WeakMap(), _b = new WeakMap(), _c = new WeakMap(), _d = new WeakMap(), _e = new WeakMap();
new A().test();
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
=== tests/cases/conformance/classes/members/privateNames/privateNameComputedPropertyName1.ts ===
class A {
>A : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))

#a = 'a';
>#a : Symbol(A.#a, Decl(privateNameComputedPropertyName1.ts, 0, 9))

#b: string;
>#b : Symbol(A.#b, Decl(privateNameComputedPropertyName1.ts, 1, 13))

readonly #c = 'c';
>#c : Symbol(A.#c, Decl(privateNameComputedPropertyName1.ts, 2, 15))

readonly #d: string;
>#d : Symbol(A.#d, Decl(privateNameComputedPropertyName1.ts, 4, 22))

#e = '';
>#e : Symbol(A.#e, Decl(privateNameComputedPropertyName1.ts, 5, 24))

constructor() {
this.#b = 'b';
>this.#b : Symbol(A.#b, Decl(privateNameComputedPropertyName1.ts, 1, 13))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))

this.#d = 'd';
>this.#d : Symbol(A.#d, Decl(privateNameComputedPropertyName1.ts, 4, 22))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))
}

test() {
>test : Symbol(A.test, Decl(privateNameComputedPropertyName1.ts, 12, 5))

const data: Record<string, string> = { a: 'a', b: 'b', c: 'c', d: 'd', e: 'e' };
>data : Symbol(data, Decl(privateNameComputedPropertyName1.ts, 15, 13))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>a : Symbol(a, Decl(privateNameComputedPropertyName1.ts, 15, 46))
>b : Symbol(b, Decl(privateNameComputedPropertyName1.ts, 15, 54))
>c : Symbol(c, Decl(privateNameComputedPropertyName1.ts, 15, 62))
>d : Symbol(d, Decl(privateNameComputedPropertyName1.ts, 15, 70))
>e : Symbol(e, Decl(privateNameComputedPropertyName1.ts, 15, 78))

const {
[this.#a]: a,
>this.#a : Symbol(A.#a, Decl(privateNameComputedPropertyName1.ts, 0, 9))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))
>a : Symbol(a, Decl(privateNameComputedPropertyName1.ts, 16, 15))

[this.#b]: b,
>this.#b : Symbol(A.#b, Decl(privateNameComputedPropertyName1.ts, 1, 13))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))
>b : Symbol(b, Decl(privateNameComputedPropertyName1.ts, 17, 25))

[this.#c]: c,
>this.#c : Symbol(A.#c, Decl(privateNameComputedPropertyName1.ts, 2, 15))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))
>c : Symbol(c, Decl(privateNameComputedPropertyName1.ts, 18, 25))

[this.#d]: d,
>this.#d : Symbol(A.#d, Decl(privateNameComputedPropertyName1.ts, 4, 22))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))
>d : Symbol(d, Decl(privateNameComputedPropertyName1.ts, 19, 25))

[this.#e = 'e']: e,
>this.#e : Symbol(A.#e, Decl(privateNameComputedPropertyName1.ts, 5, 24))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))
>e : Symbol(e, Decl(privateNameComputedPropertyName1.ts, 20, 25))

} = data;
>data : Symbol(data, Decl(privateNameComputedPropertyName1.ts, 15, 13))

console.log(a, b, c, d, e);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>a : Symbol(a, Decl(privateNameComputedPropertyName1.ts, 16, 15))
>b : Symbol(b, Decl(privateNameComputedPropertyName1.ts, 17, 25))
>c : Symbol(c, Decl(privateNameComputedPropertyName1.ts, 18, 25))
>d : Symbol(d, Decl(privateNameComputedPropertyName1.ts, 19, 25))
>e : Symbol(e, Decl(privateNameComputedPropertyName1.ts, 20, 25))

const a1 = data[this.#a];
>a1 : Symbol(a1, Decl(privateNameComputedPropertyName1.ts, 25, 13))
>data : Symbol(data, Decl(privateNameComputedPropertyName1.ts, 15, 13))
>this.#a : Symbol(A.#a, Decl(privateNameComputedPropertyName1.ts, 0, 9))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))

const b1 = data[this.#b];
>b1 : Symbol(b1, Decl(privateNameComputedPropertyName1.ts, 26, 13))
>data : Symbol(data, Decl(privateNameComputedPropertyName1.ts, 15, 13))
>this.#b : Symbol(A.#b, Decl(privateNameComputedPropertyName1.ts, 1, 13))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))

const c1 = data[this.#c];
>c1 : Symbol(c1, Decl(privateNameComputedPropertyName1.ts, 27, 13))
>data : Symbol(data, Decl(privateNameComputedPropertyName1.ts, 15, 13))
>this.#c : Symbol(A.#c, Decl(privateNameComputedPropertyName1.ts, 2, 15))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))

const d1 = data[this.#d];
>d1 : Symbol(d1, Decl(privateNameComputedPropertyName1.ts, 28, 13))
>data : Symbol(data, Decl(privateNameComputedPropertyName1.ts, 15, 13))
>this.#d : Symbol(A.#d, Decl(privateNameComputedPropertyName1.ts, 4, 22))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))

const e1 = data[this.#e];
>e1 : Symbol(e1, Decl(privateNameComputedPropertyName1.ts, 29, 13))
>data : Symbol(data, Decl(privateNameComputedPropertyName1.ts, 15, 13))
>this.#e : Symbol(A.#e, Decl(privateNameComputedPropertyName1.ts, 5, 24))
>this : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))

console.log(a1, b1, c1, d1);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>a1 : Symbol(a1, Decl(privateNameComputedPropertyName1.ts, 25, 13))
>b1 : Symbol(b1, Decl(privateNameComputedPropertyName1.ts, 26, 13))
>c1 : Symbol(c1, Decl(privateNameComputedPropertyName1.ts, 27, 13))
>d1 : Symbol(d1, Decl(privateNameComputedPropertyName1.ts, 28, 13))
}
}

new A().test();
>new A().test : Symbol(A.test, Decl(privateNameComputedPropertyName1.ts, 12, 5))
>A : Symbol(A, Decl(privateNameComputedPropertyName1.ts, 0, 0))
>test : Symbol(A.test, Decl(privateNameComputedPropertyName1.ts, 12, 5))


Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
=== tests/cases/conformance/classes/members/privateNames/privateNameComputedPropertyName1.ts ===
class A {
>A : A

#a = 'a';
>#a : string
>'a' : "a"

#b: string;
>#b : string

readonly #c = 'c';
>#c : "c"
>'c' : "c"

readonly #d: string;
>#d : string

#e = '';
>#e : string
>'' : ""

constructor() {
this.#b = 'b';
>this.#b = 'b' : "b"
>this.#b : string
>this : this
>'b' : "b"

this.#d = 'd';
>this.#d = 'd' : "d"
>this.#d : string
>this : this
>'d' : "d"
}

test() {
>test : () => void

const data: Record<string, string> = { a: 'a', b: 'b', c: 'c', d: 'd', e: 'e' };
>data : Record<string, string>
>{ a: 'a', b: 'b', c: 'c', d: 'd', e: 'e' } : { a: string; b: string; c: string; d: string; e: string; }
>a : string
>'a' : "a"
>b : string
>'b' : "b"
>c : string
>'c' : "c"
>d : string
>'d' : "d"
>e : string
>'e' : "e"

const {
[this.#a]: a,
>this.#a : string
>this : this
>a : string

[this.#b]: b,
>this.#b : string
>this : this
>b : string

[this.#c]: c,
>this.#c : "c"
>this : this
>c : string

[this.#d]: d,
>this.#d : string
>this : this
>d : string

[this.#e = 'e']: e,
>this.#e = 'e' : "e"
>this.#e : string
>this : this
>'e' : "e"
>e : string

} = data;
>data : Record<string, string>

console.log(a, b, c, d, e);
>console.log(a, b, c, d, e) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>a : string
>b : string
>c : string
>d : string
>e : string

const a1 = data[this.#a];
>a1 : string
>data[this.#a] : string
>data : Record<string, string>
>this.#a : string
>this : this

const b1 = data[this.#b];
>b1 : string
>data[this.#b] : string
>data : Record<string, string>
>this.#b : string
>this : this

const c1 = data[this.#c];
>c1 : string
>data[this.#c] : string
>data : Record<string, string>
>this.#c : "c"
>this : this

const d1 = data[this.#d];
>d1 : string
>data[this.#d] : string
>data : Record<string, string>
>this.#d : string
>this : this

const e1 = data[this.#e];
>e1 : string
>data[this.#e] : string
>data : Record<string, string>
>this.#e : string
>this : this

console.log(a1, b1, c1, d1);
>console.log(a1, b1, c1, d1) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>a1 : string
>b1 : string
>c1 : string
>d1 : string
}
}

new A().test();
>new A().test() : void
>new A().test : () => void
>new A() : A
>A : typeof A
>test : () => void


Loading