8000 Merge pull request #4656 from Microsoft/Fix4655 · prmdeveloper/TypeScript@a5c7201 · GitHub
[go: up one dir, main page]

Skip to content

Commit a5c7201

Browse files
committed
Merge pull request microsoft#4656 from Microsoft/Fix4655
Report error for class expressions incorrectly extending abstract classes
2 parents 971c777 + d8c6f7e commit a5c7201

File tree

6 files changed

+75
-10
lines changed

6 files changed

+75
-10
lines changed

src/compiler/checker.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5111,8 +5111,8 @@ namespace ts {
51115111
function abstractSignatureRelatedTo(source: Type, sourceSig: Signature, target: Type, targetSig: Signature) {
51125112
if (sourceSig && targetSig) {
51135113

5114-
let sourceDecl = source.symbol && getDeclarationOfKind(source.symbol, SyntaxKind.ClassDeclaration);
5115-
let targetDecl = target.symbol && getDeclarationOfKind(target.symbol, SyntaxKind.ClassDeclaration);
5114+
let sourceDecl = source.symbol && getClassLikeDeclarationOfSymbol(source.symbol);
5115+
let targetDecl = target.symbol && getClassLikeDeclarationOfSymbol(target.symbol);
51165116

51175117
if (!sourceDecl) {
51185118
// If the source object isn't itself a class declaration, it can be freely assigned, regardless
@@ -5126,8 +5126,8 @@ namespace ts {
51265126
let sourceReturnType = sourceErasedSignature && getReturnTypeOfSignature(sourceErasedSignature);
51275127
let targetReturnType = targetErasedSignature && getReturnTypeOfSignature(targetErasedSignature);
51285128

5129-
let sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getDeclarationOfKind(sourceReturnType.symbol, SyntaxKind.ClassDeclaration);
5130-
let targetReturnDecl = targetReturnType && targetReturnType.symbol && getDeclarationOfKind(targetReturnType.symbol, SyntaxKind.ClassDeclaration);
5129+
let sourceReturnDecl = sourceReturnType && sourceReturnType.symbol && getClassLikeDeclarationOfSymbol(sourceReturnType.symbol);
5130+
let targetReturnDecl = targetReturnType && targetReturnType.symbol && getClassLikeDeclarationOfSymbol(targetReturnType.symbol);
51315131
let sourceIsAbstract = sourceReturnDecl && sourceReturnDecl.flags & NodeFlags.Abstract;
51325132
let targetIsAbstract = targetReturnDecl && targetReturnDecl.flags & 8000 NodeFlags.Abstract;
51335133

@@ -8879,7 +8879,7 @@ namespace ts {
88798879
// Note, only class declarations can be declared abstract.
88808880
// In the case of a merged class-module or class-interface declaration,
88818881
// only the class declaration node will have the Abstract flag set.
8882-
let valueDecl = expressionType.symbol && getDeclarationOfKind(expressionType.symbol, SyntaxKind.ClassDeclaration);
8882+
let valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol);
88838883
if (valueDecl && valueDecl.flags & NodeFlags.Abstract) {
88848884
error(node, Diagnostics.Cannot_create_an_instance_of_the_abstract_class_0, declarationNameToString(valueDecl.name));
88858885
return resolveErrorCall(node);
@@ -12631,6 +12631,10 @@ namespace ts {
1263112631
return s.flags & SymbolFlags.Instantiated ? getSymbolLinks(s).target : s;
1263212632
}
1263312633

12634+
function getClassLikeDeclarationOfSymbol(symbol: Symbol): Declaration {
12635+
return forEach(symbol.declarations, d => isClassLike(d) ? d : undefined);
12636+
}
12637+
1263412638
function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: ObjectType): void {
1263512639

1263612640
// TypeScript 1.0 spec (April 2014): 8.2.3
@@ -12668,14 +12672,20 @@ namespace ts {
1266812672
if (derived === base) {
1266912673
// derived class inherits base without override/redeclaration
1267012674

12671-
let derivedClassDecl = getDeclarationOfKind(type.symbol, SyntaxKind.ClassDeclaration);
12675+
let derivedClassDecl = getClassLikeDeclarationOfSymbol(type.symbol);
1267212676

1267312677
// It is an error to inherit an abstract member without implementing it or being declared abstract.
1267412678
// If there is no declaration for the derived class (as in the case of class expressions),
1267512679
// then the class cannot be declared abstract.
12676-
if ( baseDeclarationFlags & NodeFlags.Abstract && (!derivedClassDecl || !(derivedClassDecl.flags & NodeFlags.Abstract))) {
12677-
error(derivedClassDecl, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2,
12678-
typeToString(type), symbolToString(baseProperty), typeToString(baseType));
12680+
if (baseDeclarationFlags & NodeFlags.Abstract && (!derivedClassDecl || !(derivedClassDecl.flags & NodeFlags.Abstract))) {
12681+
if (derivedClassDecl.kind === SyntaxKind.ClassExpression) {
12682+
error(derivedClassDecl, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1,
12683+
symbolToString(baseProperty), typeToString(baseType));
12684+
}
12685+
else {
12686+
error(derivedClassDecl, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2,
12687+
typeToString(type), symbolToString(baseProperty), typeToString(baseType));
12688+
}
1267912689
}
1268012690
}
1268112691
else {

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ namespace ts {
427427
Cannot_emit_namespaced_JSX_elements_in_React: { code: 2650, category: DiagnosticCategory.Error, key: "Cannot emit namespaced JSX elements in React" },
428428
A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums: { code: 2651, category: DiagnosticCategory.Error, key: "A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums." },
429429
Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead: { code: 2652, category: DiagnosticCategory.Error, key: "Merged declaration '{0}' cannot include a default export declaration. Consider adding a separate 'export default {0}' declaration instead." },
430+
Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1: { code: 2653, category: DiagnosticCategory.Error, key: "Non-abstract class expression does not implement inherited abstract member '{0}' from class '{1}'." },
430431
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
431432
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
432433
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },

src/compiler/diagnosticMessages.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1692,11 +1692,16 @@
16921692
"A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums.": {
16931693
"category": "Error",
16941694
"code": 2651
1695-
},
1695+
},
16961696
"Merged declaration '{0}' cannot include a default export declaration. Consider adding a separate 'export default {0}' declaration instead.": {
16971697
"category": "Error",
16981698
"code": 2652
16991699
},
1700+
"Non-abstract class expression does not implement inherited abstract member '{0}' from class '{1}'.": {
1701+
"category": "Error",
1702+
"code": 2653
1703+
},
1704+
17001705
"Import declaration '{0}' is using private name '{1}'.": {
17011706
"category": "Error",
17021707
"code": 4000
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
tests/cases/compiler/classExpressionExtendingAbstractClass.ts(5,9): error TS2653: Non-abstract class expression does not implement inherited abstract member 'foo' from class 'A'.
2+
3+
4+
==== tests/cases/compiler/classExpressionExtendingAbstractClass.ts (1 errors) ====
5+
abstract class A {
6+
abstract foo(): void;
7+
}
8+
9+
var C = class extends A { // no error reported!
10+
~~~~~
11+
!!! error TS2653: Non-abstract class expression does not implement inherited abstract member 'foo' from class 'A'.
12+
};
13+
14+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [classExpressionExtendingAbstractClass.ts]
2+
abstract class A {
3+
abstract foo(): void;
4+
}
5+
6+
var C = class extends A { // no error reported!
7+
};
8+
9+
10+
11+
//// [classExpressionExtendingAbstractClass.js]
12+
var __extends = (this && this.__extends) || function (d, b) {
13+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
14+
function __() { this.constructor = d; }
15+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
16+
};
17+
var A = (function () {
18+
function A() {
19+
}
20+
return A;
21+
})();
22+
var C = (function (_super) {
23+
__extends(class_1, _super);
24+
function class_1() {
25+
_super.apply(this, arguments);
26+
}
27+
return class_1;
28+
})(A);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
abstract class A {
2+
abstract foo(): void;
3+
}
4+
5+
var C = class extends A { // no error reported!
6+
};
7+

0 commit comments

Comments
 (0)
0