Skip to content

Commit 8bdc91f

Browse files
ennrufelixmulder
authored andcommitted
Change 'overrides nothing' to report via Message (see #1965) (#1968)
* Change 'overrides nothing' to report via Message, split into two different messages * Change 'overrides nothing' to report via Message, split into two different messages
1 parent e360c2a commit 8bdc91f

File tree

4 files changed

+98
-6
lines changed

4 files changed

+98
-6
lines changed

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,4 +1002,36 @@ object messages {
10021002
|${typeCode}
10031003
|"""
10041004
}
1005+
1006+
case class OverridesNothing(member: Symbol)(implicit ctx: Context)
1007+
extends Message(37) {
1008+
val kind = "Reference"
1009+
val msg = hl"""${member} overrides nothing"""
1010+
1011+
val explanation =
1012+
hl"""|There must be a field or method with the name `${member.name}` in a super
1013+
|class of `${member.owner}` to override it. Did you misspell it?
1014+
|Are you extending the right classes?
1015+
|"""
1016+
}
1017+
1018+
case class OverridesNothingButNameExists(member: Symbol, existing: List[Denotations.SingleDenotation])(implicit ctx: Context)
1019+
extends Message(38) {
1020+
val kind = "Reference"
1021+
val msg = hl"""${member} has a different signature than the overridden declaration"""
1022+
1023+
val existingDecl = existing.map(_.showDcl).mkString(" \n")
1024+
1025+
val explanation =
1026+
hl"""|There must be a non-final field or method with the name `${member.name}` and the
1027+
|same parameter list in a super class of `${member.owner}` to override it.
1028+
|
1029+
| ${member.showDcl}
1030+
|
1031+
|The super classes of `${member.owner}` contain the following members
1032+
|named `${member.name}`:
1033+
| ${existingDecl}
1034+
|"""
1035+
}
1036+
10051037
}

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import DenotTransformers._
2121

2222
object RefChecks {
2323
import tpd._
24+
import reporting.diagnostic.Message
25+
import reporting.diagnostic.messages._
26+
2427

2528
private def isDefaultGetter(name: Name): Boolean =
2629
name.isTermName && name.asTermName.defaultGetterIndex >= 0
@@ -622,15 +625,12 @@ object RefChecks {
622625
if (member.isAnyOverride && !(clazz.thisType.baseClasses exists (hasMatchingSym(_, member)))) {
623626
// for (bc <- clazz.info.baseClasses.tail) Console.println("" + bc + " has " + bc.info.decl(member.name) + ":" + bc.info.decl(member.name).tpe);//DEBUG
624627

625-
val nonMatching = clazz.info.member(member.name).altsWith(alt => alt.owner != clazz && !alt.is(Final))
626-
def issueError(suffix: String) =
627-
ctx.error(i"$member overrides nothing$suffix", member.pos)
628+
val nonMatching = clazz.info.member(member.name).altsWith(alt => alt.owner != clazz)
628629
nonMatching match {
629630
case Nil =>
630-
issueError("")
631+
ctx.error(OverridesNothing(member), member.pos)
631632
case ms =>
632-
val superSigs = ms.map(_.showDcl).mkString("\n")
633-
issueError(s".\nNote: the super classes of ${member.owner} contain the following, non final members named ${member.name}:\n${superSigs}")
633+
ctx.error(OverridesNothingButNameExists(member, ms), member.pos)
634634
}
635635
member.resetFlag(Override)
636636
member.resetFlag(AbsOverride)

compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,47 @@ class ErrorMessagesTests extends ErrorMessagesTest {
4242
// is a type reference to `java.lang.String`
4343
assert(expected.dealias =:= defn.StringType, s"expected was: $expected")
4444
}
45+
46+
@Test def overridesNothing =
47+
checkMessagesAfter("refchecks") {
48+
"""
49+
|object Foo {
50+
| override def bar: Unit = {}
51+
|}
52+
""".stripMargin
53+
}
54+
.expect { (ictx, messages) =>
55+
implicit val ctx: Context = ictx
56+
val defn = ictx.definitions
57+
58+
assertMessageCount(1, messages)
59+
val OverridesNothing(member) :: Nil = messages
60+
assertEquals("bar", member.name.show)
61+
}
62+
63+
@Test def overridesNothingDifferentSignature =
64+
checkMessagesAfter("refchecks") {
65+
"""
66+
|class Bar {
67+
| def bar(s: String): Unit = {}
68+
| def bar(s: Int): Unit = {}
69+
| final def bar(s: Long): Unit = {}
70+
|}
71+
|object Foo extends Bar {
72+
| override def bar: Unit = {}
73+
|}
74+
""".stripMargin
75+
}
76+
.expect { (ictx, messages) =>
77+
implicit val ctx: Context = ictx
78+
val defn = ictx.definitions
79+
80+
assertMessageCount(1, messages)
81+
val OverridesNothingButNameExists(member, sameName) :: Nil = messages
82+
// check expected context data
83+
assertEquals("bar", member.name.show)
84+
assertEquals(3, sameName.size)
85+
assert(sameName.forall(_.symbol.name.show == "bar"),
86+
"at least one method had an unexpected name")
87+
}
4588
}

tests/repl/overrides.check

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
scala> class B { override def foo(i: Int): Unit = {}; }
2+
-- [E037] Reference Error: <console> -------------------------------------------
3+
4 |class B { override def foo(i: Int): Unit = {}; }
4+
| ^
5+
| method foo overrides nothing
6+
7+
longer explanation available when compiling with `-explain`
8+
scala> class A { def foo: Unit = {}; }
9+
defined class A
10+
scala> class B extends A { override def foo(i: Int): Unit = {}; }
11+
-- [E038] Reference Error: <console> -------------------------------------------
12+
5 |class B extends A { override def foo(i: Int): Unit = {}; }
13+
| ^
14+
| method foo has a different signature than the overridden declaration
15+
16+
longer explanation available when compiling with `-explain`
17+
scala> :quit

0 commit comments

Comments
 (0)