diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c39fdb19131..d5963593b2f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10431,9 +10431,17 @@ namespace ts { // TS 1.0 spec (April 2014): 8.3.2 // Constructors of classes with no extends clause may not contain super calls, whereas // constructors of derived classes must contain at least one super call somewhere in their function body. - if (getClassExtendsHeritageClauseElement(node.parent)) { + let containingClassDecl = node.parent; + if (getClassExtendsHeritageClauseElement(containingClassDecl)) { + let containingClassSymbol = getSymbolOfNode(containingClassDecl); + let containingClassInstanceType = getDeclaredTypeOfSymbol(containingClassSymbol); + let baseConstructorType = getBaseConstructorTypeOfClass(containingClassInstanceType); if (containsSuperCall(node.body)) { + if (baseConstructorType === nullType) { + error(node, Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null); + } + // The first statement in the body of a constructor (excluding prologue directives) must be a super call // if both of the following are true: // - The containing class is a derived class. @@ -10466,7 +10474,7 @@ namespace ts { } } } - else { + else if (baseConstructorType !== nullType) { error(node, Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call); } } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 854d214fb74..87e73e0c9c9 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -614,5 +614,6 @@ namespace ts { Expected_corresponding_JSX_closing_tag_for_0: { code: 17002, category: DiagnosticCategory.Error, key: "Expected corresponding JSX closing tag for '{0}'." }, JSX_attribute_expected: { code: 17003, category: DiagnosticCategory.Error, key: "JSX attribute expected." }, Cannot_use_JSX_unless_the_jsx_flag_is_provided: { code: 17004, category: DiagnosticCategory.Error, key: "Cannot use JSX unless the '--jsx' flag is provided." }, + A_constructor_cannot_contain_a_super_call_when_its_class_extends_null: { code: 17005, category: DiagnosticCategory.Error, key: "A constructor cannot contain a 'super' call when its class extends 'null'" }, }; } \ No newline at end of file diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index fd235a9d38a..903ad00add3 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1,4 +1,4 @@ -{ + { "Unterminated string literal.": { "category": "Error", "code": 1002 @@ -2449,5 +2449,9 @@ "Cannot use JSX unless the '--jsx' flag is provided.": { "category": "Error", "code": 17004 + }, + "A constructor cannot contain a 'super' call when its class extends 'null'": { + "category": "Error", + "code": 17005 } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 21eed30c244..ba7aceb856d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1777,10 +1777,10 @@ namespace ts { StringLike = String | StringLiteral, NumberLike = Number | Enum, ObjectType = Class | Interface | Reference | Tuple | Anonymous, - UnionOrIntersection = Union | Intersection, + UnionOrIntersection = Union | Intersection, StructuredType = ObjectType | Union | Intersection, /* @internal */ - RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral + RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral } // Properties common to all types diff --git a/tests/baselines/reference/classExtendsNull.errors.txt b/tests/baselines/reference/classExtendsNull.errors.txt new file mode 100644 index 00000000000..7bb44774826 --- /dev/null +++ b/tests/baselines/reference/classExtendsNull.errors.txt @@ -0,0 +1,21 @@ +tests/cases/compiler/classExtendsNull.ts(2,5): error TS17005: A constructor cannot contain a 'super' call when its class extends 'null' + + +==== tests/cases/compiler/classExtendsNull.ts (1 errors) ==== + class C extends null { + constructor() { + ~~~~~~~~~~~~~~~ + super(); + ~~~~~~~~~~~~~~~~ + return Object.create(null); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~~~~~ +!!! error TS17005: A constructor cannot contain a 'super' call when its class extends 'null' + } + + class D extends null { + constructor() { + return Object.create(null); + } + } \ No newline at end of file diff --git a/tests/baselines/reference/classExtendsNull.js b/tests/baselines/reference/classExtendsNull.js new file mode 100644 index 00000000000..5627f10dca6 --- /dev/null +++ b/tests/baselines/reference/classExtendsNull.js @@ -0,0 +1,35 @@ +//// [classExtendsNull.ts] +class C extends null { + constructor() { + super(); + return Object.create(null); + } +} + +class D extends null { + constructor() { + return Object.create(null); + } +} + +//// [classExtendsNull.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.call(this); + return Object.create(null); + } + return C; +})(null); +var D = (function (_super) { + __extends(D, _super); + function D() { + return Object.create(null); + } + return D; +})(null); diff --git a/tests/cases/compiler/classExtendsNull.ts b/tests/cases/compiler/classExtendsNull.ts new file mode 100644 index 00000000000..5532fa72702 --- /dev/null +++ b/tests/cases/compiler/classExtendsNull.ts @@ -0,0 +1,12 @@ +class C extends null { + constructor() { + super(); + return Object.create(null); + } +} + +class D extends null { + constructor() { + return Object.create(null); + } +} \ No newline at end of file