Skip to content

Commit

Permalink
Merge pull request #10456 from lrytz/t12816
Browse files Browse the repository at this point in the history
Detect symbols inherited into package objects in ambiguity warning
  • Loading branch information
lrytz committed Jul 5, 2023
2 parents 5e44bb8 + 31c5ffb commit 364ee69
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 4 deletions.
17 changes: 13 additions & 4 deletions src/compiler/scala/tools/nsc/typechecker/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1533,7 +1533,7 @@ trait Contexts { self: Analyzer =>
*
* Scala: Bindings of different kinds have a defined precedence order:
*
* 1) Definitions and declarations in lexical scope that are not top-level have the highest precedence.
* 1) Definitions and declarations in lexical scope have the highest precedence.
* 1b) Definitions and declarations that are either inherited, or made
* available by a package clause and also defined in the same compilation unit
* as the reference to them, have the next highest precedence.
Expand All @@ -1545,6 +1545,8 @@ trait Contexts { self: Analyzer =>
* as well as bindings supplied by the compiler but not explicitly written in source code,
* have the lowest precedence.
*/

/* Level 4 (see above) */
def foreignDefined = defSym.exists && thisContext.isPackageOwnedInDifferentUnit(defSym) // SI-2458

// Find the first candidate import
Expand Down Expand Up @@ -1612,15 +1614,22 @@ trait Contexts { self: Analyzer =>
val depth0 = symbolDepth
val wasFoundInSuper = foundInSuper
val foundCompetingSymbol: () => Boolean =
if (foreignDefined) () => !foreignDefined
else () => !defSym.owner.isPackageObjectOrClass && !foundInSuper && !foreignDefined
if (foreignDefined)
// if the first found symbol (defSym0) is level 4 (foreignDefined), a lower level (1 or 1b) defSym is competing
() => defSym.exists && !foreignDefined
else {
// if defSym0 is level 1 or 1b, another defSym is competing if defined in an outer scope in the same file
() => defSym.exists && !(pre.typeSymbol.isPackageClass && !defSym.owner.isPackageClass) && !foundInSuper && !foreignDefined
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// defined in package object (or inherited into package object)
}
while ((cx ne NoContext) && cx.depth >= symbolDepth) cx = cx.outer
if (wasFoundInSuper)
while ((cx ne NoContext) && (cx.owner eq cx0.owner)) cx = cx.outer
var done = false
while (!done) {
nextDefinition(defSym0, pre0)
done = (cx eq NoContext) || defSym.exists && foundCompetingSymbol()
done = (cx eq NoContext) || foundCompetingSymbol()
if (!done && (cx ne NoContext)) cx = cx.outer
}
if (defSym.exists && (defSym ne defSym0)) {
Expand Down
20 changes: 20 additions & 0 deletions test/files/neg/t12816.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
t12816.scala:8: error: package object inheritance is deprecated (https://github.com/scala/scala-dev/issues/441);
drop the `extends` clause or use a regular object instead
package object p extends U {
^
t12816.scala:29: warning: reference to c is ambiguous;
it is both defined in the enclosing package p and inherited in the enclosing trait RR as method c (defined in trait T)
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 m3 = c // warn
^
t12816.scala:33: warning: reference to Z is ambiguous;
it is both defined in the enclosing package p and inherited in the enclosing trait RR as trait Z (defined in trait T)
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.Z`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def n3: Z // warn
^
2 warnings
1 error
35 changes: 35 additions & 0 deletions test/files/neg/t12816.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// scalac: -Xsource:3 -Werror

trait U {
def a: Int = 0
trait X
}

package object p extends U {
def b: Int = 0
trait Y
}

package p {
object c
trait Z
trait T {
def a = 1
def b = 1
def c = 1

trait X
trait Y
trait Z
}

trait RR extends T {
def m1 = a // ok
def m2 = b // ok
def m3 = c // warn

def n1: X // ok
def n2: Y // ok
def n3: Z // warn
}
}
20 changes: 20 additions & 0 deletions test/files/neg/t12816b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
A.scala:5: error: package object inheritance is deprecated (https://github.com/scala/scala-dev/issues/441);
drop the `extends` clause or use a regular object instead
package object p extends U {
^
B.scala:19: warning: reference to c is ambiguous;
it is both defined in the enclosing package p and inherited in the enclosing trait RR as method c (defined in trait T)
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 m3 = c // warn
^
B.scala:23: warning: reference to Z is ambiguous;
it is both defined in the enclosing package p and inherited in the enclosing trait RR as trait Z (defined in trait T)
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.Z`.
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
def n3: Z // warn
^
2 warnings
1 error
8 changes: 8 additions & 0 deletions test/files/neg/t12816b/A.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
trait U {
def a: Int = 0
trait X
}
package object p extends U {
def b: Int = 0
trait Y
}
25 changes: 25 additions & 0 deletions test/files/neg/t12816b/B.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// scalac: -Xsource:3 -Werror

package p {
object c
trait Z
trait T {
def a = 1
def b = 1
def c = 1

trait X
trait Y
trait Z
}

trait RR extends T {
def m1 = a // ok
def m2 = b // ok
def m3 = c // warn

def n1: X // ok
def n2: Y // ok
def n3: Z // warn
}
}

0 comments on commit 364ee69

Please sign in to comment.