Skip to content

Commit

Permalink
Merge pull request #10324 from lrytz/t11921-overloads-213
Browse files Browse the repository at this point in the history
Deal with overloads in new ambiguity warning (2.13)
  • Loading branch information
lrytz committed Mar 1, 2023
2 parents 1248384 + d3737fb commit 0fd61f7
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 70 deletions.
46 changes: 26 additions & 20 deletions src/compiler/scala/tools/nsc/typechecker/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1362,28 +1362,32 @@ trait Contexts { self: Analyzer =>
LookupAmbiguous(s"it is imported twice in the same scope by\n$imp1\nand $imp2")
def ambiguousDefnAndImport(owner: Symbol, imp: ImportInfo) =
LookupAmbiguous(s"it is both defined in $owner and imported subsequently by \n$imp")
def ambiguousDefinitions(sym: Symbol, other: Symbol, otherFoundInSuper: Boolean, otherEnclClass: Symbol) = {
if (otherFoundInSuper) {
val enclDesc = if (otherEnclClass.isAnonymousClass) "anonymous class" else otherEnclClass.toString
val parent = otherEnclClass.parentSymbols.find(_.isNonBottomSubClass(other.owner)).getOrElse(NoSymbol)
val inherit = if (parent.exists && parent != other.owner) s", inherited through parent $parent" else ""
val message =
s"""it is both defined in the enclosing ${sym.owner} and available in the enclosing $enclDesc as $other (defined in ${other.ownsString}$inherit)
|Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
|To continue using the symbol from the superclass, write `this.${sym.name}`.""".stripMargin
if (currentRun.isScala3)
Some(LookupAmbiguous(message))
def ambiguousDefinitions(outer: Symbol, inherited: Symbol, foundInSuper: Boolean, currentClass: Symbol) =
if (foundInSuper) {
if (inherited.isImplicit) None
else {
// passing the message to `typedIdent` as attachment, we don't have the position here to report the warning
other.updateAttachment(LookupAmbiguityWarning(
s"""reference to ${sym.name} is ambiguous;
|$message
|Or use `-Wconf:msg=legacy-binding:s` to silence this warning.""".stripMargin))
None
val outer1 = outer.alternatives.head
val inherited1 = inherited.alternatives.head
val classDesc = if (currentClass.isAnonymousClass) "anonymous class" else currentClass.toString
val parent = currentClass.parentSymbols.find(_.isNonBottomSubClass(inherited1.owner)).getOrElse(NoSymbol)
val inherit = if (parent.exists && parent != inherited1.owner) s", inherited through parent $parent" else ""
val message =
s"""it is both defined in the enclosing ${outer1.owner} and inherited in the enclosing $classDesc as $inherited1 (defined in ${inherited1.ownsString}$inherit)
|In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
|Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.${outer1.name}`.""".stripMargin
if (currentRun.isScala3)
Some(LookupAmbiguous(message))
else {
// passing the message to `typedIdent` as attachment, we don't have the position here to report the warning
inherited.updateAttachment(LookupAmbiguityWarning(
s"""reference to ${outer1.name} is ambiguous;
|$message
|Or use `-Wconf:msg=legacy-binding:s` to silence this warning.""".stripMargin))
None
}
}
} else
Some(LookupAmbiguous(s"it is both defined in ${sym.owner} and available as ${other.fullLocationString}"))
}
Some(LookupAmbiguous(s"it is both defined in ${outer.owner} and available as ${inherited.fullLocationString}"))

def apply(thisContext: Context, name: Name)(qualifies: Symbol => Boolean): NameLookup = {
lookupError = null
Expand Down Expand Up @@ -1492,7 +1496,7 @@ trait Contexts { self: Analyzer =>
(lastPre.memberType(lastDef).termSymbol == defSym || pre.memberType(defSym).termSymbol == lastDef))
defSym = NoSymbol
foundInPrefix = inPrefix && defSym.exists
foundInSuper = foundInPrefix && defSym.owner != cx.owner
foundInSuper = foundInPrefix && defSym.alternatives.forall(_.owner != cx.owner)
}
nextDefinition(NoSymbol, NoPrefix)

Expand Down Expand Up @@ -1599,6 +1603,7 @@ trait Contexts { self: Analyzer =>
val defSym0 = defSym
val pre0 = pre
val cx0 = cx
val depth0 = symbolDepth
val wasFoundInSuper = foundInSuper
val foundCompetingSymbol: () => Boolean =
if (foreignDefined) () => !foreignDefined
Expand All @@ -1621,6 +1626,7 @@ trait Contexts { self: Analyzer =>
defSym = defSym0
pre = pre0
cx = cx0
symbolDepth = depth0
}

if (preferDef) impSym = NoSymbol else defSym = NoSymbol
Expand Down
24 changes: 12 additions & 12 deletions test/files/neg/t11921-alias.check
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
t11921-alias.scala:18: warning: reference to TT is ambiguous;
it is both defined in the enclosing object O and available in the enclosing class D as type TT (defined in class C)
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.TT`.
it is both defined in the enclosing object O and inherited in the enclosing class D as type TT (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.TT`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def n(x: TT) = x // ambiguous
^
t11921-alias.scala:38: warning: reference to c is ambiguous;
it is both defined in the enclosing class B and available in the enclosing anonymous class as value c (defined in class A)
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.c`.
it is both defined in the enclosing class B and inherited in the enclosing anonymous class as value c (defined in class A)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.c`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def n = c // ambiguous
^
t11921-alias.scala:57: warning: reference to name is ambiguous;
it is both defined in the enclosing method m and available in the enclosing anonymous class as value name (defined in class C)
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.name`.
it is both defined in the enclosing method m and inherited in the enclosing anonymous class as value name (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.name`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(name)
^
t11921-alias.scala:67: warning: reference to name is ambiguous;
it is both defined in the enclosing method m and available in the enclosing anonymous class as value name (defined in class A, inherited through parent class C)
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.name`.
it is both defined in the enclosing method m and inherited in the enclosing anonymous class as value name (defined in class A, inherited through parent class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.name`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(name)
^
Expand Down
6 changes: 3 additions & 3 deletions test/files/neg/t11921.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ t11921.scala:6: error: type mismatch;
def iterator = coll.iterator.map(f) // coll is ambiguous
^
t11921.scala:6: warning: reference to coll is ambiguous;
it is both defined in the enclosing method lazyMap and available in the enclosing anonymous class as method coll (defined in trait Iterable)
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.coll`.
it is both defined in the enclosing method lazyMap and inherited in the enclosing anonymous class as method coll (defined in trait Iterable)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.coll`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def iterator = coll.iterator.map(f) // coll is ambiguous
^
Expand Down
50 changes: 33 additions & 17 deletions test/files/neg/t11921b.check
Original file line number Diff line number Diff line change
@@ -1,38 +1,54 @@
t11921b.scala:135: error: could not find implicit value for parameter i: Int
def u = t // doesn't compile in Scala 2 (maybe there's a ticket for that)
^
t11921b.scala:11: warning: reference to x is ambiguous;
it is both defined in the enclosing object Test and available in the enclosing class D as value x (defined in class C)
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.x`.
it is both defined in the enclosing object Test and inherited in the enclosing class D as value x (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.x`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(x) // error
^
t11921b.scala:15: warning: reference to x is ambiguous;
it is both defined in the enclosing object Test and available in the enclosing anonymous class as value x (defined in class C)
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.x`.
it is both defined in the enclosing object Test and inherited in the enclosing anonymous class as value x (defined in class C)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.x`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(x) // error
^
t11921b.scala:26: warning: reference to y is ambiguous;
it is both defined in the enclosing method c and available in the enclosing anonymous class as value y (defined in class D)
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.y`.
it is both defined in the enclosing method c and inherited in the enclosing anonymous class as value y (defined in class D)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.y`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(y) // error
^
t11921b.scala:38: warning: reference to y is ambiguous;
it is both defined in the enclosing method c and available in the enclosing class E as value y (defined in class D)
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.y`.
it is both defined in the enclosing method c and inherited in the enclosing class E as value y (defined in class D)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.y`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
println(y) // error
^
t11921b.scala:75: warning: reference to x is ambiguous;
it is both defined in the enclosing object Uhu and available in the enclosing class C as value x (defined in class A, inherited through parent class B)
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
To continue using the symbol from the superclass, write `this.x`.
it is both defined in the enclosing object Uhu and inherited in the enclosing class C as value x (defined in class A, inherited through parent class B)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.x`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def t = x // ambiguous, message mentions parent B
^
error: No warnings can be incurred under -Werror.
5 warnings
t11921b.scala:89: warning: reference to a is ambiguous;
it is both defined in the enclosing class C and inherited in the enclosing trait J as method a (defined in trait I)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.a`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
val t = a // error
^
t11921b.scala:136: warning: reference to lo is ambiguous;
it is both defined in the enclosing object test10 and inherited in the enclosing class C as value lo (defined in class P)
In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope.
Such references are ambiguous in Scala 3. To continue using the inherited symbol, write `this.lo`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def v = t(lo) // error
^
7 warnings
1 error
61 changes: 60 additions & 1 deletion test/files/neg/t11921b.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class C {
val global = 42
}
object D extends C {
println(global) // OK, since global is defined in package
println(global) // OK, since global is defined in package (https://github.com/scala/scala/pull/10220/files#r1109773904)
}

object test5 {
Expand All @@ -77,3 +77,62 @@ object test5 {
}
}
}

object test6 {
trait I {
val a = 1
def a(x: Int) = ""
}
class C {
val a = ""
trait J extends I {
val t = a // error
}
}
}


object test7 {
trait T {
// overloaded a
val a = ""
def a(x: Int) = ""
}

trait I {
val a = 1
}

class C extends T {
trait J {
self: I =>
// no warning here. when checking for an outer `a`, we find an OverloadedSymbol with the two definitions in `T`.
// The owner of the overloaded symbol is `C`, but the alternatives have owner `T`.
val t = a
}
}
}

object test9 {
val lo: Int = 1
class P {
implicit val lo: Int = 1
}
class C extends P {
def t(implicit i: Int) = 10
def u = t // ok, reference to `lo` by implicit search
def v = t(lo) // should warn, but doesn't. can't tell if reference to `lo` was explicit or not.
}
}

object test10 {
implicit val lo: Int = 1
class P {
val lo: Int = 1
}
class C extends P {
def t(implicit i: Int) = 10
def u = t // doesn't compile in Scala 2 (maybe there's a ticket for that)
def v = t(lo) // error
}
}
18 changes: 1 addition & 17 deletions test/files/pos/t11921b.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

// scalac: -Werror -Wconf:msg=legacy-binding:s

object test1 {
Expand Down Expand Up @@ -42,26 +41,11 @@ object test3 {
}
}

object test4 {

class C {
val x = 0
}
object Test {
val x = 1
class D extends C {
def x(y: Int) = 3
val y: Int = this.x // OK
val z: Int = x // OK
}
}
}

object global

class C {
val global = 42
}
object D extends C {
println(global) // OK, since global is defined in package
println(global) // OK, since global is defined in package (https://github.com/scala/scala/pull/10220/files#r1109773904)
}

0 comments on commit 0fd61f7

Please sign in to comment.