From d7a20f5c6fc869a3185b21af34d1f39d9c5cde4f Mon Sep 17 00:00:00 2001 From: Yui Date: Thu, 1 Sep 2016 15:34:39 -0700 Subject: [PATCH] Port 10404 : optimize emit default constructor for subclass (#10598) * Port 10404 : optimize emit default constructor for subclass * Address PR --- src/compiler/transformers/ts.ts | 27 ++++++++++++++----- .../reference/classExpressionES63.js | 8 +++--- ...sDeclarationWithPropertyAssignmentInES6.js | 4 +-- ...hDefaultConstructorAndExtendsClause.js.map | 2 +- ...tConstructorAndExtendsClause.sourcemap.txt | 13 +++------ 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 6390c874885..efb247ba663 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -821,7 +821,7 @@ namespace ts { return visitEachChild(constructor, visitor, context); } - const parameters = transformConstructorParameters(constructor, hasExtendsClause); + const parameters = transformConstructorParameters(constructor); const body = transformConstructorBody(node, constructor, hasExtendsClause, parameters); // constructor(${parameters}) { @@ -848,10 +848,25 @@ namespace ts { * @param constructor The constructor declaration. * @param hasExtendsClause A value indicating whether the class has an extends clause. */ - function transformConstructorParameters(constructor: ConstructorDeclaration, hasExtendsClause: boolean) { + function transformConstructorParameters(constructor: ConstructorDeclaration) { + // The ES2015 spec specifies in 14.5.14. Runtime Semantics: ClassDefinitionEvaluation: + // If constructor is empty, then + // If ClassHeritag_eopt is present and protoParent is not null, then + // Let constructor be the result of parsing the source text + // constructor(...args) { super (...args);} + // using the syntactic grammar with the goal symbol MethodDefinition[~Yield]. + // Else, + // Let constructor be the result of parsing the source text + // constructor( ){ } + // using the syntactic grammar with the goal symbol MethodDefinition[~Yield]. + // + // While we could emit the '...args' rest parameter, certain later tools in the pipeline might + // downlevel the '...args' portion less efficiently by naively copying the contents of 'arguments' to an array. + // Instead, we'll avoid using a rest parameter and spread into the super call as + // 'super(...arguments)' instead of 'super(...args)', as you can see in "transformConstructorBody". return constructor ? visitNodes(constructor.parameters, visitor, isParameter) - : hasExtendsClause ? [createRestParameter("args")] : []; + : []; } /** @@ -889,18 +904,16 @@ namespace ts { addRange(statements, map(propertyAssignments, transformParameterWithPropertyAssignment)); } else if (hasExtendsClause) { - Debug.assert(parameters.length === 1 && isIdentifier(parameters[0].name)); - // Add a synthetic `super` call: // - // super(...args); + // super(...arguments); // statements.push( createStatement( createCall( createSuper(), /*typeArguments*/ undefined, - [createSpread(parameters[0].name)] + [createSpread(createIdentifier("arguments"))] ) ) ); diff --git a/tests/baselines/reference/classExpressionES63.js b/tests/baselines/reference/classExpressionES63.js index 254014c9458..66d5bc4de4c 100644 --- a/tests/baselines/reference/classExpressionES63.js +++ b/tests/baselines/reference/classExpressionES63.js @@ -12,13 +12,13 @@ let C = class extends class extends class { this.a = 1; } } { - 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 03fb45b806e..91e6c506c2b 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; } } diff --git a/tests/baselines/reference/sourceMapValidationClassWithDefaultConstructorAndExtendsClause.js.map b/tests/baselines/reference/sourceMapValidationClassWithDefaultConstructorAndExtendsClause.js.map index 7dd53ed4b62..9c350133f2b 100644 --- a/tests/baselines/reference/sourceMapValidationClassWithDefaultConstructorAndExtendsClause.js.map +++ b/tests/baselines/reference/sourceMapValidationClassWithDefaultConstructorAndExtendsClause.js.map @@ -1,2 +1,2 @@ //// [sourceMapValidationClassWithDefaultConstructorAndExtendsClause.js.map] -{"version":3,"file":"sourceMapValidationClassWithDefaultConstructorAndExtendsClause.js","sourceRoot":"","sources":["sourceMapValidationClassWithDefaultConstructorAndExtendsClause.ts"],"names":[],"mappings":";;;;;AAAA;IAAA;IACA,CAAC;IAAD,sBAAC;AAAD,CAAC,AADD,IACC;AAED;IAAsB,2BAAe;IAArC;QAAsB,8BAAe;QAC1B,MAAC,GAAG,EAAE,CAAC;QACP,UAAK,GAAG,KAAK,CAAC;IACzB,CAAC;IAAD,cAAC;AAAD,CAAC,AAHD,CAAsB,eAAe,GAGpC"} \ No newline at end of file +{"version":3,"file":"sourceMapValidationClassWithDefaultConstructorAndExtendsClause.js","sourceRoot":"","sources":["sourceMapValidationClassWithDefaultConstructorAndExtendsClause.ts"],"names":[],"mappings":";;;;;AAAA;IAAA;IACA,CAAC;IAAD,sBAAC;AAAD,CAAC,AADD,IACC;AAED;IAAsB,2BAAe;IAArC;;QACW,MAAC,GAAG,EAAE,CAAC;QACP,UAAK,GAAG,KAAK,CAAC;IACzB,CAAC;IAAD,cAAC;AAAD,CAAC,AAHD,CAAsB,eAAe,GAGpC"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationClassWithDefaultConstructorAndExtendsClause.sourcemap.txt b/tests/baselines/reference/sourceMapValidationClassWithDefaultConstructorAndExtendsClause.sourcemap.txt index 5a3b2f86be9..f3052384651 100644 --- a/tests/baselines/reference/sourceMapValidationClassWithDefaultConstructorAndExtendsClause.sourcemap.txt +++ b/tests/baselines/reference/sourceMapValidationClassWithDefaultConstructorAndExtendsClause.sourcemap.txt @@ -82,27 +82,20 @@ sourceFile:sourceMapValidationClassWithDefaultConstructorAndExtendsClause.ts 1 >Emitted(13, 5) Source(4, 1) + SourceIndex(0) --- >>> _super.apply(this, arguments); -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -1->class Greeter extends -2 > AbstractGreeter -1->Emitted(14, 9) Source(4, 23) + SourceIndex(0) -2 >Emitted(14, 39) Source(4, 38) + SourceIndex(0) ---- >>> this.a = 10; -1 >^^^^^^^^ +1->^^^^^^^^ 2 > ^^^^^^ 3 > ^^^ 4 > ^^ 5 > ^ 6 > ^^^^^^^^-> -1 > { +1->class Greeter extends AbstractGreeter { > public 2 > a 3 > = 4 > 10 5 > ; -1 >Emitted(15, 9) Source(5, 12) + SourceIndex(0) +1->Emitted(15, 9) Source(5, 12) + SourceIndex(0) 2 >Emitted(15, 15) Source(5, 13) + SourceIndex(0) 3 >Emitted(15, 18) Source(5, 16) + SourceIndex(0) 4 >Emitted(15, 20) Source(5, 18) + SourceIndex(0)