diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 880c8add64cf..60aeb43a9b32 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -2364,7 +2364,7 @@ class SymbolIsNotAValue(symbol: Symbol)(using Context) extends TypeMsg(SymbolIsN } class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(using Context) -extends NamingMsg(DoubleDefinitionID) { +extends NamingMsg(DoubleDefinitionID): import Signature.MatchDegree.* private def erasedType: Type = @@ -2426,6 +2426,25 @@ extends NamingMsg(DoubleDefinitionID) { } + details } def explain(using Context) = + def givenAddendum = + def isGivenName(sym: Symbol) = sym.name.startsWith("given_") // Desugar.inventGivenName + def print(tpe: Type): String = + def addParams(tpe: Type): List[String] = tpe match + case tpe: MethodType => + val s = if tpe.isContextualMethod then i"(${tpe.paramInfos}%, %) =>" else "" + s :: addParams(tpe.resType) + case tpe: PolyType => + i"[${tpe.paramNames}%, %] =>" :: addParams(tpe.resType) + case tpe => + i"$tpe" :: Nil + addParams(tpe).mkString(" ") + if decl.is(Given) && previousDecl.is(Given) && isGivenName(decl) && isGivenName(previousDecl) then + i"""| Provide an explicit, unique name to given definitions, + | since the names assigned to anonymous givens may clash. For example: + | + | given myGiven: ${print(atPhase(typerPhase)(decl.info))} + |""" + else "" decl.signature.matchDegree(previousDecl.signature) match case FullMatch => i""" @@ -2439,8 +2458,8 @@ extends NamingMsg(DoubleDefinitionID) { | |In your code the two declarations | - | ${previousDecl.showDcl} - | ${decl.showDcl} + | ${atPhase(typerPhase)(previousDecl.showDcl)} + | ${atPhase(typerPhase)(decl.showDcl)} | |erase to the identical signature | @@ -2448,21 +2467,20 @@ extends NamingMsg(DoubleDefinitionID) { | |so the compiler cannot keep both: the generated bytecode symbols would collide. | - |To fix this error, you need to disambiguate the two definitions. You can either: + |To fix this error, you must disambiguate the two definitions by doing one of the following: | - |1. Rename one of the definitions, or + |1. Rename one of the definitions.$givenAddendum |2. Keep the same names in source but give one definition a distinct - | bytecode-level name via `@targetName` for example: + | bytecode-level name via `@targetName`; for example: | | @targetName("${decl.name.show}_2") - | ${decl.showDcl} + | ${atPhase(typerPhase)(decl.showDcl)} | |Choose the `@targetName` argument carefully: it is the name that will be used |when calling the method externally, so it should be unique and descriptive. - """ + |""" case _ => "" - -} +end DoubleDefinition class ImportedTwice(sel: Name)(using Context) extends SyntaxMsg(ImportedTwiceID) { def msg(using Context) = s"${sel.show} is imported twice on the same import line." diff --git a/tests/neg/i23350.check b/tests/neg/i23350.check index d9ae6a99cdca..ac64b3d22c1e 100644 --- a/tests/neg/i23350.check +++ b/tests/neg/i23350.check @@ -31,16 +31,15 @@ | | so the compiler cannot keep both: the generated bytecode symbols would collide. | - | To fix this error, you need to disambiguate the two definitions. You can either: + | To fix this error, you must disambiguate the two definitions by doing one of the following: | - | 1. Rename one of the definitions, or + | 1. Rename one of the definitions. | 2. Keep the same names in source but give one definition a distinct - | bytecode-level name via `@targetName` for example: + | bytecode-level name via `@targetName`; for example: | | @targetName("apply_2") | def apply(a: UndefOr2[String]): Unit | | Choose the `@targetName` argument carefully: it is the name that will be used | when calling the method externally, so it should be unique and descriptive. - | --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/i23402.check b/tests/neg/i23402.check index 4a98af863348..b258ab79e75c 100644 --- a/tests/neg/i23402.check +++ b/tests/neg/i23402.check @@ -31,16 +31,15 @@ | | so the compiler cannot keep both: the generated bytecode symbols would collide. | - | To fix this error, you need to disambiguate the two definitions. You can either: + | To fix this error, you must disambiguate the two definitions by doing one of the following: | - | 1. Rename one of the definitions, or + | 1. Rename one of the definitions. | 2. Keep the same names in source but give one definition a distinct - | bytecode-level name via `@targetName` for example: + | bytecode-level name via `@targetName`; for example: | | @targetName("apply_2") | def apply(p1: String)(p2: Int): A | | Choose the `@targetName` argument carefully: it is the name that will be used | when calling the method externally, so it should be unique and descriptive. - | --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/i23832a.check b/tests/neg/i23832a.check new file mode 100644 index 000000000000..6886327484c3 --- /dev/null +++ b/tests/neg/i23832a.check @@ -0,0 +1,45 @@ +-- [E120] Naming Error: tests/neg/i23832a.scala:9:8 -------------------------------------------------------------------- +9 | given Special[Option[Int]] = ??? // error + | ^ + | Conflicting definitions: + | final lazy given val given_Special_Option: Special[Option[Long]] in object syntax at line 8 and + | final lazy given val given_Special_Option: Special[Option[Int]] in object syntax at line 9 + |--------------------------------------------------------------------------------------------------------------------- + | Explanation (enabled by `-explain`) + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | + | As part of the Scala compilation pipeline every type is reduced to its erased + | (runtime) form. In this phase, among other transformations, generic parameters + | disappear and separate parameter-list boundaries are flattened. + | + | For example, both `f[T](x: T)(y: String): Unit` and `f(x: Any, z: String): Unit` + | erase to the same runtime signature `f(x: Object, y: String): Unit`. Note that + | parameter names are irrelevant. + | + | In your code the two declarations + | + | final lazy given val given_Special_Option: Special[Option[Long]] + | final lazy given val given_Special_Option: Special[Option[Int]] + | + | erase to the identical signature + | + | Special + | + | so the compiler cannot keep both: the generated bytecode symbols would collide. + | + | To fix this error, you must disambiguate the two definitions by doing one of the following: + | + | 1. Rename one of the definitions. Provide an explicit, unique name to given definitions, + | since the names assigned to anonymous givens may clash. For example: + | + | given myGiven: Special[Option[Int]] + | + | 2. Keep the same names in source but give one definition a distinct + | bytecode-level name via `@targetName`; for example: + | + | @targetName("given_Special_Option_2") + | final lazy given val given_Special_Option: Special[Option[Int]] + | + | Choose the `@targetName` argument carefully: it is the name that will be used + | when calling the method externally, so it should be unique and descriptive. + --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/i23832a.scala b/tests/neg/i23832a.scala new file mode 100644 index 000000000000..5020c998ee96 --- /dev/null +++ b/tests/neg/i23832a.scala @@ -0,0 +1,9 @@ +//> using options -explain + +// follow-up to neg/i23402*.scala + +trait Special[A] + +object syntax: + given Special[Option[Long]] = ??? + given Special[Option[Int]] = ??? // error diff --git a/tests/neg/i23832b.check b/tests/neg/i23832b.check new file mode 100644 index 000000000000..82cb54044449 --- /dev/null +++ b/tests/neg/i23832b.check @@ -0,0 +1,45 @@ +-- [E120] Naming Error: tests/neg/i23832b.scala:9:8 -------------------------------------------------------------------- +9 | given [A] => Special[Option[A]] = ??? // error + | ^ + | Conflicting definitions: + | final lazy given val given_Special_Option: Special[Option[Long]] in object syntax at line 8 and + | final given def given_Special_Option[A]: Special[Option[A]] in object syntax at line 9 + |--------------------------------------------------------------------------------------------------------------------- + | Explanation (enabled by `-explain`) + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | + | As part of the Scala compilation pipeline every type is reduced to its erased + | (runtime) form. In this phase, among other transformations, generic parameters + | disappear and separate parameter-list boundaries are flattened. + | + | For example, both `f[T](x: T)(y: String): Unit` and `f(x: Any, z: String): Unit` + | erase to the same runtime signature `f(x: Object, y: String): Unit`. Note that + | parameter names are irrelevant. + | + | In your code the two declarations + | + | final lazy given val given_Special_Option: Special[Option[Long]] + | final given def given_Special_Option[A]: Special[Option[A]] + | + | erase to the identical signature + | + | (): Special + | + | so the compiler cannot keep both: the generated bytecode symbols would collide. + | + | To fix this error, you must disambiguate the two definitions by doing one of the following: + | + | 1. Rename one of the definitions. Provide an explicit, unique name to given definitions, + | since the names assigned to anonymous givens may clash. For example: + | + | given myGiven: [A] => Special[Option[A]] + | + | 2. Keep the same names in source but give one definition a distinct + | bytecode-level name via `@targetName`; for example: + | + | @targetName("given_Special_Option_2") + | final given def given_Special_Option[A]: Special[Option[A]] + | + | Choose the `@targetName` argument carefully: it is the name that will be used + | when calling the method externally, so it should be unique and descriptive. + --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/i23832b.scala b/tests/neg/i23832b.scala new file mode 100644 index 000000000000..6e43ed008047 --- /dev/null +++ b/tests/neg/i23832b.scala @@ -0,0 +1,9 @@ +//> using options -explain + +// follow-up to neg/i23402*.scala + +trait Special[A] + +object syntax: + given Special[Option[Long]] = ??? + given [A] => Special[Option[A]] = ??? // error