From 0948a0583e7b0fa95f11f0f3cc113c70e6e1448c Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Mon, 1 Sep 2025 16:34:20 +0000 Subject: [PATCH] Compute the right span for abstract error messages Co-authored-by: HarrisL2 Co-authored-by: kalil0321 --- compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 11 ++++++++++- tests/neg/i10666.check | 2 +- tests/neg/i12828.check | 2 +- tests/neg/i13466.check | 2 +- tests/neg/i19731.check | 6 +++--- tests/neg/i21335.check | 4 ++-- tests/neg/i22941.check | 4 ++++ tests/neg/i22941.scala | 5 +++++ tests/neg/i9329.check | 2 +- tests/neg/targetName-override.check | 2 +- 10 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 tests/neg/i22941.check create mode 100644 tests/neg/i22941.scala diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index a79408b756ee..2d178e2f3773 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -329,6 +329,15 @@ object RefChecks { val mixinOverrideErrors = new mutable.ListBuffer[MixinOverrideError]() + /** Returns a `SourcePosition` containing the full span (with the correct + * end) of the class name. */ + def clazzNamePos = + if clazz.name == tpnme.ANON_CLASS then + clazz.srcPos + else + val clazzNameEnd = clazz.srcPos.span.start + clazz.name.stripModuleClassSuffix.lastPart.length + clazz.srcPos.sourcePos.copy(span = clazz.srcPos.span.withEnd(clazzNameEnd)) + def printMixinOverrideErrors(): Unit = mixinOverrideErrors.toList match { case Nil => @@ -914,7 +923,7 @@ object RefChecks { checkNoAbstractDecls(clazz) if (abstractErrors.nonEmpty) - report.error(abstractErrorMessage, clazz.srcPos) + report.error(abstractErrorMessage, clazzNamePos) checkMemberTypesOK() checkCaseClassInheritanceInvariant() diff --git a/tests/neg/i10666.check b/tests/neg/i10666.check index a70aa9815dc5..491b88f1ffa5 100644 --- a/tests/neg/i10666.check +++ b/tests/neg/i10666.check @@ -1,6 +1,6 @@ -- Error: tests/neg/i10666.scala:8:6 ----------------------------------------------------------------------------------- 8 |class Bar extends Foo { // error - | ^ + | ^^^ | class Bar needs to be abstract, since def foo[T <: B](tx: T): Unit in trait Foo is not defined | (Note that | parameter T in def foo[T <: B](tx: T): Unit in trait Foo does not match diff --git a/tests/neg/i12828.check b/tests/neg/i12828.check index 070633fc35b3..e2a1cdb92dcd 100644 --- a/tests/neg/i12828.check +++ b/tests/neg/i12828.check @@ -1,6 +1,6 @@ -- Error: tests/neg/i12828.scala:7:7 ----------------------------------------------------------------------------------- 7 |object Baz extends Bar[Int] // error: not implemented - | ^ + | ^^^ | object creation impossible, since def foo(x: A): Unit in trait Foo is not defined | (Note that | parameter A in def foo(x: A): Unit in trait Foo does not match diff --git a/tests/neg/i13466.check b/tests/neg/i13466.check index a15ae059427f..ad097ddae96b 100644 --- a/tests/neg/i13466.check +++ b/tests/neg/i13466.check @@ -1,6 +1,6 @@ -- Error: tests/neg/i13466.scala:9:6 ----------------------------------------------------------------------------------- 9 |given none: SomeTrait[Finally] with {} // error - | ^ + | ^^^^ | object creation impossible, since: | it has 3 unimplemented members. | /** As seen from module class none$, the missing signatures are as follows. diff --git a/tests/neg/i19731.check b/tests/neg/i19731.check index eebfb924d199..5c6ef5246b1d 100644 --- a/tests/neg/i19731.check +++ b/tests/neg/i19731.check @@ -1,10 +1,10 @@ -- Error: tests/neg/i19731.scala:4:6 ----------------------------------------------------------------------------------- 4 |class F1 extends Foo: // error - | ^ + | ^^ | class F1 needs to be abstract, since def foo(): Unit in class F1 is not defined -- Error: tests/neg/i19731.scala:7:6 ----------------------------------------------------------------------------------- 7 |class F2 extends Foo: // error - | ^ + | ^^ | class F2 needs to be abstract, since: | it has 2 unimplemented members. | /** As seen from class F2, the missing signatures are as follows. @@ -14,7 +14,7 @@ | def foo(x: Int): Unit = ??? -- Error: tests/neg/i19731.scala:16:6 ---------------------------------------------------------------------------------- 16 |class B1 extends Bar: // error - | ^ + | ^^ | class B1 needs to be abstract, since: | it has 2 unimplemented members. | /** As seen from class B1, the missing signatures are as follows. diff --git a/tests/neg/i21335.check b/tests/neg/i21335.check index a7ee092eec0e..ae2e09df1f61 100644 --- a/tests/neg/i21335.check +++ b/tests/neg/i21335.check @@ -1,8 +1,8 @@ -- Error: tests/neg/i21335.scala:7:6 ----------------------------------------------------------------------------------- 7 |class Z1 extends Bar1 // error - | ^ + | ^^ | class Z1 needs to be abstract, since override def bar(): Bar1 in trait Bar1 is not defined -- Error: tests/neg/i21335.scala:12:6 ---------------------------------------------------------------------------------- 12 |class Z2 extends Bar2 // error - | ^ + | ^^ | class Z2 needs to be abstract, since def bar(): Bar2 in trait Bar2 is not defined diff --git a/tests/neg/i22941.check b/tests/neg/i22941.check new file mode 100644 index 000000000000..81edebd098d3 --- /dev/null +++ b/tests/neg/i22941.check @@ -0,0 +1,4 @@ +-- Error: tests/neg/i22941.scala:4:6 ----------------------------------------------------------------------------------- +4 |class Baz extends Foo: // error + | ^^^ + | class Baz needs to be abstract, since def bar: String in trait Foo is not defined diff --git a/tests/neg/i22941.scala b/tests/neg/i22941.scala new file mode 100644 index 000000000000..3e8eb39777ab --- /dev/null +++ b/tests/neg/i22941.scala @@ -0,0 +1,5 @@ +trait Foo: + def bar: String + +class Baz extends Foo: // error + val a = "hello" diff --git a/tests/neg/i9329.check b/tests/neg/i9329.check index 7e4968edf607..e604a1b22888 100644 --- a/tests/neg/i9329.check +++ b/tests/neg/i9329.check @@ -1,5 +1,5 @@ -- Error: tests/neg/i9329.scala:8:6 ------------------------------------------------------------------------------------ 8 |class GrandSon extends Son // error - | ^ + | ^^^^^^^^ |class GrandSon needs to be abstract, since def name: String in trait Parent is not defined |(The class implements abstract override def name: String in trait Son but that definition still needs an implementation) diff --git a/tests/neg/targetName-override.check b/tests/neg/targetName-override.check index 2d21e8cbfbd4..230b7fe77745 100644 --- a/tests/neg/targetName-override.check +++ b/tests/neg/targetName-override.check @@ -15,5 +15,5 @@ | method ++ of type (xs: Alpha[String]): Alpha[String] misses a target name annotation @targetName(append) -- Error: tests/neg/targetName-override.scala:14:6 --------------------------------------------------------------------- 14 |class Beta extends Alpha[String] { // error: needs to be abstract - | ^ + | ^^^^ |class Beta needs to be abstract, since there is a deferred declaration of method foo in class Alpha of type (x: String): String which is not implemented in a subclass