From 43fc19c95857dbcb4d1e24019642a6bf047d44bf Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 24 Jan 2020 14:52:48 -0800 Subject: [PATCH] Emit statements before super (#36417) * Emit statements before super When statements come before super, Typescript's emit is incorrect, whether there is an error or not. This change preserves statements that come before super whether there is an error or not. Here is the case with no errors: ```ts class Test extends Array { p: number constructor() { console.log("p is initialised in the constructor below super()") super() this.p = 1 } } ``` Notice that `p` is manually initialised in the constructor after `super()` instead of at the property declaration. * Update baselines Parameter properties in the error case now move below the super call. This is an improvement because it means the code is more likely to execute correctly. * remove outdated comments --- src/compiler/transformers/utilities.ts | 10 ++- tests/baselines/reference/classUpdateTests.js | 4 +- .../derivedClassParameterProperties.js | 8 +- .../reference/emitCodeBeforeSuperCall.js | 53 +++++++++++++ .../reference/emitCodeBeforeSuperCall.symbols | 51 +++++++++++++ .../reference/emitCodeBeforeSuperCall.types | 60 +++++++++++++++ .../reference/emitCodeBeforeSuperCall2.js | 49 ++++++++++++ .../emitCodeBeforeSuperCall2.symbols | 23 ++++++ .../reference/emitCodeBeforeSuperCall2.types | 24 ++++++ ...emitCodeBeforeSuperCallWithDefineFields.js | 74 +++++++++++++++++++ ...odeBeforeSuperCallWithDefineFields.symbols | 51 +++++++++++++ ...tCodeBeforeSuperCallWithDefineFields.types | 60 +++++++++++++++ .../emitStatementsBeforeSuperCall.js | 44 +++++++++++ .../emitStatementsBeforeSuperCall.symbols | 46 ++++++++++++ .../emitStatementsBeforeSuperCall.types | 55 ++++++++++++++ ...atementsBeforeSuperCallWithDefineFields.js | 65 ++++++++++++++++ ...ntsBeforeSuperCallWithDefineFields.symbols | 46 ++++++++++++ ...mentsBeforeSuperCallWithDefineFields.types | 55 ++++++++++++++ .../reference/privateNameBadSuper.js | 2 +- .../reference/strictModeInConstructor.js | 2 +- .../emitStatementsBeforeSuperCall.ts | 23 ++++++ ...atementsBeforeSuperCallWithDefineFields.ts | 23 ++++++ 22 files changed, 816 insertions(+), 12 deletions(-) create mode 100644 tests/baselines/reference/emitCodeBeforeSuperCall.js create mode 100644 tests/baselines/reference/emitCodeBeforeSuperCall.symbols create mode 100644 tests/baselines/reference/emitCodeBeforeSuperCall.types create mode 100644 tests/baselines/reference/emitCodeBeforeSuperCall2.js create mode 100644 tests/baselines/reference/emitCodeBeforeSuperCall2.symbols create mode 100644 tests/baselines/reference/emitCodeBeforeSuperCall2.types create mode 100644 tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.js create mode 100644 tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.symbols create mode 100644 tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.types create mode 100644 tests/baselines/reference/emitStatementsBeforeSuperCall.js create mode 100644 tests/baselines/reference/emitStatementsBeforeSuperCall.symbols create mode 100644 tests/baselines/reference/emitStatementsBeforeSuperCall.types create mode 100644 tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.js create mode 100644 tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.symbols create mode 100644 tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.types create mode 100644 tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCall.ts create mode 100644 tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCallWithDefineFields.ts diff --git a/src/compiler/transformers/utilities.ts b/src/compiler/transformers/utilities.ts index 3cf912dfb47..a602d6c0486 100644 --- a/src/compiler/transformers/utilities.ts +++ b/src/compiler/transformers/utilities.ts @@ -294,10 +294,12 @@ namespace ts { return index; } - const statement = statements[index]; - if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((statement).expression)) { - result.push(visitNode(statement, visitor, isStatement)); - return index + 1; + const superIndex = findIndex(statements, s => isExpressionStatement(s) && isSuperCall(s.expression), index); + if (superIndex > -1) { + for (let i = index; i <= superIndex; i++) { + result.push(visitNode(statements[i], visitor, isStatement)); + } + return superIndex + 1; } return index; diff --git a/tests/baselines/reference/classUpdateTests.js b/tests/baselines/reference/classUpdateTests.js index 077bd62bfa4..916ac9baa47 100644 --- a/tests/baselines/reference/classUpdateTests.js +++ b/tests/baselines/reference/classUpdateTests.js @@ -214,9 +214,9 @@ var K = /** @class */ (function (_super) { __extends(K, _super); function K(p1) { var _this = this; - _this.p1 = p1; var i = 0; _this = _super.call(this) || this; + _this.p1 = p1; return _this; } return K; @@ -234,9 +234,9 @@ var M = /** @class */ (function (_super) { __extends(M, _super); function M(p1) { var _this = this; - _this.p1 = p1; var i = 0; _this = _super.call(this) || this; + _this.p1 = p1; return _this; } return M; diff --git a/tests/baselines/reference/derivedClassParameterProperties.js b/tests/baselines/reference/derivedClassParameterProperties.js index f13be2bd7f6..a3213b0ebbd 100644 --- a/tests/baselines/reference/derivedClassParameterProperties.js +++ b/tests/baselines/reference/derivedClassParameterProperties.js @@ -128,9 +128,9 @@ var Derived2 = /** @class */ (function (_super) { __extends(Derived2, _super); function Derived2(y) { var _this = this; - _this.y = y; var a = 1; _this = _super.call(this) || this; // error + _this.y = y; return _this; } return Derived2; @@ -149,9 +149,9 @@ var Derived4 = /** @class */ (function (_super) { __extends(Derived4, _super); function Derived4(y) { var _this = this; - _this.a = 1; var b = 2; _this = _super.call(this) || this; // error + _this.a = 1; return _this; } return Derived4; @@ -181,10 +181,10 @@ var Derived7 = /** @class */ (function (_super) { __extends(Derived7, _super); function Derived7(y) { var _this = this; - _this.a = 1; _this.a = 3; _this.b = 3; _this = _super.call(this) || this; // error + _this.a = 1; return _this; } return Derived7; @@ -210,10 +210,10 @@ var Derived9 = /** @class */ (function (_super) { __extends(Derived9, _super); function Derived9(y) { var _this = this; - _this.a = 1; _this.a = 3; _this.b = 3; _this = _super.call(this) || this; // error + _this.a = 1; return _this; } return Derived9; diff --git a/tests/baselines/reference/emitCodeBeforeSuperCall.js b/tests/baselines/reference/emitCodeBeforeSuperCall.js new file mode 100644 index 00000000000..1c5f63e6377 --- /dev/null +++ b/tests/baselines/reference/emitCodeBeforeSuperCall.js @@ -0,0 +1,53 @@ +//// [emitCodeBeforeSuperCall.ts] +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code + +class Base { +} +class Sub extends Base { + // @ts-ignore + constructor(public p: number) { + console.log('hi'); + super(); + } + field = 0; +} + +class Test extends Base { + prop: number; + // @ts-ignore + constructor(public p: number) { + 1; // Any statements here break it + super(); + this.prop = 1; + } +} + + +//// [emitCodeBeforeSuperCall.js] +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code +class Base { +} +class Sub extends Base { + // @ts-ignore + constructor(p) { + console.log('hi'); + super(); + this.p = p; + this.field = 0; + } +} +class Test extends Base { + // @ts-ignore + constructor(p) { + 1; // Any statements here break it + super(); + this.p = p; + this.prop = 1; + } +} diff --git a/tests/baselines/reference/emitCodeBeforeSuperCall.symbols b/tests/baselines/reference/emitCodeBeforeSuperCall.symbols new file mode 100644 index 00000000000..a79857ba65a --- /dev/null +++ b/tests/baselines/reference/emitCodeBeforeSuperCall.symbols @@ -0,0 +1,51 @@ +=== tests/cases/conformance/classes/constructorDeclarations/superCalls/emitCodeBeforeSuperCall.ts === +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code + +class Base { +>Base : Symbol(Base, Decl(emitCodeBeforeSuperCall.ts, 0, 0)) +} +class Sub extends Base { +>Sub : Symbol(Sub, Decl(emitCodeBeforeSuperCall.ts, 6, 1)) +>Base : Symbol(Base, Decl(emitCodeBeforeSuperCall.ts, 0, 0)) + + // @ts-ignore + constructor(public p: number) { +>p : Symbol(Sub.p, Decl(emitCodeBeforeSuperCall.ts, 9, 16)) + + console.log('hi'); +>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, --, --)) + + super(); +>super : Symbol(Base, Decl(emitCodeBeforeSuperCall.ts, 0, 0)) + } + field = 0; +>field : Symbol(Sub.field, Decl(emitCodeBeforeSuperCall.ts, 12, 5)) +} + +class Test extends Base { +>Test : Symbol(Test, Decl(emitCodeBeforeSuperCall.ts, 14, 1)) +>Base : Symbol(Base, Decl(emitCodeBeforeSuperCall.ts, 0, 0)) + + prop: number; +>prop : Symbol(Test.prop, Decl(emitCodeBeforeSuperCall.ts, 16, 25)) + + // @ts-ignore + constructor(public p: number) { +>p : Symbol(Test.p, Decl(emitCodeBeforeSuperCall.ts, 19, 16)) + + 1; // Any statements here break it + super(); +>super : Symbol(Base, Decl(emitCodeBeforeSuperCall.ts, 0, 0)) + + this.prop = 1; +>this.prop : Symbol(Test.prop, Decl(emitCodeBeforeSuperCall.ts, 16, 25)) +>this : Symbol(Test, Decl(emitCodeBeforeSuperCall.ts, 14, 1)) +>prop : Symbol(Test.prop, Decl(emitCodeBeforeSuperCall.ts, 16, 25)) + } +} + diff --git a/tests/baselines/reference/emitCodeBeforeSuperCall.types b/tests/baselines/reference/emitCodeBeforeSuperCall.types new file mode 100644 index 00000000000..49f5c079513 --- /dev/null +++ b/tests/baselines/reference/emitCodeBeforeSuperCall.types @@ -0,0 +1,60 @@ +=== tests/cases/conformance/classes/constructorDeclarations/superCalls/emitCodeBeforeSuperCall.ts === +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code + +class Base { +>Base : Base +} +class Sub extends Base { +>Sub : Sub +>Base : Base + + // @ts-ignore + constructor(public p: number) { +>p : number + + console.log('hi'); +>console.log('hi') : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>'hi' : "hi" + + super(); +>super() : void +>super : typeof Base + } + field = 0; +>field : number +>0 : 0 +} + +class Test extends Base { +>Test : Test +>Base : Base + + prop: number; +>prop : number + + // @ts-ignore + constructor(public p: number) { +>p : number + + 1; // Any statements here break it +>1 : 1 + + super(); +>super() : void +>super : typeof Base + + this.prop = 1; +>this.prop = 1 : 1 +>this.prop : number +>this : this +>prop : number +>1 : 1 + } +} + diff --git a/tests/baselines/reference/emitCodeBeforeSuperCall2.js b/tests/baselines/reference/emitCodeBeforeSuperCall2.js new file mode 100644 index 00000000000..43bf2c1e82c --- /dev/null +++ b/tests/baselines/reference/emitCodeBeforeSuperCall2.js @@ -0,0 +1,49 @@ +//// [emitCodeBeforeSuperCall2.ts] +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code + + +class BaseA { + public constructor(public x: number) { } +} +class DerivedA extends BaseA { + constructor(public x: number) { super(x); } +} + + +//// [emitCodeBeforeSuperCall2.js] +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code +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 (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var BaseA = /** @class */ (function () { + function BaseA(x) { + this.x = x; + } + return BaseA; +}()); +var DerivedA = /** @class */ (function (_super) { + __extends(DerivedA, _super); + function DerivedA(x) { + var _this = this; + _this.x = x; + _this = _super.call(this, x) || this; + return _this; + } + return DerivedA; +}(BaseA)); diff --git a/tests/baselines/reference/emitCodeBeforeSuperCall2.symbols b/tests/baselines/reference/emitCodeBeforeSuperCall2.symbols new file mode 100644 index 00000000000..8502639b32a --- /dev/null +++ b/tests/baselines/reference/emitCodeBeforeSuperCall2.symbols @@ -0,0 +1,23 @@ +=== tests/cases/conformance/classes/constructorDeclarations/superCalls/emitCodeBeforeSuperCall2.ts === +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code + + +class BaseA { +>BaseA : Symbol(BaseA, Decl(emitCodeBeforeSuperCall2.ts, 0, 0)) + + public constructor(public x: number) { } +>x : Symbol(BaseA.x, Decl(emitCodeBeforeSuperCall2.ts, 7, 23)) +} +class DerivedA extends BaseA { +>DerivedA : Symbol(DerivedA, Decl(emitCodeBeforeSuperCall2.ts, 8, 1)) +>BaseA : Symbol(BaseA, Decl(emitCodeBeforeSuperCall2.ts, 0, 0)) + + constructor(public x: number) { super(x); } +>x : Symbol(DerivedA.x, Decl(emitCodeBeforeSuperCall2.ts, 10, 16)) +>super : Symbol(BaseA, Decl(emitCodeBeforeSuperCall2.ts, 0, 0)) +>x : Symbol(x, Decl(emitCodeBeforeSuperCall2.ts, 10, 16)) +} + diff --git a/tests/baselines/reference/emitCodeBeforeSuperCall2.types b/tests/baselines/reference/emitCodeBeforeSuperCall2.types new file mode 100644 index 00000000000..6aef3c503cf --- /dev/null +++ b/tests/baselines/reference/emitCodeBeforeSuperCall2.types @@ -0,0 +1,24 @@ +=== tests/cases/conformance/classes/constructorDeclarations/superCalls/emitCodeBeforeSuperCall2.ts === +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code + + +class BaseA { +>BaseA : BaseA + + public constructor(public x: number) { } +>x : number +} +class DerivedA extends BaseA { +>DerivedA : DerivedA +>BaseA : BaseA + + constructor(public x: number) { super(x); } +>x : number +>super(x) : void +>super : typeof BaseA +>x : number +} + diff --git a/tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.js b/tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.js new file mode 100644 index 00000000000..f84a843ddcd --- /dev/null +++ b/tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.js @@ -0,0 +1,74 @@ +//// [emitCodeBeforeSuperCallWithDefineFields.ts] +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code + +class Base { +} +class Sub extends Base { + // @ts-ignore + constructor(public p: number) { + console.log('hi'); + super(); + } + field = 0; +} + +class Test extends Base { + prop: number; + // @ts-ignore + constructor(public p: number) { + 1; // Any statements here break it + super(); + this.prop = 1; + } +} + + +//// [emitCodeBeforeSuperCallWithDefineFields.js] +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code +class Base { +} +class Sub extends Base { + // @ts-ignore + constructor(p) { + console.log('hi'); + super(); + Object.defineProperty(this, "p", { + enumerable: true, + configurable: true, + writable: true, + value: p + }); + Object.defineProperty(this, "field", { + enumerable: true, + configurable: true, + writable: true, + value: 0 + }); + } +} +class Test extends Base { + // @ts-ignore + constructor(p) { + 1; // Any statements here break it + super(); + Object.defineProperty(this, "p", { + enumerable: true, + configurable: true, + writable: true, + value: p + }); + Object.defineProperty(this, "prop", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); + this.prop = 1; + } +} diff --git a/tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.symbols b/tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.symbols new file mode 100644 index 00000000000..50260f261b6 --- /dev/null +++ b/tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.symbols @@ -0,0 +1,51 @@ +=== tests/cases/conformance/classes/constructorDeclarations/superCalls/emitCodeBeforeSuperCallWithDefineFields.ts === +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code + +class Base { +>Base : Symbol(Base, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 0, 0)) +} +class Sub extends Base { +>Sub : Symbol(Sub, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 6, 1)) +>Base : Symbol(Base, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 0, 0)) + + // @ts-ignore + constructor(public p: number) { +>p : Symbol(Sub.p, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 9, 16)) + + console.log('hi'); +>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, --, --)) + + super(); +>super : Symbol(Base, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 0, 0)) + } + field = 0; +>field : Symbol(Sub.field, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 12, 5)) +} + +class Test extends Base { +>Test : Symbol(Test, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 14, 1)) +>Base : Symbol(Base, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 0, 0)) + + prop: number; +>prop : Symbol(Test.prop, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 16, 25)) + + // @ts-ignore + constructor(public p: number) { +>p : Symbol(Test.p, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 19, 16)) + + 1; // Any statements here break it + super(); +>super : Symbol(Base, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 0, 0)) + + this.prop = 1; +>this.prop : Symbol(Test.prop, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 16, 25)) +>this : Symbol(Test, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 14, 1)) +>prop : Symbol(Test.prop, Decl(emitCodeBeforeSuperCallWithDefineFields.ts, 16, 25)) + } +} + diff --git a/tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.types b/tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.types new file mode 100644 index 00000000000..94dfd93cf86 --- /dev/null +++ b/tests/baselines/reference/emitCodeBeforeSuperCallWithDefineFields.types @@ -0,0 +1,60 @@ +=== tests/cases/conformance/classes/constructorDeclarations/superCalls/emitCodeBeforeSuperCallWithDefineFields.ts === +// TODO: With false, master is correct for `Test` but incorrect for `Sub`. +// `Test` is correct because classic emit doesn't emit for definition and `Test` +// doesn't need to emit any code for initialisation because it's already +// part of the user code + +class Base { +>Base : Base +} +class Sub extends Base { +>Sub : Sub +>Base : Base + + // @ts-ignore + constructor(public p: number) { +>p : number + + console.log('hi'); +>console.log('hi') : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>'hi' : "hi" + + super(); +>super() : void +>super : typeof Base + } + field = 0; +>field : number +>0 : 0 +} + +class Test extends Base { +>Test : Test +>Base : Base + + prop: number; +>prop : number + + // @ts-ignore + constructor(public p: number) { +>p : number + + 1; // Any statements here break it +>1 : 1 + + super(); +>super() : void +>super : typeof Base + + this.prop = 1; +>this.prop = 1 : 1 +>this.prop : number +>this : this +>prop : number +>1 : 1 + } +} + diff --git a/tests/baselines/reference/emitStatementsBeforeSuperCall.js b/tests/baselines/reference/emitStatementsBeforeSuperCall.js new file mode 100644 index 00000000000..72b3e7b4836 --- /dev/null +++ b/tests/baselines/reference/emitStatementsBeforeSuperCall.js @@ -0,0 +1,44 @@ +//// [emitStatementsBeforeSuperCall.ts] +class Base { +} +class Sub extends Base { + // @ts-ignore + constructor(public p: number) { + console.log('hi'); // should emit before super + super(); + } + field = 0; +} + +class Test extends Base { + prop: number; + // @ts-ignore + constructor(public p: number) { + 1; // should emit before super + super(); + this.prop = 1; + } +} + + +//// [emitStatementsBeforeSuperCall.js] +class Base { +} +class Sub extends Base { + // @ts-ignore + constructor(p) { + console.log('hi'); // should emit before super + super(); + this.p = p; + this.field = 0; + } +} +class Test extends Base { + // @ts-ignore + constructor(p) { + 1; // should emit before super + super(); + this.p = p; + this.prop = 1; + } +} diff --git a/tests/baselines/reference/emitStatementsBeforeSuperCall.symbols b/tests/baselines/reference/emitStatementsBeforeSuperCall.symbols new file mode 100644 index 00000000000..1a76d236318 --- /dev/null +++ b/tests/baselines/reference/emitStatementsBeforeSuperCall.symbols @@ -0,0 +1,46 @@ +=== tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCall.ts === +class Base { +>Base : Symbol(Base, Decl(emitStatementsBeforeSuperCall.ts, 0, 0)) +} +class Sub extends Base { +>Sub : Symbol(Sub, Decl(emitStatementsBeforeSuperCall.ts, 1, 1)) +>Base : Symbol(Base, Decl(emitStatementsBeforeSuperCall.ts, 0, 0)) + + // @ts-ignore + constructor(public p: number) { +>p : Symbol(Sub.p, Decl(emitStatementsBeforeSuperCall.ts, 4, 16)) + + console.log('hi'); // should emit before super +>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, --, --)) + + super(); +>super : Symbol(Base, Decl(emitStatementsBeforeSuperCall.ts, 0, 0)) + } + field = 0; +>field : Symbol(Sub.field, Decl(emitStatementsBeforeSuperCall.ts, 7, 5)) +} + +class Test extends Base { +>Test : Symbol(Test, Decl(emitStatementsBeforeSuperCall.ts, 9, 1)) +>Base : Symbol(Base, Decl(emitStatementsBeforeSuperCall.ts, 0, 0)) + + prop: number; +>prop : Symbol(Test.prop, Decl(emitStatementsBeforeSuperCall.ts, 11, 25)) + + // @ts-ignore + constructor(public p: number) { +>p : Symbol(Test.p, Decl(emitStatementsBeforeSuperCall.ts, 14, 16)) + + 1; // should emit before super + super(); +>super : Symbol(Base, Decl(emitStatementsBeforeSuperCall.ts, 0, 0)) + + this.prop = 1; +>this.prop : Symbol(Test.prop, Decl(emitStatementsBeforeSuperCall.ts, 11, 25)) +>this : Symbol(Test, Decl(emitStatementsBeforeSuperCall.ts, 9, 1)) +>prop : Symbol(Test.prop, Decl(emitStatementsBeforeSuperCall.ts, 11, 25)) + } +} + diff --git a/tests/baselines/reference/emitStatementsBeforeSuperCall.types b/tests/baselines/reference/emitStatementsBeforeSuperCall.types new file mode 100644 index 00000000000..ab731b040ef --- /dev/null +++ b/tests/baselines/reference/emitStatementsBeforeSuperCall.types @@ -0,0 +1,55 @@ +=== tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCall.ts === +class Base { +>Base : Base +} +class Sub extends Base { +>Sub : Sub +>Base : Base + + // @ts-ignore + constructor(public p: number) { +>p : number + + console.log('hi'); // should emit before super +>console.log('hi') : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>'hi' : "hi" + + super(); +>super() : void +>super : typeof Base + } + field = 0; +>field : number +>0 : 0 +} + +class Test extends Base { +>Test : Test +>Base : Base + + prop: number; +>prop : number + + // @ts-ignore + constructor(public p: number) { +>p : number + + 1; // should emit before super +>1 : 1 + + super(); +>super() : void +>super : typeof Base + + this.prop = 1; +>this.prop = 1 : 1 +>this.prop : number +>this : this +>prop : number +>1 : 1 + } +} + diff --git a/tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.js b/tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.js new file mode 100644 index 00000000000..685c7562d6d --- /dev/null +++ b/tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.js @@ -0,0 +1,65 @@ +//// [emitStatementsBeforeSuperCallWithDefineFields.ts] +class Base { +} +class Sub extends Base { + // @ts-ignore + constructor(public p: number) { + console.log('hi'); + super(); + } + field = 0; +} + +class Test extends Base { + prop: number; + // @ts-ignore + constructor(public p: number) { + 1; + super(); + this.prop = 1; + } +} + + +//// [emitStatementsBeforeSuperCallWithDefineFields.js] +class Base { +} +class Sub extends Base { + // @ts-ignore + constructor(p) { + console.log('hi'); + super(); + Object.defineProperty(this, "p", { + enumerable: true, + configurable: true, + writable: true, + value: p + }); + Object.defineProperty(this, "field", { + enumerable: true, + configurable: true, + writable: true, + value: 0 + }); + } +} +class Test extends Base { + // @ts-ignore + constructor(p) { + 1; + super(); + Object.defineProperty(this, "p", { + enumerable: true, + configurable: true, + writable: true, + value: p + }); + Object.defineProperty(this, "prop", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); + this.prop = 1; + } +} diff --git a/tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.symbols b/tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.symbols new file mode 100644 index 00000000000..106aa7bc343 --- /dev/null +++ b/tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.symbols @@ -0,0 +1,46 @@ +=== tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCallWithDefineFields.ts === +class Base { +>Base : Symbol(Base, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 0, 0)) +} +class Sub extends Base { +>Sub : Symbol(Sub, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 1, 1)) +>Base : Symbol(Base, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 0, 0)) + + // @ts-ignore + constructor(public p: number) { +>p : Symbol(Sub.p, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 4, 16)) + + console.log('hi'); +>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, --, --)) + + super(); +>super : Symbol(Base, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 0, 0)) + } + field = 0; +>field : Symbol(Sub.field, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 7, 5)) +} + +class Test extends Base { +>Test : Symbol(Test, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 9, 1)) +>Base : Symbol(Base, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 0, 0)) + + prop: number; +>prop : Symbol(Test.prop, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 11, 25)) + + // @ts-ignore + constructor(public p: number) { +>p : Symbol(Test.p, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 14, 16)) + + 1; + super(); +>super : Symbol(Base, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 0, 0)) + + this.prop = 1; +>this.prop : Symbol(Test.prop, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 11, 25)) +>this : Symbol(Test, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 9, 1)) +>prop : Symbol(Test.prop, Decl(emitStatementsBeforeSuperCallWithDefineFields.ts, 11, 25)) + } +} + diff --git a/tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.types b/tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.types new file mode 100644 index 00000000000..29a20cbbdc0 --- /dev/null +++ b/tests/baselines/reference/emitStatementsBeforeSuperCallWithDefineFields.types @@ -0,0 +1,55 @@ +=== tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCallWithDefineFields.ts === +class Base { +>Base : Base +} +class Sub extends Base { +>Sub : Sub +>Base : Base + + // @ts-ignore + constructor(public p: number) { +>p : number + + console.log('hi'); +>console.log('hi') : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>'hi' : "hi" + + super(); +>super() : void +>super : typeof Base + } + field = 0; +>field : number +>0 : 0 +} + +class Test extends Base { +>Test : Test +>Base : Base + + prop: number; +>prop : number + + // @ts-ignore + constructor(public p: number) { +>p : number + + 1; +>1 : 1 + + super(); +>super() : void +>super : typeof Base + + this.prop = 1; +>this.prop = 1 : 1 +>this.prop : number +>this : this +>prop : number +>1 : 1 + } +} + diff --git a/tests/baselines/reference/privateNameBadSuper.js b/tests/baselines/reference/privateNameBadSuper.js index be1b0e6ea61..07d8c2324f5 100644 --- a/tests/baselines/reference/privateNameBadSuper.js +++ b/tests/baselines/reference/privateNameBadSuper.js @@ -15,9 +15,9 @@ class B { ; class A extends B { constructor() { - _x.set(this, void 0); void 0; // Error: 'super' call must come first super(); + _x.set(this, void 0); } } _x = new WeakMap(); diff --git a/tests/baselines/reference/strictModeInConstructor.js b/tests/baselines/reference/strictModeInConstructor.js index 4356793d3d2..d7e877eda2f 100644 --- a/tests/baselines/reference/strictModeInConstructor.js +++ b/tests/baselines/reference/strictModeInConstructor.js @@ -103,9 +103,9 @@ var D = /** @class */ (function (_super) { __extends(D, _super); function D() { var _this = this; - _this.s = 9; var x = 1; // Error _this = _super.call(this) || this; + _this.s = 9; "use strict"; return _this; } diff --git a/tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCall.ts b/tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCall.ts new file mode 100644 index 00000000000..3c3559808b1 --- /dev/null +++ b/tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCall.ts @@ -0,0 +1,23 @@ +// @useDefineForClassFields: false +// @target: es2015 + +class Base { +} +class Sub extends Base { + // @ts-ignore + constructor(public p: number) { + console.log('hi'); // should emit before super + super(); + } + field = 0; +} + +class Test extends Base { + prop: number; + // @ts-ignore + constructor(public p: number) { + 1; // should emit before super + super(); + this.prop = 1; + } +} diff --git a/tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCallWithDefineFields.ts b/tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCallWithDefineFields.ts new file mode 100644 index 00000000000..f1736ac8a9f --- /dev/null +++ b/tests/cases/conformance/classes/constructorDeclarations/superCalls/emitStatementsBeforeSuperCallWithDefineFields.ts @@ -0,0 +1,23 @@ +// @useDefineForClassFields: true +// @target: es2015 + +class Base { +} +class Sub extends Base { + // @ts-ignore + constructor(public p: number) { + console.log('hi'); + super(); + } + field = 0; +} + +class Test extends Base { + prop: number; + // @ts-ignore + constructor(public p: number) { + 1; + super(); + this.prop = 1; + } +}