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

Detect symbols inherited into package objects in ambiguity warning #10456

Merged
merged 1 commit into from
Jul 5, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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.
som-snytt marked this conversation as resolved.
Show resolved Hide resolved
* 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
}
}