From 0d4414d10d7d26935568948a856f5f7682fc89df Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 25 Mar 2024 11:20:08 -0700 Subject: [PATCH] Allow `this` in constructor parameter defaults when legal (#57682) --- src/compiler/checker.ts | 6 --- src/compiler/diagnosticMessages.json | 4 -- ...torDefaultValuesReferencingThis.errors.txt | 24 ++++++------ ...constructorDefaultValuesReferencingThis.js | 34 ++++++++++++++++- ...ructorDefaultValuesReferencingThis.symbols | 37 ++++++++++++++----- ...structorDefaultValuesReferencingThis.types | 21 +++++++++++ .../thisInConstructorParameter1.errors.txt | 10 ----- .../thisInConstructorParameter2.errors.txt | 20 ---------- ...ypeOfThisInConstructorParamList.errors.txt | 12 ------ ...constructorDefaultValuesReferencingThis.ts | 9 ++++- 10 files changed, 103 insertions(+), 74 deletions(-) delete mode 100644 tests/baselines/reference/thisInConstructorParameter1.errors.txt delete mode 100644 tests/baselines/reference/thisInConstructorParameter2.errors.txt delete mode 100644 tests/baselines/reference/typeOfThisInConstructorParamList.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ad13bd597db..1bfb1831fce 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29815,12 +29815,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(node, Diagnostics.this_cannot_be_referenced_in_current_location); // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks break; - case SyntaxKind.Constructor: - if (isInConstructorArgumentInitializer(node, container)) { - error(node, Diagnostics.this_cannot_be_referenced_in_constructor_arguments); - // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks - } - break; } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index dfbb41b3d40..97fe428189d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1836,10 +1836,6 @@ "category": "Error", "code": 2332 }, - "'this' cannot be referenced in constructor arguments.": { - "category": "Error", - "code": 2333 - }, "'this' cannot be referenced in a static property initializer.": { "category": "Error", "code": 2334 diff --git a/tests/baselines/reference/constructorDefaultValuesReferencingThis.errors.txt b/tests/baselines/reference/constructorDefaultValuesReferencingThis.errors.txt index 6ece6c8ff40..522a3235465 100644 --- a/tests/baselines/reference/constructorDefaultValuesReferencingThis.errors.txt +++ b/tests/baselines/reference/constructorDefaultValuesReferencingThis.errors.txt @@ -1,23 +1,25 @@ -constructorDefaultValuesReferencingThis.ts(2,21): error TS2333: 'this' cannot be referenced in constructor arguments. -constructorDefaultValuesReferencingThis.ts(6,21): error TS2333: 'this' cannot be referenced in constructor arguments. -constructorDefaultValuesReferencingThis.ts(10,28): error TS2333: 'this' cannot be referenced in constructor arguments. +constructorDefaultValuesReferencingThis.ts(15,21): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class. -==== constructorDefaultValuesReferencingThis.ts (3 errors) ==== +==== constructorDefaultValuesReferencingThis.ts (1 errors) ==== class C { + public baseProp = 1; constructor(x = this) { } - ~~~~ -!!! error TS2333: 'this' cannot be referenced in constructor arguments. } class D { constructor(x = this) { } - ~~~~ -!!! error TS2333: 'this' cannot be referenced in constructor arguments. } class E { constructor(public x = this) { } - ~~~~ -!!! error TS2333: 'this' cannot be referenced in constructor arguments. - } \ No newline at end of file + } + + class F extends C { + constructor(y = this.baseProp) { + ~~~~ +!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class. + super(); + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/constructorDefaultValuesReferencingThis.js b/tests/baselines/reference/constructorDefaultValuesReferencingThis.js index ff12c465946..87394c3841f 100644 --- a/tests/baselines/reference/constructorDefaultValuesReferencingThis.js +++ b/tests/baselines/reference/constructorDefaultValuesReferencingThis.js @@ -2,6 +2,7 @@ //// [constructorDefaultValuesReferencingThis.ts] class C { + public baseProp = 1; constructor(x = this) { } } @@ -11,12 +12,35 @@ class D { class E { constructor(public x = this) { } -} +} + +class F extends C { + constructor(y = this.baseProp) { + super(); + } +} + //// [constructorDefaultValuesReferencingThis.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var C = /** @class */ (function () { function C(x) { if (x === void 0) { x = this; } + this.baseProp = 1; } return C; }()); @@ -33,3 +57,11 @@ var E = /** @class */ (function () { } return E; }()); +var F = /** @class */ (function (_super) { + __extends(F, _super); + function F(y) { + if (y === void 0) { y = _this.baseProp; } + return _super.call(this) || this; + } + return F; +}(C)); diff --git a/tests/baselines/reference/constructorDefaultValuesReferencingThis.symbols b/tests/baselines/reference/constructorDefaultValuesReferencingThis.symbols index 6f734e10d45..002bbecc0ab 100644 --- a/tests/baselines/reference/constructorDefaultValuesReferencingThis.symbols +++ b/tests/baselines/reference/constructorDefaultValuesReferencingThis.symbols @@ -4,25 +4,44 @@ class C { >C : Symbol(C, Decl(constructorDefaultValuesReferencingThis.ts, 0, 0)) + public baseProp = 1; +>baseProp : Symbol(C.baseProp, Decl(constructorDefaultValuesReferencingThis.ts, 0, 9)) + constructor(x = this) { } ->x : Symbol(x, Decl(constructorDefaultValuesReferencingThis.ts, 1, 16)) +>x : Symbol(x, Decl(constructorDefaultValuesReferencingThis.ts, 2, 16)) >this : Symbol(C, Decl(constructorDefaultValuesReferencingThis.ts, 0, 0)) } class D { ->D : Symbol(D, Decl(constructorDefaultValuesReferencingThis.ts, 2, 1)) ->T : Symbol(T, Decl(constructorDefaultValuesReferencingThis.ts, 4, 8)) +>D : Symbol(D, Decl(constructorDefaultValuesReferencingThis.ts, 3, 1)) +>T : Symbol(T, Decl(constructorDefaultValuesReferencingThis.ts, 5, 8)) constructor(x = this) { } ->x : Symbol(x, Decl(constructorDefaultValuesReferencingThis.ts, 5, 16)) ->this : Symbol(D, Decl(constructorDefaultValuesReferencingThis.ts, 2, 1)) +>x : Symbol(x, Decl(constructorDefaultValuesReferencingThis.ts, 6, 16)) +>this : Symbol(D, Decl(constructorDefaultValuesReferencingThis.ts, 3, 1)) } class E { ->E : Symbol(E, Decl(constructorDefaultValuesReferencingThis.ts, 6, 1)) ->T : Symbol(T, Decl(constructorDefaultValuesReferencingThis.ts, 8, 8)) +>E : Symbol(E, Decl(constructorDefaultValuesReferencingThis.ts, 7, 1)) +>T : Symbol(T, Decl(constructorDefaultValuesReferencingThis.ts, 9, 8)) constructor(public x = this) { } ->x : Symbol(E.x, Decl(constructorDefaultValuesReferencingThis.ts, 9, 16)) ->this : Symbol(E, Decl(constructorDefaultValuesReferencingThis.ts, 6, 1)) +>x : Symbol(E.x, Decl(constructorDefaultValuesReferencingThis.ts, 10, 16)) +>this : Symbol(E, Decl(constructorDefaultValuesReferencingThis.ts, 7, 1)) } + +class F extends C { +>F : Symbol(F, Decl(constructorDefaultValuesReferencingThis.ts, 11, 1)) +>C : Symbol(C, Decl(constructorDefaultValuesReferencingThis.ts, 0, 0)) + + constructor(y = this.baseProp) { +>y : Symbol(y, Decl(constructorDefaultValuesReferencingThis.ts, 14, 16)) +>this.baseProp : Symbol(C.baseProp, Decl(constructorDefaultValuesReferencingThis.ts, 0, 9)) +>this : Symbol(F, Decl(constructorDefaultValuesReferencingThis.ts, 11, 1)) +>baseProp : Symbol(C.baseProp, Decl(constructorDefaultValuesReferencingThis.ts, 0, 9)) + + super(); +>super : Symbol(C, Decl(constructorDefaultValuesReferencingThis.ts, 0, 0)) + } +} + diff --git a/tests/baselines/reference/constructorDefaultValuesReferencingThis.types b/tests/baselines/reference/constructorDefaultValuesReferencingThis.types index acbd8df29a6..3a9744849a0 100644 --- a/tests/baselines/reference/constructorDefaultValuesReferencingThis.types +++ b/tests/baselines/reference/constructorDefaultValuesReferencingThis.types @@ -4,6 +4,10 @@ class C { >C : C + public baseProp = 1; +>baseProp : number +>1 : 1 + constructor(x = this) { } >x : this >this : this @@ -24,3 +28,20 @@ class E { >x : this >this : this } + +class F extends C { +>F : F +>C : C + + constructor(y = this.baseProp) { +>y : number +>this.baseProp : number +>this : this +>baseProp : number + + super(); +>super() : void +>super : typeof C + } +} + diff --git a/tests/baselines/reference/thisInConstructorParameter1.errors.txt b/tests/baselines/reference/thisInConstructorParameter1.errors.txt deleted file mode 100644 index 8c38aa05ed7..00000000000 --- a/tests/baselines/reference/thisInConstructorParameter1.errors.txt +++ /dev/null @@ -1,10 +0,0 @@ -thisInConstructorParameter1.ts(3,21): error TS2333: 'this' cannot be referenced in constructor arguments. - - -==== thisInConstructorParameter1.ts (1 errors) ==== - class Foo { - public y; - constructor(x = this.y) { } - ~~~~ -!!! error TS2333: 'this' cannot be referenced in constructor arguments. - } \ No newline at end of file diff --git a/tests/baselines/reference/thisInConstructorParameter2.errors.txt b/tests/baselines/reference/thisInConstructorParameter2.errors.txt deleted file mode 100644 index 044bc39cd54..00000000000 --- a/tests/baselines/reference/thisInConstructorParameter2.errors.txt +++ /dev/null @@ -1,20 +0,0 @@ -thisInConstructorParameter2.ts(5,28): error TS2333: 'this' cannot be referenced in constructor arguments. -thisInConstructorParameter2.ts(5,39): error TS2333: 'this' cannot be referenced in constructor arguments. - - -==== thisInConstructorParameter2.ts (2 errors) ==== - class P { - x = this; - static y = this; - - constructor(public z = this, zz = this, zzz = (p = this) => this) { - ~~~~ -!!! error TS2333: 'this' cannot be referenced in constructor arguments. - ~~~~ -!!! error TS2333: 'this' cannot be referenced in constructor arguments. - zzz = (p = this) => this; - } - - foo(zz = this) { zz.x; } - static bar(zz = this) { zz.y; } - } \ No newline at end of file diff --git a/tests/baselines/reference/typeOfThisInConstructorParamList.errors.txt b/tests/baselines/reference/typeOfThisInConstructorParamList.errors.txt deleted file mode 100644 index 7f3e0fbe542..00000000000 --- a/tests/baselines/reference/typeOfThisInConstructorParamList.errors.txt +++ /dev/null @@ -1,12 +0,0 @@ -typeOfThisInConstructorParamList.ts(4,21): error TS2333: 'this' cannot be referenced in constructor arguments. - - -==== typeOfThisInConstructorParamList.ts (1 errors) ==== - //type of 'this' in constructor param list is the class instance type (error) - class ErrClass { - // Should be an error - constructor(f = this) { } - ~~~~ -!!! error TS2333: 'this' cannot be referenced in constructor arguments. - } - \ No newline at end of file diff --git a/tests/cases/conformance/classes/constructorDeclarations/constructorParameters/constructorDefaultValuesReferencingThis.ts b/tests/cases/conformance/classes/constructorDeclarations/constructorParameters/constructorDefaultValuesReferencingThis.ts index 9209dcd7c52..6c02c67af90 100644 --- a/tests/cases/conformance/classes/constructorDeclarations/constructorParameters/constructorDefaultValuesReferencingThis.ts +++ b/tests/cases/conformance/classes/constructorDeclarations/constructorParameters/constructorDefaultValuesReferencingThis.ts @@ -1,4 +1,5 @@ class C { + public baseProp = 1; constructor(x = this) { } } @@ -8,4 +9,10 @@ class D { class E { constructor(public x = this) { } -} \ No newline at end of file +} + +class F extends C { + constructor(y = this.baseProp) { + super(); + } +}