Skip to content

Commit b67daed

Browse files
authored
Clarify ambiguous reference error message (#16137)
2 parents b5b24d9 + 363996c commit b67daed

File tree

6 files changed

+100
-25
lines changed

6 files changed

+100
-25
lines changed

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

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,21 +1328,32 @@ class AmbiguousReference(name: Name, newPrec: BindingPrec, prevPrec: BindingPrec
13281328
}
13291329

13301330
def msg(using Context) =
1331-
i"""|Reference to $name is ambiguous,
1332-
|it is both ${bindingString(newPrec, ctx)}
1331+
i"""|Reference to $name is ambiguous.
1332+
|It is both ${bindingString(newPrec, ctx)}
13331333
|and ${bindingString(prevPrec, prevCtx, " subsequently")}"""
13341334

13351335
def explain(using Context) =
1336-
i"""|The compiler can't decide which of the possible choices you
1337-
|are referencing with $name: A definition of lower precedence
1338-
|in an inner scope, or a definition with higher precedence in
1339-
|an outer scope.
1336+
val precedent =
1337+
if newPrec == prevPrec then """two name bindings of equal precedence
1338+
|were introduced in the same scope.""".stripMargin
1339+
else """a name binding of lower precedence
1340+
|in an inner scope cannot shadow a binding with higher precedence in
1341+
|an outer scope.""".stripMargin
1342+
1343+
i"""|The identifier $name is ambiguous because $precedent
1344+
|
1345+
|The precedence of the different kinds of name bindings, from highest to lowest, is:
1346+
| - Definitions in an enclosing scope
1347+
| - Inherited definitions and top-level definitions in packages
1348+
| - Names introduced by import of a specific name
1349+
| - Names introduced by wildcard import
1350+
| - Definitions from packages in other files
13401351
|Note:
1341-
| - Definitions in an enclosing scope take precedence over inherited definitions
1342-
| - Definitions take precedence over imports
1343-
| - Named imports take precedence over wildcard imports
1344-
| - You may replace a name when imported using
1345-
| ${hl("import")} scala.{ $name => ${name.show + "Tick"} }
1352+
| - As a rule, definitions take precedence over imports.
1353+
| - Definitions in an enclosing scope take precedence over inherited definitions,
1354+
| which can result in ambiguities in nested classes.
1355+
| - When importing, you can avoid naming conflicts by renaming:
1356+
| ${hl("import")} scala.{$name => ${name.show}Tick}
13461357
|"""
13471358
}
13481359

tests/neg/ambiref.check

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
-- [E049] Reference Error: tests/neg/ambiref.scala:8:14 ----------------------------------------------------------------
22
8 | println(x) // error
33
| ^
4-
| Reference to x is ambiguous,
5-
| it is both defined in object Test
4+
| Reference to x is ambiguous.
5+
| It is both defined in object Test
66
| and inherited subsequently in class D
77
|
88
| longer explanation available when compiling with `-explain`
99
-- [E049] Reference Error: tests/neg/ambiref.scala:10:14 ---------------------------------------------------------------
1010
10 | println(x) // error
1111
| ^
12-
| Reference to x is ambiguous,
13-
| it is both defined in object Test
12+
| Reference to x is ambiguous.
13+
| It is both defined in object Test
1414
| and inherited subsequently in anonymous class test1.C {...}
1515
|
1616
| longer explanation available when compiling with `-explain`
1717
-- [E049] Reference Error: tests/neg/ambiref.scala:17:14 ---------------------------------------------------------------
1818
17 | println(y) // error
1919
| ^
20-
| Reference to y is ambiguous,
21-
| it is both defined in method c
20+
| Reference to y is ambiguous.
21+
| It is both defined in method c
2222
| and inherited subsequently in anonymous class D {...}
2323
|
2424
| longer explanation available when compiling with `-explain`
2525
-- [E049] Reference Error: tests/neg/ambiref.scala:25:16 ---------------------------------------------------------------
2626
25 | println(y) // error
2727
| ^
28-
| Reference to y is ambiguous,
29-
| it is both defined in method c
28+
| Reference to y is ambiguous.
29+
| It is both defined in method c
3030
| and inherited subsequently in class E
3131
|
3232
| longer explanation available when compiling with `-explain`

tests/neg/i12682.check

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
-- [E049] Reference Error: tests/neg/i12682.scala:6:12 -----------------------------------------------------------------
2+
6 | val x = m(1) // error
3+
| ^
4+
| Reference to m is ambiguous.
5+
| It is both defined in object C
6+
| and inherited subsequently in object T
7+
|---------------------------------------------------------------------------------------------------------------------
8+
| Explanation (enabled by `-explain`)
9+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
10+
| The identifier m is ambiguous because a name binding of lower precedence
11+
| in an inner scope cannot shadow a binding with higher precedence in
12+
| an outer scope.
13+
|
14+
| The precedence of the different kinds of name bindings, from highest to lowest, is:
15+
| - Definitions in an enclosing scope
16+
| - Inherited definitions and top-level definitions in packages
17+
| - Names introduced by import of a specific name
18+
| - Names introduced by wildcard import
19+
| - Definitions from packages in other files
20+
| Note:
21+
| - As a rule, definitions take precedence over imports.
22+
| - Definitions in an enclosing scope take precedence over inherited definitions,
23+
| which can result in ambiguities in nested classes.
24+
| - When importing, you can avoid naming conflicts by renaming:
25+
| import scala.{m => mTick}
26+
---------------------------------------------------------------------------------------------------------------------
27+
-- [E049] Reference Error: tests/neg/i12682.scala:13:10 ----------------------------------------------------------------
28+
13 | def d = m(42) // error
29+
| ^
30+
| Reference to m is ambiguous.
31+
| It is both imported by import X._
32+
| and imported subsequently by import Y._
33+
|--------------------------------------------------------------------------------------------------------------------
34+
| Explanation (enabled by `-explain`)
35+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
36+
| The identifier m is ambiguous because two name bindings of equal precedence
37+
| were introduced in the same scope.
38+
|
39+
| The precedence of the different kinds of name bindings, from highest to lowest, is:
40+
| - Definitions in an enclosing scope
41+
| - Inherited definitions and top-level definitions in packages
42+
| - Names introduced by import of a specific name
43+
| - Names introduced by wildcard import
44+
| - Definitions from packages in other files
45+
| Note:
46+
| - As a rule, definitions take precedence over imports.
47+
| - Definitions in an enclosing scope take precedence over inherited definitions,
48+
| which can result in ambiguities in nested classes.
49+
| - When importing, you can avoid naming conflicts by renaming:
50+
| import scala.{m => mTick}
51+
--------------------------------------------------------------------------------------------------------------------

tests/neg/i12682.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// scalac: -explain
2+
3+
object C:
4+
def m(x: Int) = 1
5+
object T extends K:
6+
val x = m(1) // error
7+
class K:
8+
def m(i: Int) = 2
9+
object X extends K
10+
object Y extends K
11+
object D:
12+
import X.*, Y.*
13+
def d = m(42) // error

tests/neg/i13558.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
|
99
| failed with:
1010
|
11-
| Reference to id is ambiguous,
12-
| it is both imported by import testcode.ExtensionB._
11+
| Reference to id is ambiguous.
12+
| It is both imported by import testcode.ExtensionB._
1313
| and imported subsequently by import testcode.ExtensionA._
1414
-- [E008] Not Found Error: tests/neg/i13558.scala:29:14 ----------------------------------------------------------------
1515
29 | println(a.id) // error
@@ -21,6 +21,6 @@
2121
|
2222
| failed with:
2323
|
24-
| Reference to id is ambiguous,
25-
| it is both imported by import testcode.ExtensionA._
24+
| Reference to id is ambiguous.
25+
| It is both imported by import testcode.ExtensionA._
2626
| and imported subsequently by import testcode.ExtensionB._

tests/neg/i9803.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
-- [E049] Reference Error: tests/neg/i9803.scala:15:10 -----------------------------------------------------------------
22
15 | println(f421()) // error
33
| ^^^^
4-
| Reference to f421 is ambiguous,
5-
| it is both imported by name by import bugs.shadowing.x.f421
4+
| Reference to f421 is ambiguous.
5+
| It is both imported by name by import bugs.shadowing.x.f421
66
| and imported by name subsequently by import bugs.shadowing.y.f421
77
|
88
| longer explanation available when compiling with `-explain`

0 commit comments

Comments
 (0)