Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify ambiguous reference error message #16137

Merged
merged 2 commits into from
Feb 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1328,21 +1328,32 @@ class AmbiguousReference(name: Name, newPrec: BindingPrec, prevPrec: BindingPrec
}

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

def explain(using Context) =
i"""|The compiler can't decide which of the possible choices you
|are referencing with $name: A definition of lower precedence
|in an inner scope, or a definition with higher precedence in
|an outer scope.
val precedent =
if newPrec == prevPrec then """two name bindings of equal precedence
|were introduced in the same scope.""".stripMargin
else """a name binding of lower precedence
|in an inner scope cannot shadow a binding with higher precedence in
|an outer scope.""".stripMargin

i"""|The identifier $name is ambiguous because $precedent
|
|The precedence of the different kinds of name bindings, from highest to lowest, is:
| - Definitions in an enclosing scope
| - Inherited definitions and top-level definitions in packages
| - Names introduced by import of a specific name
| - Names introduced by wildcard import
| - Definitions from packages in other files
|Note:
| - Definitions in an enclosing scope take precedence over inherited definitions
| - Definitions take precedence over imports
| - Named imports take precedence over wildcard imports
| - You may replace a name when imported using
| ${hl("import")} scala.{ $name => ${name.show + "Tick"} }
| - As a rule, definitions take precedence over imports.
| - Definitions in an enclosing scope take precedence over inherited definitions,
| which can result in ambiguities in nested classes.
| - When importing, you can avoid naming conflicts by renaming:
| ${hl("import")} scala.{$name => ${name.show}Tick}
|"""
}

Expand Down
16 changes: 8 additions & 8 deletions tests/neg/ambiref.check
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
-- [E049] Reference Error: tests/neg/ambiref.scala:8:14 ----------------------------------------------------------------
8 | println(x) // error
| ^
| Reference to x is ambiguous,
| it is both defined in object Test
| Reference to x is ambiguous.
| It is both defined in object Test
| and inherited subsequently in class D
|
| longer explanation available when compiling with `-explain`
-- [E049] Reference Error: tests/neg/ambiref.scala:10:14 ---------------------------------------------------------------
10 | println(x) // error
| ^
| Reference to x is ambiguous,
| it is both defined in object Test
| Reference to x is ambiguous.
| It is both defined in object Test
| and inherited subsequently in anonymous class test1.C {...}
|
| longer explanation available when compiling with `-explain`
-- [E049] Reference Error: tests/neg/ambiref.scala:17:14 ---------------------------------------------------------------
17 | println(y) // error
| ^
| Reference to y is ambiguous,
| it is both defined in method c
| Reference to y is ambiguous.
| It is both defined in method c
| and inherited subsequently in anonymous class D {...}
|
| longer explanation available when compiling with `-explain`
-- [E049] Reference Error: tests/neg/ambiref.scala:25:16 ---------------------------------------------------------------
25 | println(y) // error
| ^
| Reference to y is ambiguous,
| it is both defined in method c
| Reference to y is ambiguous.
| It is both defined in method c
| and inherited subsequently in class E
|
| longer explanation available when compiling with `-explain`
51 changes: 51 additions & 0 deletions tests/neg/i12682.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
-- [E049] Reference Error: tests/neg/i12682.scala:6:12 -----------------------------------------------------------------
6 | val x = m(1) // error
| ^
| Reference to m is ambiguous.
| It is both defined in object C
| and inherited subsequently in object T
|---------------------------------------------------------------------------------------------------------------------
| Explanation (enabled by `-explain`)
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| The identifier m is ambiguous because a name binding of lower precedence
| in an inner scope cannot shadow a binding with higher precedence in
| an outer scope.
|
| The precedence of the different kinds of name bindings, from highest to lowest, is:
| - Definitions in an enclosing scope
| - Inherited definitions and top-level definitions in packages
| - Names introduced by import of a specific name
| - Names introduced by wildcard import
| - Definitions from packages in other files
| Note:
| - As a rule, definitions take precedence over imports.
| - Definitions in an enclosing scope take precedence over inherited definitions,
| which can result in ambiguities in nested classes.
| - When importing, you can avoid naming conflicts by renaming:
| import scala.{m => mTick}
---------------------------------------------------------------------------------------------------------------------
-- [E049] Reference Error: tests/neg/i12682.scala:13:10 ----------------------------------------------------------------
13 | def d = m(42) // error
| ^
| Reference to m is ambiguous.
| It is both imported by import X._
| and imported subsequently by import Y._
|--------------------------------------------------------------------------------------------------------------------
| Explanation (enabled by `-explain`)
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| The identifier m is ambiguous because two name bindings of equal precedence
| were introduced in the same scope.
|
| The precedence of the different kinds of name bindings, from highest to lowest, is:
| - Definitions in an enclosing scope
| - Inherited definitions and top-level definitions in packages
| - Names introduced by import of a specific name
| - Names introduced by wildcard import
| - Definitions from packages in other files
| Note:
| - As a rule, definitions take precedence over imports.
| - Definitions in an enclosing scope take precedence over inherited definitions,
| which can result in ambiguities in nested classes.
| - When importing, you can avoid naming conflicts by renaming:
| import scala.{m => mTick}
--------------------------------------------------------------------------------------------------------------------
13 changes: 13 additions & 0 deletions tests/neg/i12682.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// scalac: -explain

object C:
def m(x: Int) = 1
object T extends K:
val x = m(1) // error
class K:
def m(i: Int) = 2
object X extends K
object Y extends K
object D:
import X.*, Y.*
def d = m(42) // error
8 changes: 4 additions & 4 deletions tests/neg/i13558.check
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
|
| failed with:
|
| Reference to id is ambiguous,
| it is both imported by import testcode.ExtensionB._
| Reference to id is ambiguous.
| It is both imported by import testcode.ExtensionB._
| and imported subsequently by import testcode.ExtensionA._
-- [E008] Not Found Error: tests/neg/i13558.scala:29:14 ----------------------------------------------------------------
29 | println(a.id) // error
Expand All @@ -21,6 +21,6 @@
|
| failed with:
|
| Reference to id is ambiguous,
| it is both imported by import testcode.ExtensionA._
| Reference to id is ambiguous.
| It is both imported by import testcode.ExtensionA._
| and imported subsequently by import testcode.ExtensionB._
4 changes: 2 additions & 2 deletions tests/neg/i9803.check
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
-- [E049] Reference Error: tests/neg/i9803.scala:15:10 -----------------------------------------------------------------
15 | println(f421()) // error
| ^^^^
| Reference to f421 is ambiguous,
| it is both imported by name by import bugs.shadowing.x.f421
| Reference to f421 is ambiguous.
| It is both imported by name by import bugs.shadowing.x.f421
| and imported by name subsequently by import bugs.shadowing.y.f421
|
| longer explanation available when compiling with `-explain`