Skip to content

Use related spans for "implement abstract class" errors #42546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36173,6 +36173,8 @@ namespace ts {

// NOTE: assignability is checked in checkClassDeclaration
const baseProperties = getPropertiesOfType(baseType);
const derivedClassDecl = getClassLikeDeclarationOfSymbol(type.symbol)!;
const inheritedAbstractMemberNotImplementedErrors: Diagnostic[] = [];
basePropertyCheck: for (const baseProperty of baseProperties) {
const base = getTargetSymbol(baseProperty);

Expand All @@ -36193,7 +36195,6 @@ namespace ts {
// 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)!;

// 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),
Expand All @@ -36212,12 +36213,16 @@ namespace ts {
}

if (derivedClassDecl.kind === SyntaxKind.ClassExpression) {
error(derivedClassDecl, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1,
const err = createDiagnosticForNode(derivedClassDecl,
Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1,
symbolToString(baseProperty), typeToString(baseType));
inheritedAbstractMemberNotImplementedErrors.push(err);
}
else {
error(derivedClassDecl, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2,
const err = createDiagnosticForNode(derivedClassDecl,
Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2,
typeToString(type), symbolToString(baseProperty), typeToString(baseType));
inheritedAbstractMemberNotImplementedErrors.push(err);
}
}
}
Expand Down Expand Up @@ -36293,6 +36298,20 @@ namespace ts {
error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type));
}
}

if (inheritedAbstractMemberNotImplementedErrors.length) {
const err = error(
derivedClassDecl,
Diagnostics.Non_abstract_class_0_does_not_implement_all_abstract_members_of_1,
typeToString(type), typeToString(baseType));

for (const inheritedAbstractMemberNotImplementedError of inheritedAbstractMemberNotImplementedErrors) {
addRelatedInfo(
err,
inheritedAbstractMemberNotImplementedError,
);
}
}
}

function getNonInterhitedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) {
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -6346,5 +6346,9 @@
"Invalid value for 'jsxFragmentFactory'. '{0}' is not a valid identifier or qualified-name.": {
"category": "Error",
"code": 18035
},
"Non-abstract class '{0}' does not implement all abstract members of '{1}'": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the message should be "Non-abstract class '{0}' does not implement all inherited abstract members of '{1}'", to match the old ones

"category": "Error",
"code": 18036
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* @internal */
namespace ts.codefix {
const errorCodes = [
Diagnostics.Non_abstract_class_0_does_not_implement_all_abstract_members_of_1.code,
Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2.code,
Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1.code,
];
Expand Down
19 changes: 7 additions & 12 deletions tests/baselines/reference/abstractPropertyNegative.errors.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
tests/cases/compiler/abstractPropertyNegative.ts(10,18): error TS2380: 'get' and 'set' accessor must have the same type.
tests/cases/compiler/abstractPropertyNegative.ts(11,18): error TS2380: 'get' and 'set' accessor must have the same type.
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'm' from class 'B'.
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'mismatch' from class 'B'.
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'prop' from class 'B'.
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'readonlyProp' from class 'B'.
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS18036: Non-abstract class 'C' does not implement all abstract members of 'B'
tests/cases/compiler/abstractPropertyNegative.ts(15,5): error TS1244: Abstract methods can only appear within an abstract class.
tests/cases/compiler/abstractPropertyNegative.ts(16,37): error TS1005: '{' expected.
tests/cases/compiler/abstractPropertyNegative.ts(19,3): error TS2540: Cannot assign to 'ro' because it is a read-only property.
Expand All @@ -19,7 +16,7 @@ tests/cases/compiler/abstractPropertyNegative.ts(40,9): error TS2676: Accessors
tests/cases/compiler/abstractPropertyNegative.ts(41,18): error TS2676: Accessors must both be abstract or non-abstract.


==== tests/cases/compiler/abstractPropertyNegative.ts (16 errors) ====
==== tests/cases/compiler/abstractPropertyNegative.ts (13 errors) ====
interface A {
prop: string;
m(): string;
Expand All @@ -38,13 +35,11 @@ tests/cases/compiler/abstractPropertyNegative.ts(41,18): error TS2676: Accessors
}
class C extends B {
~
!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'm' from class 'B'.
~
!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'mismatch' from class 'B'.
~
!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'prop' from class 'B'.
~
!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'readonlyProp' from class 'B'.
!!! error TS18036: Non-abstract class 'C' does not implement all abstract members of 'B'
!!! related TS2515 tests/cases/compiler/abstractPropertyNegative.ts:13:7: Non-abstract class 'C' does not implement inherited abstract member 'prop' from class 'B'.
!!! related TS2515 tests/cases/compiler/abstractPropertyNegative.ts:13:7: Non-abstract class 'C' does not implement inherited abstract member 'readonlyProp' from class 'B'.
!!! related TS2515 tests/cases/compiler/abstractPropertyNegative.ts:13:7: Non-abstract class 'C' does not implement inherited abstract member 'm' from class 'B'.
!!! related TS2515 tests/cases/compiler/abstractPropertyNegative.ts:13:7: Non-abstract class 'C' does not implement inherited abstract member 'mismatch' from class 'B'.
readonly ro = "readonly please";
abstract notAllowed: string;
~~~~~~~~
Expand Down
15 changes: 9 additions & 6 deletions tests/baselines/reference/classAbstractDeclarations.d.errors.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(2,5): error TS1242: 'abstract' modifier can only appear on a class, method, or property declaration.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(2,28): error TS1183: An implementation cannot be declared in ambient contexts.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(11,15): error TS2515: Non-abstract class 'CC' does not implement inherited abstract member 'foo' from class 'AA'.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(13,15): error TS2515: Non-abstract class 'DD' does not implement inherited abstract member 'foo' from class 'BB'.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(17,15): error TS2515: Non-abstract class 'FF' does not implement inherited abstract member 'foo' from class 'CC'.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(11,15): error TS18036: Non-abstract class 'CC' does not implement all abstract members of 'AA'
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(13,15): error TS18036: Non-abstract class 'DD' does not implement all abstract members of 'BB'
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(17,15): error TS18036: Non-abstract class 'FF' does not implement all abstract members of 'CC'


==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts (5 errors) ====
Expand All @@ -22,17 +22,20 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst

declare class CC extends AA {}
~~
!!! error TS2515: Non-abstract class 'CC' does not implement inherited abstract member 'foo' from class 'AA'.
!!! error TS18036: Non-abstract class 'CC' does not implement all abstract members of 'AA'
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts:11:15: Non-abstract class 'CC' does not implement inherited abstract member 'foo' from class 'AA'.

declare class DD extends BB {}
~~
!!! error TS2515: Non-abstract class 'DD' does not implement inherited abstract member 'foo' from class 'BB'.
!!! error TS18036: Non-abstract class 'DD' does not implement all abstract members of 'BB'
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts:13:15: Non-abstract class 'DD' does not implement inherited abstract member 'foo' from class 'BB'.

declare abstract class EE extends BB {}

declare class FF extends CC {}
~~
!!! error TS2515: Non-abstract class 'FF' does not implement inherited abstract member 'foo' from class 'CC'.
!!! error TS18036: Non-abstract class 'FF' does not implement all abstract members of 'CC'
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts:17:15: Non-abstract class 'FF' does not implement inherited abstract member 'foo' from class 'CC'.

declare abstract class GG extends CC {}

Expand Down
5 changes: 3 additions & 2 deletions tests/baselines/reference/classAbstractExtends.errors.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts(9,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'bar' from class 'B'.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts(9,7): error TS18036: Non-abstract class 'C' does not implement all abstract members of 'B'


==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts (1 errors) ====
Expand All @@ -12,7 +12,8 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst

class C extends B { }
~
!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'bar' from class 'B'.
!!! error TS18036: Non-abstract class 'C' does not implement all abstract members of 'B'
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts:9:7: Non-abstract class 'C' does not implement inherited abstract member 'bar' from class 'B'.

abstract class D extends B {}

Expand Down
30 changes: 15 additions & 15 deletions tests/baselines/reference/classAbstractGeneric.errors.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(10,7): error TS2515: Non-abstract class 'C<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(10,7): error TS2515: Non-abstract class 'C<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(12,7): error TS2515: Non-abstract class 'D' does not implement inherited abstract member 'bar' from class 'A<number>'.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(12,7): error TS2515: Non-abstract class 'D' does not implement inherited abstract member 'foo' from class 'A<number>'.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(14,7): error TS2515: Non-abstract class 'E<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(18,7): error TS2515: Non-abstract class 'F<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(10,7): error TS18036: Non-abstract class 'C<T>' does not implement all abstract members of 'A<T>'
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(12,7): error TS18036: Non-abstract class 'D' does not implement all abstract members of 'A<number>'
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(14,7): error TS18036: Non-abstract class 'E<T>' does not implement all abstract members of 'A<T>'
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(18,7): error TS18036: Non-abstract class 'F<T>' does not implement all abstract members of 'A<T>'


==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts (6 errors) ====
==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts (4 errors) ====
abstract class A<T> {
t: T;

Expand All @@ -18,25 +16,27 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst

class C<T> extends A<T> {} // error -- inherits abstract methods
~
!!! error TS2515: Non-abstract class 'C<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
~
!!! error TS2515: Non-abstract class 'C<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
!!! error TS18036: Non-abstract class 'C<T>' does not implement all abstract members of 'A<T>'
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:10:7: Non-abstract class 'C<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:10:7: Non-abstract class 'C<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.

class D extends A<number> {} // error -- inherits abstract methods
~
!!! error TS2515: Non-abstract class 'D' does not implement inherited abstract member 'bar' from class 'A<number>'.
~
!!! error TS2515: Non-abstract class 'D' does not implement inherited abstract member 'foo' from class 'A<number>'.
!!! error TS18036: Non-abstract class 'D' does not implement all abstract members of 'A<number>'
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:12:7: Non-abstract class 'D' does not implement inherited abstract member 'foo' from class 'A<number>'.
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:12:7: Non-abstract class 'D' does not implement inherited abstract member 'bar' from class 'A<number>'.

class E<T> extends A<T> { // error -- doesn't implement bar
~
!!! error TS2515: Non-abstract class 'E<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
!!! error TS18036: Non-abstract class 'E<T>' does not implement all abstract members of 'A<T>'
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:14:7: Non-abstract class 'E<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
foo() { return this.t; }
}

class F<T> extends A<T> { // error -- doesn't implement foo
~
!!! error TS2515: Non-abstract class 'F<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
!!! error TS18036: Non-abstract class 'F<T>' does not implement all abstract members of 'A<T>'
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:18:7: Non-abstract class 'F<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
bar(t : T) {}
}

Expand Down
Loading