Merge pull request #19046 from Microsoft/fix15395

Fix emit for classes with both fields and 'extends null'
This commit is contained in:
Ron Buckton 2017-10-11 11:49:22 -07:00 committed by GitHub
commit d08770bdff
5 changed files with 53 additions and 15 deletions

View File

@ -26,7 +26,7 @@ namespace ts {
IsExportOfNamespace = 1 << 3,
IsNamedExternalExport = 1 << 4,
IsDefaultExternalExport = 1 << 5,
HasExtendsClause = 1 << 6,
IsDerivedClass = 1 << 6,
UseImmediatelyInvokedFunctionExpression = 1 << 7,
HasAnyDecorators = HasConstructorDecorators | HasMemberDecorators,
@ -553,7 +553,8 @@ namespace ts {
function getClassFacts(node: ClassDeclaration, staticProperties: ReadonlyArray<PropertyDeclaration>) {
let facts = ClassFacts.None;
if (some(staticProperties)) facts |= ClassFacts.HasStaticInitializedProperties;
if (getClassExtendsHeritageClauseElement(node)) facts |= ClassFacts.HasExtendsClause;
const extendsClauseElement = getClassExtendsHeritageClauseElement(node);
if (extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword) facts |= ClassFacts.IsDerivedClass;
if (shouldEmitDecorateCallForClass(node)) facts |= ClassFacts.HasConstructorDecorators;
if (childIsDecorated(node)) facts |= ClassFacts.HasMemberDecorators;
if (isExportOfNamespace(node)) facts |= ClassFacts.IsExportOfNamespace;
@ -699,7 +700,7 @@ namespace ts {
name,
/*typeParameters*/ undefined,
visitNodes(node.heritageClauses, visitor, isHeritageClause),
transformClassMembers(node, (facts & ClassFacts.HasExtendsClause) !== 0)
transformClassMembers(node, (facts & ClassFacts.IsDerivedClass) !== 0)
);
// To better align with the old emitter, we should not emit a trailing source map
@ -814,7 +815,7 @@ namespace ts {
// ${members}
// }
const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
const members = transformClassMembers(node, (facts & ClassFacts.HasExtendsClause) !== 0);
const members = transformClassMembers(node, (facts & ClassFacts.IsDerivedClass) !== 0);
const classExpression = createClassExpression(/*modifiers*/ undefined, name, /*typeParameters*/ undefined, heritageClauses, members);
setOriginalNode(classExpression, node);
setTextRange(classExpression, location);
@ -887,11 +888,11 @@ namespace ts {
* Transforms the members of a class.
*
* @param node The current class.
* @param hasExtendsClause A value indicating whether the class has an extends clause.
* @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'.
*/
function transformClassMembers(node: ClassDeclaration | ClassExpression, hasExtendsClause: boolean) {
function transformClassMembers(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
const members: ClassElement[] = [];
const constructor = transformConstructor(node, hasExtendsClause);
const constructor = transformConstructor(node, isDerivedClass);
if (constructor) {
members.push(constructor);
}
@ -904,9 +905,9 @@ namespace ts {
* Transforms (or creates) a constructor for a class.
*
* @param node The current class.
* @param hasExtendsClause A value indicating whether the class has an extends clause.
* @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'.
*/
function transformConstructor(node: ClassDeclaration | ClassExpression, hasExtendsClause: boolean) {
function transformConstructor(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
// Check if we have property assignment inside class declaration.
// If there is a property assignment, we need to emit constructor whether users define it or not
// If there is no property assignment, we can omit constructor if users do not define it
@ -921,7 +922,7 @@ namespace ts {
}
const parameters = transformConstructorParameters(constructor);
const body = transformConstructorBody(node, constructor, hasExtendsClause);
const body = transformConstructorBody(node, constructor, isDerivedClass);
// constructor(${parameters}) {
// ${body}
@ -947,7 +948,6 @@ namespace ts {
* parameter property assignments or instance property initializers.
*
* @param constructor The constructor declaration.
* @param hasExtendsClause A value indicating whether the class has an extends clause.
*/
function transformConstructorParameters(constructor: ConstructorDeclaration) {
// The ES2015 spec specifies in 14.5.14. Runtime Semantics: ClassDefinitionEvaluation:
@ -975,9 +975,9 @@ namespace ts {
*
* @param node The current class.
* @param constructor The current class constructor.
* @param hasExtendsClause A value indicating whether the class has an extends clause.
* @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'.
*/
function transformConstructorBody(node: ClassExpression | ClassDeclaration, constructor: ConstructorDeclaration, hasExtendsClause: boolean) {
function transformConstructorBody(node: ClassExpression | ClassDeclaration, constructor: ConstructorDeclaration, isDerivedClass: boolean) {
let statements: Statement[] = [];
let indexOfFirstStatement = 0;
@ -1001,7 +1001,7 @@ namespace ts {
const propertyAssignments = getParametersWithPropertyAssignments(constructor);
addRange(statements, map(propertyAssignments, transformParameterWithPropertyAssignment));
}
else if (hasExtendsClause) {
else if (isDerivedClass) {
// Add a synthetic `super` call:
//
// super(...arguments);

View File

@ -1,7 +1,8 @@
//// [classExtendingNull.ts]
class C1 extends null { }
class C2 extends (null) { }
class C3 extends null { x = 1; }
class C4 extends (null) { x = 1; }
//// [classExtendingNull.js]
var __extends = (this && this.__extends) || (function () {
@ -26,3 +27,17 @@ var C2 = /** @class */ (function (_super) {
}
return C2;
}((null)));
var C3 = /** @class */ (function (_super) {
__extends(C3, _super);
function C3() {
this.x = 1;
}
return C3;
}(null));
var C4 = /** @class */ (function (_super) {
__extends(C4, _super);
function C4() {
this.x = 1;
}
return C4;
}((null)));

View File

@ -5,3 +5,11 @@ class C1 extends null { }
class C2 extends (null) { }
>C2 : Symbol(C2, Decl(classExtendingNull.ts, 0, 25))
class C3 extends null { x = 1; }
>C3 : Symbol(C3, Decl(classExtendingNull.ts, 1, 27))
>x : Symbol(C3.x, Decl(classExtendingNull.ts, 2, 23))
class C4 extends (null) { x = 1; }
>C4 : Symbol(C4, Decl(classExtendingNull.ts, 2, 32))
>x : Symbol(C4.x, Decl(classExtendingNull.ts, 3, 25))

View File

@ -8,3 +8,16 @@ class C2 extends (null) { }
>(null) : null
>null : null
class C3 extends null { x = 1; }
>C3 : C3
>null : null
>x : number
>1 : 1
class C4 extends (null) { x = 1; }
>C4 : C4
>(null) : null
>null : null
>x : number
>1 : 1

View File

@ -1,2 +1,4 @@
class C1 extends null { }
class C2 extends (null) { }
class C3 extends null { x = 1; }
class C4 extends (null) { x = 1; }