Skip to content

Improve error message for conflicting definitions #23453

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
merged 3 commits into from
Jul 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2333,7 +2333,9 @@ class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(using C
extends NamingMsg(DoubleDefinitionID) {
def msg(using Context) = {
def nameAnd = if (decl.name != previousDecl.name) " name and" else ""
def erasedType = if ctx.erasedTypes then i" ${decl.info}" else ""
def erasedType: Type =
if ctx.erasedTypes then decl.info
else TypeErasure.transformInfo(decl, decl.info)
def details(using Context): String =
if (decl.isRealMethod && previousDecl.isRealMethod) {
import Signature.MatchDegree.*
Expand Down Expand Up @@ -2361,7 +2363,7 @@ extends NamingMsg(DoubleDefinitionID) {
|Consider adding a @targetName annotation to one of the conflicting definitions
|for disambiguation."""
else ""
i"have the same$nameAnd type$erasedType after erasure.$hint"
i"have the same$nameAnd type $erasedType after erasure.$hint"
}
}
else ""
Expand All @@ -2374,7 +2376,7 @@ extends NamingMsg(DoubleDefinitionID) {
}
val clashDescription =
if (decl.owner eq previousDecl.owner)
"Double definition"
"Conflicting definitions"
else if ((decl.owner eq base) || (previousDecl eq base))
"Name clash between defined and inherited member"
else
Expand Down Expand Up @@ -3538,4 +3540,4 @@ final class NamedPatternNotApplicable(selectorType: Type)(using Context) extends
override protected def msg(using Context): String =
i"Named patterns cannot be used with $selectorType, because it is not a named tuple or case class"

override protected def explain(using Context): String = ""
override protected def explain(using Context): String = ""
3 changes: 3 additions & 0 deletions compiler/test/dotc/neg-best-effort-unpickling.excludelist
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ i22357a.scala

# `110 (of class java.lang.Integer)`
context-function-syntax.scala

# Failure to disambiguate overloaded reference
i23402b.scala
44 changes: 22 additions & 22 deletions tests/neg/doubleDefinition.check
Original file line number Diff line number Diff line change
@@ -1,130 +1,130 @@
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:14:5 ----------------------------------------------------------
14 | def foo(x: List[B]): Function1[B, B] = ??? // error: same jvm signature
| ^
| Double definition:
| Conflicting definitions:
| def foo(x: List[A]): A => A in class Test2 at line 13 and
| def foo(x: List[B]): B => B in class Test2 at line 14
| have the same type after erasure.
| have the same type (x: List): Function1 after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:21:5 ----------------------------------------------------------
21 | def foo(x: List[A]): Function2[B, B, B] = ??? // error
| ^
| Double definition:
| Conflicting definitions:
| def foo(x: List[A]): A => A in class Test3 at line 20 and
| def foo(x: List[A]): (B, B) => B in class Test3 at line 21
| have matching parameter types.
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:26:5 ----------------------------------------------------------
26 | def foo = 2 // error
| ^
| Double definition:
| Conflicting definitions:
| val foo: Int in class Test4 at line 25 and
| def foo: Int in class Test4 at line 26
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:31:5 ----------------------------------------------------------
31 | val foo = 1 // error
| ^
| Double definition:
| Conflicting definitions:
| def foo: Int in class Test4b at line 30 and
| val foo: Int in class Test4b at line 31
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:36:5 ----------------------------------------------------------
36 | var foo = 1 // error
| ^
| Double definition:
| Conflicting definitions:
| def foo: Int in class Test4c at line 35 and
| var foo: Int in class Test4c at line 36
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:41:5 ----------------------------------------------------------
41 | def foo = 2 // error
| ^
| Double definition:
| Conflicting definitions:
| var foo: Int in class Test4d at line 40 and
| def foo: Int in class Test4d at line 41
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:55:5 ----------------------------------------------------------
55 | def foo(x: List[B]): Function1[B, B] = ??? // error: same jvm signature
| ^
| Double definition:
| Conflicting definitions:
| def foo(x: List[A]): A => A in trait Test6 at line 54 and
| def foo(x: List[B]): B => B in trait Test6 at line 55
| have the same type after erasure.
| have the same type (x: List): Function1 after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:62:5 ----------------------------------------------------------
62 | def foo(x: List[A]): Function2[B, B, B] = ??? // error
| ^
| Double definition:
| Conflicting definitions:
| def foo(x: List[A]): A => A in trait Test7 at line 61 and
| def foo(x: List[A]): (B, B) => B in trait Test7 at line 62
| have matching parameter types.
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:67:5 ----------------------------------------------------------
67 | def foo = 2 // error
| ^
| Double definition:
| Conflicting definitions:
| val foo: Int in class Test8 at line 66 and
| def foo: Int in class Test8 at line 67
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:72:5 ----------------------------------------------------------
72 | val foo = 1 // error
| ^
| Double definition:
| Conflicting definitions:
| def foo: Int in class Test8b at line 71 and
| val foo: Int in class Test8b at line 72
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:77:5 ----------------------------------------------------------
77 | var foo = 1 // error
| ^
| Double definition:
| Conflicting definitions:
| def foo: Int in class Test8c at line 76 and
| var foo: Int in class Test8c at line 77
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:82:5 ----------------------------------------------------------
82 | def foo = 2 // error
| ^
| Double definition:
| Conflicting definitions:
| var foo: Int in class Test8d at line 81 and
| def foo: Int in class Test8d at line 82
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:88:5 ----------------------------------------------------------
88 | def foo: String // error
| ^
| Double definition:
| Conflicting definitions:
| val foo: Int in class Test9 at line 87 and
| def foo: String in class Test9 at line 88
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:92:5 ----------------------------------------------------------
92 | def foo: Int // error
| ^
| Double definition:
| Conflicting definitions:
| val foo: Int in class Test10 at line 91 and
| def foo: Int in class Test10 at line 92
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:96:5 ----------------------------------------------------------
96 | def foo: String // error
| ^
| Double definition:
| Conflicting definitions:
| val foo: Int in class Test11 at line 95 and
| def foo: String in class Test11 at line 96
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:100:5 ---------------------------------------------------------
100 | def foo: Int // error
| ^
| Double definition:
| Conflicting definitions:
| val foo: Int in class Test12 at line 99 and
| def foo: Int in class Test12 at line 100
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:104:5 ---------------------------------------------------------
104 | def foo: String // error
| ^
| Double definition:
| Conflicting definitions:
| var foo: Int in class Test13 at line 103 and
| def foo: String in class Test13 at line 104
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:108:5 ---------------------------------------------------------
108 | def foo: Int // error
| ^
| Double definition:
| Conflicting definitions:
| var foo: Int in class Test14 at line 107 and
| def foo: Int in class Test14 at line 108
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:112:5 ---------------------------------------------------------
112 | def foo: String // error
| ^
| Double definition:
| Conflicting definitions:
| var foo: Int in class Test15 at line 111 and
| def foo: String in class Test15 at line 112
-- [E120] Naming Error: tests/neg/doubleDefinition.scala:116:5 ---------------------------------------------------------
116 | def foo: Int // error
| ^
| Double definition:
| Conflicting definitions:
| var foo: Int in class Test16 at line 115 and
| def foo: Int in class Test16 at line 116
14 changes: 7 additions & 7 deletions tests/neg/exports.check
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,30 @@
-- [E120] Naming Error: tests/neg/exports.scala:23:33 ------------------------------------------------------------------
23 | export printUnit.{stat => _, _} // error: double definition
| ^
| Double definition:
| Conflicting definitions:
| def status: List[String] in class Copier at line 28 and
| final def status: List[String] in class Copier at line 23
| have the same type after erasure.
| have the same type (): List after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
-- [E120] Naming Error: tests/neg/exports.scala:24:20 ------------------------------------------------------------------
24 | export scanUnit._ // error: double definition
| ^
| Double definition:
| Conflicting definitions:
| final def status: List[String] in class Copier at line 23 and
| final def status: List[String] in class Copier at line 24
| have the same type after erasure.
| have the same type (): List after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
-- [E120] Naming Error: tests/neg/exports.scala:26:21 ------------------------------------------------------------------
26 | export printUnit.status // error: double definition
| ^
| Double definition:
| Conflicting definitions:
| final def status: List[String] in class Copier at line 24 and
| final def status: List[String] in class Copier at line 26
| have the same type after erasure.
| have the same type (): List after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
Expand All @@ -55,7 +55,7 @@
-- [E120] Naming Error: tests/neg/exports.scala:46:15 ------------------------------------------------------------------
46 | export bar._ // error: double definition
| ^
| Double definition:
| Conflicting definitions:
| val bar: Bar in class Baz at line 45 and
| final def bar: (Baz.this.bar.bar : => (Baz.this.bar.baz.bar : Bar)) in class Baz at line 46
-- [E083] Type Error: tests/neg/exports.scala:57:11 --------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i14966a.check
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- [E120] Naming Error: tests/neg/i14966a.scala:3:6 --------------------------------------------------------------------
3 | def f(x: List[Int]): String = ??? // error
| ^
| Double definition:
| Conflicting definitions:
| def f[X <: String](x: List[X]): String in class Test at line 2 and
| def f(x: List[Int]): String in class Test at line 3
| have the same type (x: scala.collection.immutable.List): String after erasure.
Expand Down
4 changes: 2 additions & 2 deletions tests/neg/i19809.check
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
-- [E120] Naming Error: tests/neg/i19809.scala:3:6 ---------------------------------------------------------------------
3 | def x_=(x: Int): Unit // error
| ^
| Double definition:
| Conflicting definitions:
| def x_=(x$1: Int): Unit in trait <refinement> at line 2 and
| def x_=(x: Int): Unit in trait <refinement> at line 3
| have the same type after erasure.
| have the same type (x: Int): Unit after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
10 changes: 10 additions & 0 deletions tests/neg/i23402.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- [E120] Naming Error: tests/neg/i23402.scala:4:5 ---------------------------------------------------------------------
4 | def apply(p1: String)(p2: Int): A = A(p1, p2) // error
| ^
| Conflicting definitions:
| def apply(p1: String, p2: Int): A in object A at line 3 and
| def apply(p1: String)(p2: Int): A in object A at line 4
| have the same type (p1: String, p2: Int): A after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
5 changes: 5 additions & 0 deletions tests/neg/i23402.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class A(p1: String, p2: Int)
object A {
def apply(p1: String, p2: Int): A = A(p1, p2)
def apply(p1: String)(p2: Int): A = A(p1, p2) // error
}
10 changes: 10 additions & 0 deletions tests/neg/i23402b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- [E120] Naming Error: tests/neg/i23402b.scala:4:5 --------------------------------------------------------------------
4 | def apply[T](p1: String)(p2: Int): A = A(p1, p2) // error
| ^
| Conflicting definitions:
| def apply[T](p1: String, p2: Int): A in object A at line 3 and
| def apply[T](p1: String)(p2: Int): A in object A at line 4
| have the same type (p1: String, p2: Int): A after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
5 changes: 5 additions & 0 deletions tests/neg/i23402b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class A(p1: String, p2: Int)
object A {
def apply[T](p1: String, p2: Int): A = A(p1, p2)
def apply[T](p1: String)(p2: Int): A = A(p1, p2) // error
}
10 changes: 10 additions & 0 deletions tests/neg/i23402c.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- [E120] Naming Error: tests/neg/i23402c.scala:4:5 --------------------------------------------------------------------
4 | def apply[T](p1: String)(p2: Int): A = A(p1, p2) // error
| ^
| Conflicting definitions:
| def apply(p1: String, p2: Int): A in object A at line 3 and
| def apply[T](p1: String)(p2: Int): A in object A at line 4
| have the same type (p1: String, p2: Int): A after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
5 changes: 5 additions & 0 deletions tests/neg/i23402c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class A(p1: String, p2: Int)
object A {
def apply(p1: String, p2: Int): A = A(p1, p2)
def apply[T](p1: String)(p2: Int): A = A(p1, p2) // error
}
2 changes: 1 addition & 1 deletion tests/neg/i7359-f.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
| Name clash between inherited members:
| def equals[T >: Boolean <: Boolean](obj: Any): T in trait SAMTrait at line 3 and
| def equals(x$0: Any): Boolean in class Any
| have the same type after erasure.
| have the same type (x$0: Object): Boolean after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
6 changes: 3 additions & 3 deletions tests/neg/into-override.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
| Name clash between defined and inherited member:
| def f(x: X): Unit in trait A at line 11 and
| override def f(x: Conversion.into[X]): Unit in trait C at line 17
| have the same type after erasure.
| have the same type (x: Object): Unit after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
Expand All @@ -14,7 +14,7 @@
| Name clash between inherited members:
| override def f(x: X): Unit in trait B at line 14 and
| override def f(x: Conversion.into[X]): Unit in trait C at line 17
| have the same type after erasure.
| have the same type (x: Object): Unit after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
Expand All @@ -24,7 +24,7 @@
| Name clash between defined and inherited member:
| override def f(x: Conversion.into[X]): Unit in trait C at line 17 and
| override def f(x: X): Unit in trait E at line 22
| have the same type after erasure.
| have the same type (x: Object): Unit after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
2 changes: 1 addition & 1 deletion tests/neg/mixin-forwarder-clash1.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
| Name clash between inherited members:
| def concat(suffix: Int): X in trait One at line 4 and
| def concat[Dummy](suffix: Int): Y in trait Two at line 8
| have the same type after erasure.
| have the same type (suffix: Int): Object after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
2 changes: 1 addition & 1 deletion tests/neg/mixin-forwarder-clash2.check
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
| Name clash between inherited members:
| def concat(suffix: Int): X in trait One at line 4 and
| def concat[Dummy](suffix: Int): Y in trait Two at line 8
| have the same type after erasure.
| have the same type (suffix: Int): Object after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
2 changes: 1 addition & 1 deletion tests/neg/override-erasure-clash.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
| Name clash between defined and inherited member:
| def f(): Int in class A at line 3 and
| def g(): Int in class B at line 5
| have the same name and type after erasure.
| have the same name and type (): Int after erasure.
4 changes: 2 additions & 2 deletions tests/neg/type-params.check
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@
-- [E120] Naming Error: tests/neg/type-params.scala:44:6 ---------------------------------------------------------------
44 | def a = (p: A) => () // error
| ^
| Double definition:
| Conflicting definitions:
| def a: () => Unit in trait t278 at line 43 and
| def a: t278.this.A => Unit in trait t278 at line 44
| have the same type after erasure.
| have the same type (): Function1 after erasure.
|
| Consider adding a @targetName annotation to one of the conflicting definitions
| for disambiguation.
Expand Down
Loading