Skip to content

Commit 9fac8b5

Browse files
Backport "Mention named givens in double def explainer" to 3.7.4 (#23992)
Backports #23833 to the 3.7.4. PR submitted by the release tooling. [skip ci]
2 parents 132ce37 + a6115ba commit 9fac8b5

File tree

7 files changed

+142
-18
lines changed

7 files changed

+142
-18
lines changed

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

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2364,7 +2364,7 @@ class SymbolIsNotAValue(symbol: Symbol)(using Context) extends TypeMsg(SymbolIsN
23642364
}
23652365

23662366
class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(using Context)
2367-
extends NamingMsg(DoubleDefinitionID) {
2367+
extends NamingMsg(DoubleDefinitionID):
23682368
import Signature.MatchDegree.*
23692369

23702370
private def erasedType: Type =
@@ -2426,6 +2426,25 @@ extends NamingMsg(DoubleDefinitionID) {
24262426
} + details
24272427
}
24282428
def explain(using Context) =
2429+
def givenAddendum =
2430+
def isGivenName(sym: Symbol) = sym.name.startsWith("given_") // Desugar.inventGivenName
2431+
def print(tpe: Type): String =
2432+
def addParams(tpe: Type): List[String] = tpe match
2433+
case tpe: MethodType =>
2434+
val s = if tpe.isContextualMethod then i"(${tpe.paramInfos}%, %) =>" else ""
2435+
s :: addParams(tpe.resType)
2436+
case tpe: PolyType =>
2437+
i"[${tpe.paramNames}%, %] =>" :: addParams(tpe.resType)
2438+
case tpe =>
2439+
i"$tpe" :: Nil
2440+
addParams(tpe).mkString(" ")
2441+
if decl.is(Given) && previousDecl.is(Given) && isGivenName(decl) && isGivenName(previousDecl) then
2442+
i"""| Provide an explicit, unique name to given definitions,
2443+
| since the names assigned to anonymous givens may clash. For example:
2444+
|
2445+
| given myGiven: ${print(atPhase(typerPhase)(decl.info))}
2446+
|"""
2447+
else ""
24292448
decl.signature.matchDegree(previousDecl.signature) match
24302449
case FullMatch =>
24312450
i"""
@@ -2439,30 +2458,29 @@ extends NamingMsg(DoubleDefinitionID) {
24392458
|
24402459
|In your code the two declarations
24412460
|
2442-
| ${previousDecl.showDcl}
2443-
| ${decl.showDcl}
2461+
| ${atPhase(typerPhase)(previousDecl.showDcl)}
2462+
| ${atPhase(typerPhase)(decl.showDcl)}
24442463
|
24452464
|erase to the identical signature
24462465
|
24472466
| ${erasedType}
24482467
|
24492468
|so the compiler cannot keep both: the generated bytecode symbols would collide.
24502469
|
2451-
|To fix this error, you need to disambiguate the two definitions. You can either:
2470+
|To fix this error, you must disambiguate the two definitions by doing one of the following:
24522471
|
2453-
|1. Rename one of the definitions, or
2472+
|1. Rename one of the definitions.$givenAddendum
24542473
|2. Keep the same names in source but give one definition a distinct
2455-
| bytecode-level name via `@targetName` for example:
2474+
| bytecode-level name via `@targetName`; for example:
24562475
|
24572476
| @targetName("${decl.name.show}_2")
2458-
| ${decl.showDcl}
2477+
| ${atPhase(typerPhase)(decl.showDcl)}
24592478
|
24602479
|Choose the `@targetName` argument carefully: it is the name that will be used
24612480
|when calling the method externally, so it should be unique and descriptive.
2462-
"""
2481+
|"""
24632482
case _ => ""
2464-
2465-
}
2483+
end DoubleDefinition
24662484

24672485
class ImportedTwice(sel: Name)(using Context) extends SyntaxMsg(ImportedTwiceID) {
24682486
def msg(using Context) = s"${sel.show} is imported twice on the same import line."

tests/neg/i23350.check

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,15 @@
3131
|
3232
| so the compiler cannot keep both: the generated bytecode symbols would collide.
3333
|
34-
| To fix this error, you need to disambiguate the two definitions. You can either:
34+
| To fix this error, you must disambiguate the two definitions by doing one of the following:
3535
|
36-
| 1. Rename one of the definitions, or
36+
| 1. Rename one of the definitions.
3737
| 2. Keep the same names in source but give one definition a distinct
38-
| bytecode-level name via `@targetName` for example:
38+
| bytecode-level name via `@targetName`; for example:
3939
|
4040
| @targetName("apply_2")
4141
| def apply(a: UndefOr2[String]): Unit
4242
|
4343
| Choose the `@targetName` argument carefully: it is the name that will be used
4444
| when calling the method externally, so it should be unique and descriptive.
45-
|
4645
---------------------------------------------------------------------------------------------------------------------

tests/neg/i23402.check

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,15 @@
3131
|
3232
| so the compiler cannot keep both: the generated bytecode symbols would collide.
3333
|
34-
| To fix this error, you need to disambiguate the two definitions. You can either:
34+
| To fix this error, you must disambiguate the two definitions by doing one of the following:
3535
|
36-
| 1. Rename one of the definitions, or
36+
| 1. Rename one of the definitions.
3737
| 2. Keep the same names in source but give one definition a distinct
38-
| bytecode-level name via `@targetName` for example:
38+
| bytecode-level name via `@targetName`; for example:
3939
|
4040
| @targetName("apply_2")
4141
| def apply(p1: String)(p2: Int): A
4242
|
4343
| Choose the `@targetName` argument carefully: it is the name that will be used
4444
| when calling the method externally, so it should be unique and descriptive.
45-
|
4645
---------------------------------------------------------------------------------------------------------------------

tests/neg/i23832a.check

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
-- [E120] Naming Error: tests/neg/i23832a.scala:9:8 --------------------------------------------------------------------
2+
9 | given Special[Option[Int]] = ??? // error
3+
| ^
4+
| Conflicting definitions:
5+
| final lazy given val given_Special_Option: Special[Option[Long]] in object syntax at line 8 and
6+
| final lazy given val given_Special_Option: Special[Option[Int]] in object syntax at line 9
7+
|---------------------------------------------------------------------------------------------------------------------
8+
| Explanation (enabled by `-explain`)
9+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
10+
|
11+
| As part of the Scala compilation pipeline every type is reduced to its erased
12+
| (runtime) form. In this phase, among other transformations, generic parameters
13+
| disappear and separate parameter-list boundaries are flattened.
14+
|
15+
| For example, both `f[T](x: T)(y: String): Unit` and `f(x: Any, z: String): Unit`
16+
| erase to the same runtime signature `f(x: Object, y: String): Unit`. Note that
17+
| parameter names are irrelevant.
18+
|
19+
| In your code the two declarations
20+
|
21+
| final lazy given val given_Special_Option: Special[Option[Long]]
22+
| final lazy given val given_Special_Option: Special[Option[Int]]
23+
|
24+
| erase to the identical signature
25+
|
26+
| Special
27+
|
28+
| so the compiler cannot keep both: the generated bytecode symbols would collide.
29+
|
30+
| To fix this error, you must disambiguate the two definitions by doing one of the following:
31+
|
32+
| 1. Rename one of the definitions. Provide an explicit, unique name to given definitions,
33+
| since the names assigned to anonymous givens may clash. For example:
34+
|
35+
| given myGiven: Special[Option[Int]]
36+
|
37+
| 2. Keep the same names in source but give one definition a distinct
38+
| bytecode-level name via `@targetName`; for example:
39+
|
40+
| @targetName("given_Special_Option_2")
41+
| final lazy given val given_Special_Option: Special[Option[Int]]
42+
|
43+
| Choose the `@targetName` argument carefully: it is the name that will be used
44+
| when calling the method externally, so it should be unique and descriptive.
45+
---------------------------------------------------------------------------------------------------------------------

tests/neg/i23832a.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//> using options -explain
2+
3+
// follow-up to neg/i23402*.scala
4+
5+
trait Special[A]
6+
7+
object syntax:
8+
given Special[Option[Long]] = ???
9+
given Special[Option[Int]] = ??? // error

tests/neg/i23832b.check

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
-- [E120] Naming Error: tests/neg/i23832b.scala:9:8 --------------------------------------------------------------------
2+
9 | given [A] => Special[Option[A]] = ??? // error
3+
| ^
4+
| Conflicting definitions:
5+
| final lazy given val given_Special_Option: Special[Option[Long]] in object syntax at line 8 and
6+
| final given def given_Special_Option[A]: Special[Option[A]] in object syntax at line 9
7+
|---------------------------------------------------------------------------------------------------------------------
8+
| Explanation (enabled by `-explain`)
9+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
10+
|
11+
| As part of the Scala compilation pipeline every type is reduced to its erased
12+
| (runtime) form. In this phase, among other transformations, generic parameters
13+
| disappear and separate parameter-list boundaries are flattened.
14+
|
15+
| For example, both `f[T](x: T)(y: String): Unit` and `f(x: Any, z: String): Unit`
16+
| erase to the same runtime signature `f(x: Object, y: String): Unit`. Note that
17+
| parameter names are irrelevant.
18+
|
19+
| In your code the two declarations
20+
|
21+
| final lazy given val given_Special_Option: Special[Option[Long]]
22+
| final given def given_Special_Option[A]: Special[Option[A]]
23+
|
24+
| erase to the identical signature
25+
|
26+
| (): Special
27+
|
28+
| so the compiler cannot keep both: the generated bytecode symbols would collide.
29+
|
30+
| To fix this error, you must disambiguate the two definitions by doing one of the following:
31+
|
32+
| 1. Rename one of the definitions. Provide an explicit, unique name to given definitions,
33+
| since the names assigned to anonymous givens may clash. For example:
34+
|
35+
| given myGiven: [A] => Special[Option[A]]
36+
|
37+
| 2. Keep the same names in source but give one definition a distinct
38+
| bytecode-level name via `@targetName`; for example:
39+
|
40+
| @targetName("given_Special_Option_2")
41+
| final given def given_Special_Option[A]: Special[Option[A]]
42+
|
43+
| Choose the `@targetName` argument carefully: it is the name that will be used
44+
| when calling the method externally, so it should be unique and descriptive.
45+
---------------------------------------------------------------------------------------------------------------------

tests/neg/i23832b.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//> using options -explain
2+
3+
// follow-up to neg/i23402*.scala
4+
5+
trait Special[A]
6+
7+
object syntax:
8+
given Special[Option[Long]] = ???
9+
given [A] => Special[Option[A]] = ??? // error

0 commit comments

Comments
 (0)