Skip to content

Commit 3b5bd33

Browse files
som-snytttgodzik
authored andcommitted
Mention named givens in double def explainer
Print info at typer in example code. Could be automatic. [Cherry-picked 912fce1]
1 parent 5fc234b commit 3b5bd33

File tree

7 files changed

+130
-13
lines changed

7 files changed

+130
-13
lines changed

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

Lines changed: 18 additions & 9 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,16 @@ 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+
if decl.is(Given) && previousDecl.is(Given) && isGivenName(decl) && isGivenName(previousDecl) then
2394+
i"""
2395+
|3. Provide an explicit, unique name to given definitions, since the names
2396+
| assigned to anonymous givens may clash. For example:
2397+
|
2398+
| given myGiven: ${atPhase(typerPhase)(decl.info)}
2399+
|"""
2400+
else ""
23912401
decl.signature.matchDegree(previousDecl.signature) match
23922402
case FullMatch =>
23932403
i"""
@@ -2401,8 +2411,8 @@ extends NamingMsg(DoubleDefinitionID) {
24012411
|
24022412
|In your code the two declarations
24032413
|
2404-
| ${previousDecl.showDcl}
2405-
| ${decl.showDcl}
2414+
| ${atPhase(typerPhase)(previousDecl.showDcl)}
2415+
| ${atPhase(typerPhase)(decl.showDcl)}
24062416
|
24072417
|erase to the identical signature
24082418
|
@@ -2414,17 +2424,16 @@ extends NamingMsg(DoubleDefinitionID) {
24142424
|
24152425
|1. Rename one of the definitions, or
24162426
|2. Keep the same names in source but give one definition a distinct
2417-
| bytecode-level name via `@targetName` for example:
2427+
| bytecode-level name via `@targetName`; for example:
24182428
|
24192429
| @targetName("${decl.name.show}_2")
2420-
| ${decl.showDcl}
2421-
|
2430+
| ${atPhase(typerPhase)(decl.showDcl)}
2431+
|$givenAddendum
24222432
|Choose the `@targetName` argument carefully: it is the name that will be used
24232433
|when calling the method externally, so it should be unique and descriptive.
2424-
"""
2434+
|"""
24252435
case _ => ""
2426-
2427-
}
2436+
end DoubleDefinition
24282437

24292438
class ImportRenamedTwice(ident: untpd.Ident)(using Context) extends SyntaxMsg(ImportRenamedTwiceID) {
24302439
def msg(using Context) = s"${ident.show} is renamed twice on the same import line."

tests/neg/i23350.check

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@
3535
|
3636
| 1. Rename one of the definitions, or
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: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@
3535
|
3636
| 1. Rename one of the definitions, or
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: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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 need to disambiguate the two definitions. You can either:
31+
|
32+
| 1. Rename one of the definitions, or
33+
| 2. Keep the same names in source but give one definition a distinct
34+
| bytecode-level name via `@targetName`; for example:
35+
|
36+
| @targetName("given_Special_Option_2")
37+
| final lazy given val given_Special_Option: Special[Option[Int]]
38+
|
39+
| 3. Provide an explicit, unique name to given definitions, since the names
40+
| assigned to anonymous givens may clash. For example:
41+
|
42+
| given myGiven: Special[Option[Int]]
43+
|
44+
| Choose the `@targetName` argument carefully: it is the name that will be used
45+
| when calling the method externally, so it should be unique and descriptive.
46+
---------------------------------------------------------------------------------------------------------------------

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: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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 need to disambiguate the two definitions. You can either:
31+
|
32+
| 1. Rename one of the definitions, or
33+
| 2. Keep the same names in source but give one definition a distinct
34+
| bytecode-level name via `@targetName`; for example:
35+
|
36+
| @targetName("given_Special_Option_2")
37+
| final given def given_Special_Option[A]: Special[Option[A]]
38+
|
39+
| 3. Provide an explicit, unique name to given definitions, since the names
40+
| assigned to anonymous givens may clash. For example:
41+
|
42+
| given myGiven: [A]: Special[Option[A]]
43+
|
44+
| Choose the `@targetName` argument carefully: it is the name that will be used
45+
| when calling the method externally, so it should be unique and descriptive.
46+
---------------------------------------------------------------------------------------------------------------------

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)