From cc2dc3acb0a3c654ca6ca26cad906af5585fcadf Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Sat, 6 Aug 2016 10:36:17 -0700 Subject: [PATCH] Emit more efficient/concise "empty" ES6 ctor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When there are property assignments in a the class body of an inheriting class, tsc current emit the following compilation: ```ts class Foo extends Bar { public foo = 1; } ``` ```js class Foo extends Bar { constructor(…args) { super(…args); this.foo = 1; } } ``` This introduces an unneeded local variable and might force a reification of the `arguments` object (or otherwise reify the arguments into an array). This is particularly bad when that output is fed into another transpiler like Babel. In Babel, you get something like this today: ```js var Foo = (function (_Bar) { _inherits(Foo, _Bar); function Foo() { _classCallCheck(this, Foo); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _Bar.call.apply(_Bar, [this].concat(args)); this.foo = 1; } return Foo; })(Bar); ``` This causes a lot of needless work/allocations and some very strange code (`.call.apply` o_0). Admittedly, this is not strictly tsc’s problem; it could have done a deeper analysis of the code and optimized out the extra dance. However, tsc could also have emitted this simpler, more concise and semantically equivalent code in the first place: ```js class Foo extends Bar { constructor() { super(…arguments); this.foo = 1; } } ``` Which compiles into the following in Babel: ```js var Foo = (function (_Bar) { _inherits(Foo, _Bar); function Foo() { _classCallCheck(this, Foo); _Bar.apply(this, arguments); this.foo = 1; } return Foo; })(Bar); ``` Which is well-optimized (today) in most engines and much less confusing to read. As far as I can tell, the proposed compilation has exactly the same semantics as before. Fixes #10175 --- src/compiler/emitter.ts | 15 ++------------- tests/baselines/reference/classExpressionES63.js | 8 ++++---- ...ClassDeclarationWithPropertyAssignmentInES6.js | 4 ++-- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index c8bd8072b2400..6666b7df2351c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5311,18 +5311,7 @@ const _super = (function (geti, seti) { emitSignatureParameters(ctor); } else { - // Based on EcmaScript6 section 14.5.14: Runtime Semantics: ClassDefinitionEvaluation. - // If constructor is empty, then, - // If ClassHeritageopt is present, then - // Let constructor be the result of parsing the String "constructor(... args){ super (...args);}" using the syntactic grammar with the goal symbol MethodDefinition. - // Else, - // Let constructor be the result of parsing the String "constructor( ){ }" using the syntactic grammar with the goal symbol MethodDefinition - if (baseTypeElement) { - write("(...args)"); - } - else { - write("()"); - } + write("()"); } } @@ -5360,7 +5349,7 @@ const _super = (function (geti, seti) { write("_super.apply(this, arguments);"); } else { - write("super(...args);"); + write("super(...arguments);"); } emitEnd(baseTypeElement); } diff --git a/tests/baselines/reference/classExpressionES63.js b/tests/baselines/reference/classExpressionES63.js index 6b3a06cf7c369..5a72e173475e2 100644 --- a/tests/baselines/reference/classExpressionES63.js +++ b/tests/baselines/reference/classExpressionES63.js @@ -13,14 +13,14 @@ let C = class extends class extends class { } } { - constructor(...args) { - super(...args); + constructor() { + super(...arguments); this.b = 2; } } { - constructor(...args) { - super(...args); + constructor() { + super(...arguments); this.c = 3; } } diff --git a/tests/baselines/reference/emitClassDeclarationWithPropertyAssignmentInES6.js b/tests/baselines/reference/emitClassDeclarationWithPropertyAssignmentInES6.js index 03fb45b806e3d..91e6c506c2b50 100644 --- a/tests/baselines/reference/emitClassDeclarationWithPropertyAssignmentInES6.js +++ b/tests/baselines/reference/emitClassDeclarationWithPropertyAssignmentInES6.js @@ -37,8 +37,8 @@ class D { } } class E extends D { - constructor(...args) { - super(...args); + constructor() { + super(...arguments); this.z = true; } }