Skip to content

Class fields w/esnext+[[Define]]:no shadow error #36405

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 4 commits into from
Jan 29, 2020
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
5 changes: 3 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1822,9 +1822,10 @@ namespace ts {

// Perform extra checks only if error reporting was requested
if (nameNotFoundMessage) {
if (propertyWithInvalidInitializer) {
if (propertyWithInvalidInitializer && !(compilerOptions.target === ScriptTarget.ESNext && compilerOptions.useDefineForClassFields)) {
// We have a match, but the reference occurred within a property initializer and the identifier also binds
// to a local variable in the constructor where the code will be emitted.
// to a local variable in the constructor where the code will be emitted. Note that this is actually allowed
// with ESNext+useDefineForClassFields because the scope semantics are different.
const propertyName = (<PropertyDeclaration>propertyWithInvalidInitializer).name;
error(errorLocation, Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor,
declarationNameToString(propertyName), diagnosticName(nameArg!));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts(28,9): error TS2304: Cannot find name 'z'.


==== tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts (1 errors) ====
// With useDefineForClassFields: true and ESNext target, initializer
// expressions for property declarations are evaluated in the scope of
// the class body and are permitted to reference parameters or local
// variables of the constructor. This is different from classic
// Typescript behaviour, with useDefineForClassFields: false. There,
// initialisers of property declarations are evaluated in the scope of
// the constructor body.

// Note that when class fields are accepted in the ECMAScript
// standard, the target will become that year's ES20xx

var x = 1;
class C {
b = x; // ok
constructor(x: string) {
}
}

var y = 1;
class D {
b = y; // ok
constructor(x: string) {
var y = "";
}
}

class E {
b = z; // not ok
~
!!! error TS2304: Cannot find name 'z'.
constructor(z: string) {
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//// [constructorParameterShadowsOuterScopes2.ts]
// With useDefineForClassFields: true and ESNext target, initializer
// expressions for property declarations are evaluated in the scope of
// the class body and are permitted to reference parameters or local
// variables of the constructor. This is different from classic
// Typescript behaviour, with useDefineForClassFields: false. There,
// initialisers of property declarations are evaluated in the scope of
// the constructor body.

// Note that when class fields are accepted in the ECMAScript
// standard, the target will become that year's ES20xx

var x = 1;
class C {
b = x; // ok
constructor(x: string) {
}
}

var y = 1;
class D {
b = y; // ok
constructor(x: string) {
var y = "";
}
}

class E {
b = z; // not ok
constructor(z: string) {
}
}


//// [constructorParameterShadowsOuterScopes2.js]
// With useDefineForClassFields: true and ESNext target, initializer
// expressions for property declarations are evaluated in the scope of
// the class body and are permitted to reference parameters or local
// variables of the constructor. This is different from classic
// Typescript behaviour, with useDefineForClassFields: false. There,
// initialisers of property declarations are evaluated in the scope of
// the constructor body.
// Note that when class fields are accepted in the ECMAScript
// standard, the target will become that year's ES20xx
var x = 1;
class C {
b = x; // ok
constructor(x) {
}
}
var y = 1;
class D {
b = y; // ok
constructor(x) {
var y = "";
}
}
class E {
b = z; // not ok
constructor(z) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
=== tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts ===
// With useDefineForClassFields: true and ESNext target, initializer
// expressions for property declarations are evaluated in the scope of
// the class body and are permitted to reference parameters or local
// variables of the constructor. This is different from classic
// Typescript behaviour, with useDefineForClassFields: false. There,
// initialisers of property declarations are evaluated in the scope of
// the constructor body.

// Note that when class fields are accepted in the ECMAScript
// standard, the target will become that year's ES20xx

var x = 1;
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 11, 3))

class C {
>C : Symbol(C, Decl(constructorParameterShadowsOuterScopes2.ts, 11, 10))

b = x; // ok
>b : Symbol(C.b, Decl(constructorParameterShadowsOuterScopes2.ts, 12, 9))
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 11, 3))

constructor(x: string) {
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 14, 16))
}
}

var y = 1;
>y : Symbol(y, Decl(constructorParameterShadowsOuterScopes2.ts, 18, 3))

class D {
>D : Symbol(D, Decl(constructorParameterShadowsOuterScopes2.ts, 18, 10))

b = y; // ok
>b : Symbol(D.b, Decl(constructorParameterShadowsOuterScopes2.ts, 19, 9))
>y : Symbol(y, Decl(constructorParameterShadowsOuterScopes2.ts, 18, 3))

constructor(x: string) {
>x : Symbol(x, Decl(constructorParameterShadowsOuterScopes2.ts, 21, 16))

var y = "";
>y : Symbol(y, Decl(constructorParameterShadowsOuterScopes2.ts, 22, 11))
}
}

class E {
>E : Symbol(E, Decl(constructorParameterShadowsOuterScopes2.ts, 24, 1))

b = z; // not ok
>b : Symbol(E.b, Decl(constructorParameterShadowsOuterScopes2.ts, 26, 9))

constructor(z: string) {
>z : Symbol(z, Decl(constructorParameterShadowsOuterScopes2.ts, 28, 16))
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
=== tests/cases/conformance/classes/propertyMemberDeclarations/constructorParameterShadowsOuterScopes2.ts ===
// With useDefineForClassFields: true and ESNext target, initializer
// expressions for property declarations are evaluated in the scope of
// the class body and are permitted to reference parameters or local
// variables of the constructor. This is different from classic
// Typescript behaviour, with useDefineForClassFields: false. There,
// initialisers of property declarations are evaluated in the scope of
// the constructor body.

// Note that when class fields are accepted in the ECMAScript
// standard, the target will become that year's ES20xx

var x = 1;
>x : number
>1 : 1

class C {
>C : C

b = x; // ok
>b : number
>x : number

constructor(x: string) {
>x : string
}
}

var y = 1;
>y : number
>1 : 1

class D {
>D : D

b = y; // ok
>b : number
>y : number

constructor(x: string) {
>x : string

var y = "";
>y : string
>"" : ""
}
}

class E {
>E : E

b = z; // not ok
>b : any
>z : any

constructor(z: string) {
>z : string
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// @target: esnext
// @useDefineForClassFields: true


// With useDefineForClassFields: true and ESNext target, initializer
// expressions for property declarations are evaluated in the scope of
// the class body and are permitted to reference parameters or local
// variables of the constructor. This is different from classic
// Typescript behaviour, with useDefineForClassFields: false. There,
// initialisers of property declarations are evaluated in the scope of
// the constructor body.

// Note that when class fields are accepted in the ECMAScript
// standard, the target will become that year's ES20xx

var x = 1;
class C {
b = x; // ok
constructor(x: string) {
}
}

var y = 1;
class D {
b = y; // ok
constructor(x: string) {
var y = "";
}
}

class E {
b = z; // not ok
constructor(z: string) {
}
}