Skip to content

Commit adb08b7

Browse files
authored
Merge pull request #579 from scala/backport-lts-3.3-23833
Backport "Mention named givens in double def explainer" to 3.3 LTS
2 parents 2f7c462 + 8333a53 commit adb08b7

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
@@ -2326,7 +2326,7 @@ class JavaSymbolIsNotAValue(symbol: Symbol)(using Context) extends TypeMsg(JavaS
23262326
}
23272327

23282328
class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(using Context)
2329-
extends NamingMsg(DoubleDefinitionID) {
2329+
extends NamingMsg(DoubleDefinitionID):
23302330
import Signature.MatchDegree.*
23312331

23322332
private def erasedType: Type =
@@ -2388,6 +2388,25 @@ extends NamingMsg(DoubleDefinitionID) {
23882388
} + details
23892389
}
23902390
def explain(using Context) =
2391+
def givenAddendum =
2392+
def isGivenName(sym: Symbol) = sym.name.startsWith("given_") // Desugar.inventGivenName
2393+
def print(tpe: Type): String =
2394+
def addParams(tpe: Type): List[String] = tpe match
2395+
case tpe: MethodType =>
2396+
val s = if tpe.isContextualMethod then i"(${tpe.paramInfos}%, %) =>" else ""
2397+
s :: addParams(tpe.resType)
2398+
case tpe: PolyType =>
2399+
i"[${tpe.paramNames}%, %] =>" :: addParams(tpe.resType)
2400+
case tpe =>
2401+
i"$tpe" :: Nil
2402+
addParams(tpe).mkString(" ")
2403+
if decl.is(Given) && previousDecl.is(Given) && isGivenName(decl) && isGivenName(previousDecl) then
2404+
i"""| Provide an explicit, unique name to given definitions,
2405+
| since the names assigned to anonymous givens may clash. For example:
2406+
|
2407+
| given myGiven: ${print(atPhase(typerPhase)(decl.info))}
2408+
|"""
2409+
else ""
23912410
decl.signature.matchDegree(previousDecl.signature) match
23922411
case FullMatch =>
23932412
i"""
@@ -2401,30 +2420,29 @@ extends NamingMsg(DoubleDefinitionID) {
24012420
|
24022421
|In your code the two declarations
24032422
|
2404-
| ${previousDecl.showDcl}
2405-
| ${decl.showDcl}
2423+
| ${atPhase(typerPhase)(previousDecl.showDcl)}
2424+
| ${atPhase(typerPhase)(decl.showDcl)}
24062425
|
24072426
|erase to the identical signature
24082427
|
24092428
| ${erasedType}
24102429
|
24112430
|so the compiler cannot keep both: the generated bytecode symbols would collide.
24122431
|
2413-
|To fix this error, you need to disambiguate the two definitions. You can either:
2432+
|To fix this error, you must disambiguate the two definitions by doing one of the following:
24142433
|
2415-
|1. Rename one of the definitions, or
2434+
|1. Rename one of the definitions.$givenAddendum
24162435
|2. Keep the same names in source but give one definition a distinct
2417-
| bytecode-level name via `@targetName` for example:
2436+
| bytecode-level name via `@targetName`; for example:
24182437
|
24192438
| @targetName("${decl.name.show}_2")
2420-
| ${decl.showDcl}
2439+
| ${atPhase(typerPhase)(decl.showDcl)}
24212440
|
24222441
|Choose the `@targetName` argument carefully: it is the name that will be used
24232442
|when calling the method externally, so it should be unique and descriptive.
2424-
"""
2443+
|"""
24252444
case _ => ""
2426-
2427-
}
2445+
end DoubleDefinition
24282446

24292447
class ImportRenamedTwice(ident: untpd.Ident)(using Context) extends SyntaxMsg(ImportRenamedTwiceID) {
24302448
def msg(using Context) = s"${ident.show} is renamed 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)