mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 01:04:49 -05:00
A merged interface with an inherited member should satisfy an abstract base class member (#32539)
* A merged interface with an inherited member should satisfy an abstract base class member * Tighten up comments and names
This commit is contained in:
@@ -29329,7 +29329,7 @@ namespace ts {
|
||||
|
||||
// NOTE: assignability is checked in checkClassDeclaration
|
||||
const baseProperties = getPropertiesOfType(baseType);
|
||||
for (const baseProperty of baseProperties) {
|
||||
basePropertyCheck: for (const baseProperty of baseProperties) {
|
||||
const base = getTargetSymbol(baseProperty);
|
||||
|
||||
if (base.flags & SymbolFlags.Prototype) {
|
||||
@@ -29341,61 +29341,71 @@ namespace ts {
|
||||
|
||||
Debug.assert(!!derived, "derived should point to something, even if it is the base class' declaration.");
|
||||
|
||||
if (derived) {
|
||||
// In order to resolve whether the inherited method was overridden in the base class or not,
|
||||
// we compare the Symbols obtained. Since getTargetSymbol returns the symbol on the *uninstantiated*
|
||||
// type declaration, derived and base resolve to the same symbol even in the case of generic classes.
|
||||
if (derived === base) {
|
||||
// derived class inherits base without override/redeclaration
|
||||
// In order to resolve whether the inherited method was overridden in the base class or not,
|
||||
// we compare the Symbols obtained. Since getTargetSymbol returns the symbol on the *uninstantiated*
|
||||
// type declaration, derived and base resolve to the same symbol even in the case of generic classes.
|
||||
if (derived === base) {
|
||||
// derived class inherits base without override/redeclaration
|
||||
|
||||
const derivedClassDecl = getClassLikeDeclarationOfSymbol(type.symbol)!;
|
||||
const derivedClassDecl = getClassLikeDeclarationOfSymbol(type.symbol)!;
|
||||
|
||||
// It is an error to inherit an abstract member without implementing it or being declared abstract.
|
||||
// If there is no declaration for the derived class (as in the case of class expressions),
|
||||
// then the class cannot be declared abstract.
|
||||
if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !hasModifier(derivedClassDecl, ModifierFlags.Abstract))) {
|
||||
if (derivedClassDecl.kind === SyntaxKind.ClassExpression) {
|
||||
error(derivedClassDecl, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1,
|
||||
symbolToString(baseProperty), typeToString(baseType));
|
||||
}
|
||||
else {
|
||||
error(derivedClassDecl, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2,
|
||||
typeToString(type), symbolToString(baseProperty), typeToString(baseType));
|
||||
// It is an error to inherit an abstract member without implementing it or being declared abstract.
|
||||
// If there is no declaration for the derived class (as in the case of class expressions),
|
||||
// then the class cannot be declared abstract.
|
||||
if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !hasModifier(derivedClassDecl, ModifierFlags.Abstract))) {
|
||||
// Searches other base types for a declaration that would satisfy the inherited abstract member.
|
||||
// (The class may have more than one base type via declaration merging with an interface with the
|
||||
// same name.)
|
||||
for (const otherBaseType of getBaseTypes(type)) {
|
||||
if (otherBaseType === baseType) continue;
|
||||
const baseSymbol = getPropertyOfObjectType(otherBaseType, base.escapedName);
|
||||
const derivedElsewhere = baseSymbol && getTargetSymbol(baseSymbol);
|
||||
if (derivedElsewhere && derivedElsewhere !== base) {
|
||||
continue basePropertyCheck;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// derived overrides base.
|
||||
const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived);
|
||||
if (baseDeclarationFlags & ModifierFlags.Private || derivedDeclarationFlags & ModifierFlags.Private) {
|
||||
// either base or derived property is private - not override, skip it
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isPrototypeProperty(base) || base.flags & SymbolFlags.PropertyOrAccessor && derived.flags & SymbolFlags.PropertyOrAccessor) {
|
||||
// method is overridden with method or property/accessor is overridden with property/accessor - correct case
|
||||
continue;
|
||||
}
|
||||
|
||||
let errorMessage: DiagnosticMessage;
|
||||
if (isPrototypeProperty(base)) {
|
||||
if (derived.flags & SymbolFlags.Accessor) {
|
||||
errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor;
|
||||
}
|
||||
else {
|
||||
errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property;
|
||||
}
|
||||
}
|
||||
else if (base.flags & SymbolFlags.Accessor) {
|
||||
errorMessage = Diagnostics.Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function;
|
||||
if (derivedClassDecl.kind === SyntaxKind.ClassExpression) {
|
||||
error(derivedClassDecl, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1,
|
||||
symbolToString(baseProperty), typeToString(baseType));
|
||||
}
|
||||
else {
|
||||
errorMessage = Diagnostics.Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function;
|
||||
error(derivedClassDecl, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2,
|
||||
typeToString(type), symbolToString(baseProperty), typeToString(baseType));
|
||||
}
|
||||
|
||||
error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// derived overrides base.
|
||||
const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived);
|
||||
if (baseDeclarationFlags & ModifierFlags.Private || derivedDeclarationFlags & ModifierFlags.Private) {
|
||||
// either base or derived property is private - not override, skip it
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isPrototypeProperty(base) || base.flags & SymbolFlags.PropertyOrAccessor && derived.flags & SymbolFlags.PropertyOrAccessor) {
|
||||
// method is overridden with method or property/accessor is overridden with property/accessor - correct case
|
||||
continue;
|
||||
}
|
||||
|
||||
let errorMessage: DiagnosticMessage;
|
||||
if (isPrototypeProperty(base)) {
|
||||
if (derived.flags & SymbolFlags.Accessor) {
|
||||
errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor;
|
||||
}
|
||||
else {
|
||||
errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property;
|
||||
}
|
||||
}
|
||||
else if (base.flags & SymbolFlags.Accessor) {
|
||||
errorMessage = Diagnostics.Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function;
|
||||
}
|
||||
else {
|
||||
errorMessage = Diagnostics.Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function;
|
||||
}
|
||||
|
||||
error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user