check for inheriting abstract member functions
This commit is contained in:
parent
a07f86240d
commit
5ca3955473
3 changed files with 88 additions and 42 deletions
|
@ -4561,7 +4561,24 @@ namespace ts {
|
|||
let requireOptionalProperties = relation === subtypeRelation && !(source.flags & TypeFlags.ObjectLiteral);
|
||||
for (let targetProp of properties) {
|
||||
let sourceProp = getPropertyOfType(source, targetProp.name);
|
||||
if (sourceProp !== targetProp) {
|
||||
|
||||
if (sourceProp === targetProp) { // source inherits targetProp and doesn't redeclare/override it.
|
||||
|
||||
if (source.flags & TypeFlags.Class && target.flags & TypeFlags.Class) {
|
||||
|
||||
let targetPropFlags = getDeclarationFlagsFromSymbol(targetProp);
|
||||
let sourceDecl = getDeclarationOfKind(source.symbol, SyntaxKind.ClassDeclaration);
|
||||
|
||||
// if target is a class and it has an abstract method, then source, inheriting that method, must be declared abstract.
|
||||
if (targetPropFlags & NodeFlags.Abstract && !(sourceDecl.flags & NodeFlags.Abstract)) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_2,
|
||||
typeToString(source), typeToString(target), symbolToString(targetProp));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
} else { // sourceProp !== targetProp -- ie: source and target have distinct declarations with the same name
|
||||
if (!sourceProp) {
|
||||
if (!(targetProp.flags & SymbolFlags.Optional) || requireOptionalProperties) {
|
||||
if (reportErrors) {
|
||||
|
@ -4571,24 +4588,24 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
else if (!(targetProp.flags & SymbolFlags.Prototype)) {
|
||||
let sourceFlags = getDeclarationFlagsFromSymbol(sourceProp);
|
||||
let targetFlags = getDeclarationFlagsFromSymbol(targetProp);
|
||||
if (sourceFlags & NodeFlags.Private || targetFlags & NodeFlags.Private) {
|
||||
let sourcePropFlags = getDeclarationFlagsFromSymbol(sourceProp);
|
||||
let targetPropFlags = getDeclarationFlagsFromSymbol(targetProp);
|
||||
if (sourcePropFlags & NodeFlags.Private || targetPropFlags & NodeFlags.Private) {
|
||||
if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) {
|
||||
if (reportErrors) {
|
||||
if (sourceFlags & NodeFlags.Private && targetFlags & NodeFlags.Private) {
|
||||
if (sourcePropFlags & NodeFlags.Private && targetPropFlags & NodeFlags.Private) {
|
||||
reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp));
|
||||
}
|
||||
else {
|
||||
reportError(Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp),
|
||||
typeToString(sourceFlags & NodeFlags.Private ? source : target),
|
||||
typeToString(sourceFlags & NodeFlags.Private ? target : source));
|
||||
typeToString(sourcePropFlags & NodeFlags.Private ? source : target),
|
||||
typeToString(sourcePropFlags & NodeFlags.Private ? target : source));
|
||||
}
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
else if (targetFlags & NodeFlags.Protected) {
|
||||
else if (targetPropFlags & NodeFlags.Protected) {
|
||||
let sourceDeclaredInClass = sourceProp.parent && sourceProp.parent.flags & SymbolFlags.Class;
|
||||
let sourceClass = sourceDeclaredInClass ? <InterfaceType>getDeclaredTypeOfSymbol(sourceProp.parent) : undefined;
|
||||
let targetClass = <InterfaceType>getDeclaredTypeOfSymbol(targetProp.parent);
|
||||
|
@ -4600,7 +4617,7 @@ namespace ts {
|
|||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
else if (sourceFlags & NodeFlags.Protected) {
|
||||
else if (sourcePropFlags & NodeFlags.Protected) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2,
|
||||
symbolToString(targetProp), typeToString(source), typeToString(target));
|
||||
|
@ -6637,7 +6654,7 @@ namespace ts {
|
|||
return s.valueDeclaration ? s.valueDeclaration.kind : SyntaxKind.PropertyDeclaration;
|
||||
}
|
||||
|
||||
function getDeclarationFlagsFromSymbol(s: Symbol) {
|
||||
function getDeclarationFlagsFromSymbol(s: Symbol): NodeFlags {
|
||||
return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0;
|
||||
}
|
||||
|
||||
|
@ -10627,6 +10644,9 @@ namespace ts {
|
|||
checkTypeAssignableTo(type, baseType, node.name || node, Diagnostics.Class_0_incorrectly_extends_base_class_1);
|
||||
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node,
|
||||
Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1);
|
||||
|
||||
|
||||
|
||||
if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class)) {
|
||||
// When the static base type is a "class-like" constructor function (but not actually a class), we verify
|
||||
// that all instantiated base constructor signatures return the same type.
|
||||
|
@ -10662,6 +10682,11 @@ namespace ts {
|
|||
}
|
||||
|
||||
forEach(node.members, checkSourceElement);
|
||||
|
||||
// Classes containing abstract members must be marked abstract
|
||||
if (!(node.flags & NodeFlags.Abstract) && forEach(node.members, (element: ClassElement) => element.flags & NodeFlags.Abstract)) {
|
||||
error(node, Diagnostics.Classes_containing_abstract_functions_must_be_marked_abstract);
|
||||
}
|
||||
if (produceDiagnostics) {
|
||||
checkIndexConstraints(type);
|
||||
checkTypeForDuplicateIndexSignatures(node);
|
||||
|
@ -10700,8 +10725,19 @@ namespace ts {
|
|||
}
|
||||
|
||||
let derived = getTargetSymbol(getPropertyOfObjectType(type, base.name));
|
||||
if (derived) {
|
||||
let baseDeclarationFlags = getDeclarationFlagsFromSymbol(base);
|
||||
|
||||
if (!derived) { // derived class inherits base without override/redeclaration
|
||||
let derivedClassDecl = getDeclarationOfKind(type.symbol, SyntaxKind.ClassDeclaration);
|
||||
Debug.assert(derivedClassDecl !== undefined);
|
||||
|
||||
// It is an error to inherit an abstract member without implementing it or being declared abstract.
|
||||
if ((baseDeclarationFlags & NodeFlags.Abstract) && !(derivedClassDecl.flags & NodeFlags.Abstract)) {
|
||||
error(derivedClassDecl, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_2,
|
||||
typeToString(type), typeToString(baseType), symbolToString(baseProperty));
|
||||
}
|
||||
|
||||
} else { // derived !== undefined -- derived overrides base
|
||||
let derivedDeclarationFlags = getDeclarationFlagsFromSymbol(derived);
|
||||
if ((baseDeclarationFlags & NodeFlags.Private) || (derivedDeclarationFlags & NodeFlags.Private)) {
|
||||
// either base or derived property is private - not override, skip it
|
||||
|
|
|
@ -396,6 +396,8 @@ namespace ts {
|
|||
Cannot_create_an_instance_of_the_abstract_class_0: { code: 2511, category: DiagnosticCategory.Error, key: "Cannot create an instance of the abstract class '{0}'." },
|
||||
All_overload_signatures_must_match_with_respect_to_modifier_0: { code: 2512, category: DiagnosticCategory.Error, key: "All overload signatures must match with respect to modifier '{0}'." },
|
||||
Abstract_member_function_0_on_type_1_cannot_be_called_via_super_expression: { code: 2513, category: DiagnosticCategory.Error, key: "Abstract member function '{0}' on type '{1}' cannot be called via super expression." },
|
||||
Classes_containing_abstract_functions_must_be_marked_abstract: { code: 2514, category: DiagnosticCategory.Error, key: "Classes containing abstract functions must be marked abstract." },
|
||||
Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_2: { code: 2515, category: DiagnosticCategory.Error, key: "Non-abstract class '{0}' does not implement inherited abstract member '{1}.{2}'." },
|
||||
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
|
||||
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}'." },
|
||||
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}'." },
|
||||
|
|
|
@ -1571,6 +1571,14 @@
|
|||
"category": "Error",
|
||||
"code": 2513
|
||||
},
|
||||
"Classes containing abstract functions must be marked abstract.": {
|
||||
"category": "Error",
|
||||
"code": 2514
|
||||
},
|
||||
"Non-abstract class '{0}' does not implement inherited abstract member '{1}.{2}'." : {
|
||||
"category": "Error",
|
||||
"code": 2515
|
||||
},
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 4000
|
||||
|
|
Loading…
Reference in a new issue