Skip to content

Commit e5bd505

Browse files
committed
Clarify ambiguous reference error message
1 parent 5d1497d commit e5bd505

File tree

6 files changed

+114
-49
lines changed

6 files changed

+114
-49
lines changed

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

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,45 +1291,52 @@ import cc.CaptureSet.IdentityCaptRefMap
12911291
import typer.Typer.BindingPrec
12921292

12931293
class AmbiguousReference(name: Name, newPrec: BindingPrec, prevPrec: BindingPrec, prevCtx: Context)(using Context)
1294-
extends ReferenceMsg(AmbiguousReferenceID) {
1295-
1296-
/** A string which explains how something was bound; Depending on `prec` this is either
1297-
* imported by <tree>
1298-
* or defined in <symbol>
1299-
*/
1300-
private def bindingString(prec: BindingPrec, whereFound: Context, qualifier: String = "") = {
1301-
val howVisible = prec match {
1302-
case BindingPrec.Definition => "defined"
1303-
case BindingPrec.Inheritance => "inherited"
1304-
case BindingPrec.NamedImport => "imported by name"
1305-
case BindingPrec.WildImport => "imported"
1306-
case BindingPrec.PackageClause => "found"
1307-
case BindingPrec.NothingBound => assert(false)
1308-
}
1309-
if (prec.isImportPrec) {
1310-
ex"""$howVisible$qualifier by ${em"${whereFound.importInfo}"}"""
1311-
} else
1312-
ex"""$howVisible$qualifier in ${em"${whereFound.owner}"}"""
1313-
}
1294+
extends ReferenceMsg(AmbiguousReferenceID):
1295+
1296+
/** A string which explains how something was bound. Depending on `prec`, this is either
1297+
* imported by <tree>
1298+
* or defined in <symbol>
1299+
*/
1300+
private def bindingString(prec: BindingPrec, whereFound: Context, qualifier: String = "") =
1301+
import BindingPrec.*
1302+
val howVisible = prec match
1303+
case Definition => "defined"
1304+
case Inheritance => "inherited"
1305+
case NamedImport => "imported by name"
1306+
case WildImport => "imported"
1307+
case PackageClause => "found"
1308+
case NothingBound => assert(false)
1309+
val where =
1310+
if prec.isImportPrec then em"${whereFound.importInfo}"
1311+
else em"${whereFound.owner}"
1312+
ex"$howVisible$qualifier in $where"
13141313

13151314
def msg =
1316-
i"""|Reference to ${em"$name"} is ambiguous,
1317-
|it is both ${bindingString(newPrec, ctx)}
1315+
i"""|Reference to ${em"$name"} is ambiguous.
1316+
|It is both ${bindingString(newPrec, ctx)}
13181317
|and ${bindingString(prevPrec, prevCtx, " subsequently")}"""
13191318

13201319
def explain =
1321-
em"""|The compiler can't decide which of the possible choices you
1322-
|are referencing with $name: A definition of lower precedence
1323-
|in an inner scope, or a definition with higher precedence in
1324-
|an outer scope.
1325-
|Note:
1326-
| - Definitions in an enclosing scope take precedence over inherited definitions
1327-
| - Definitions take precedence over imports
1320+
def precedent =
1321+
if newPrec == prevPrec then """two bindings of equal precedence
1322+
|were introduced in the same scope.""".stripMargin
1323+
else """a binding of lower precedence
1324+
|in an inner scope cannot shadow a binding with higher precedence in
1325+
|an outer scope.""".stripMargin
1326+
1327+
em"""|The identifier $name is ambiguous because $precedent
1328+
|
1329+
|The precedence of the different kinds of bindings, from highest to lowest, is:
1330+
| - Definitions in an enclosing scope
1331+
| - Inherited definitions and top-level definitions in packages
1332+
| - Names introduced by imports
13281333
| - Named imports take precedence over wildcard imports
1329-
| - You may replace a name when imported using
1330-
| ${hl("import")} scala.{ $name => ${name.show + "Tick"} }
1334+
| - Definitions from packages in other files
1335+
|Note:
1336+
| - When importing, you can avoid naming conflicts by renaming:
1337+
| ${hl("import")} scala.{$name => ${name.show}Tick}
13311338
|"""
1332-
}
1339+
end AmbiguousReference
13331340

13341341
class MethodDoesNotTakeParameters(tree: tpd.Tree)(using Context)
13351342
extends TypeMsg(MethodDoesNotTakeParametersId) {

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: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 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 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 imports
18+
| - Named imports take precedence over wildcard imports
19+
| - Definitions from packages in other files
20+
| Note:
21+
| - When importing, you can avoid naming conflicts by renaming:
22+
| import scala.{m => mTick}
23+
---------------------------------------------------------------------------------------------------------------------
24+
-- [E049] Reference Error: tests/neg/i12682.scala:13:10 ----------------------------------------------------------------
25+
13 | def d = m(42) // error
26+
| ^
27+
| Reference to m is ambiguous.
28+
| It is both imported in import X._
29+
| and imported subsequently in import Y._
30+
|--------------------------------------------------------------------------------------------------------------------
31+
| Explanation (enabled by `-explain`)
32+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33+
| The identifier m is ambiguous because two bindings of equal precedence
34+
| were introduced in the same scope.
35+
|
36+
| The precedence of the different kinds of bindings, from highest to lowest, is:
37+
| - Definitions in an enclosing scope
38+
| - Inherited definitions and top-level definitions in packages
39+
| - Names introduced by imports
40+
| - Named imports take precedence over wildcard imports
41+
| - Definitions from packages in other files
42+
| Note:
43+
| - When importing, you can avoid naming conflicts by renaming:
44+
| import scala.{m => mTick}
45+
--------------------------------------------------------------------------------------------------------------------

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: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
|
77
| testcode.ExtensionA.id(a) failed with
88
|
9-
| Reference to id is ambiguous,
10-
| it is both imported by import testcode.ExtensionB._
11-
| and imported subsequently by import testcode.ExtensionA._
9+
| Reference to id is ambiguous.
10+
| It is both imported in import testcode.ExtensionB._
11+
| and imported subsequently in import testcode.ExtensionA._
1212
-- [E008] Not Found Error: tests/neg/i13558.scala:29:14 ----------------------------------------------------------------
1313
29 | println(a.id) // error
1414
| ^^^^
@@ -17,6 +17,6 @@
1717
|
1818
| testcode.ExtensionB.id(a) failed with
1919
|
20-
| Reference to id is ambiguous,
21-
| it is both imported by import testcode.ExtensionA._
22-
| and imported subsequently by import testcode.ExtensionB._
20+
| Reference to id is ambiguous.
21+
| It is both imported in import testcode.ExtensionA._
22+
| and imported subsequently in import testcode.ExtensionB._

tests/neg/i9803.check

Lines changed: 3 additions & 3 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
6-
| and imported by name subsequently by import bugs.shadowing.y.f421
4+
| Reference to f421 is ambiguous.
5+
| It is both imported by name in import bugs.shadowing.x.f421
6+
| and imported by name subsequently in import bugs.shadowing.y.f421
77
|
88
| longer explanation available when compiling with `-explain`

0 commit comments

Comments
 (0)