Skip to content

Commit 8bbbd54

Browse files
authored
Merge pull request #10297 from lrytz/t11921-backport
2 parents de8fa1e + b6a26e5 commit 8bbbd54

10 files changed

Lines changed: 379 additions & 5 deletions

File tree

src/compiler/scala/tools/nsc/typechecker/Contexts.scala

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,27 @@ trait Contexts { self: Analyzer =>
5656
LookupAmbiguous(s"it is imported twice in the same scope by\n$imp1\nand $imp2")
5757
def ambiguousDefnAndImport(owner: Symbol, imp: ImportInfo) =
5858
LookupAmbiguous(s"it is both defined in $owner and imported subsequently by \n$imp")
59-
59+
def ambiguousWithEnclosing(sym: Symbol, other: Symbol, otherEnclClass: Symbol) =
60+
if (!currentRun.isScala213) None else {
61+
val enclDesc = if (otherEnclClass.isAnonymousClass) "anonymous class" else otherEnclClass.toString
62+
val parent = otherEnclClass.parentSymbols.find(_.isNonBottomSubClass(other.owner)).getOrElse(NoSymbol)
63+
val inherit = if (parent.exists && parent != other.owner) s", inherited through parent $parent" else ""
64+
val message =
65+
s"""it is both defined in the enclosing ${sym.owner} and available in the enclosing $enclDesc as $other (defined in ${other.ownsString}$inherit)
66+
|Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
67+
|To continue using the symbol from the superclass, write `this.${sym.name}`.""".stripMargin
68+
if (currentRun.isScala3)
69+
Some(LookupAmbiguous(message))
70+
else {
71+
// passing the message to `typedIdent` as attachment, we don't have the position here to report the warning
72+
other.updateAttachment(
73+
LookupAmbiguityWarning(
74+
s"""reference to ${sym.name} is ambiguous;
75+
|$message
76+
|Or use `-Wconf:msg=legacy-binding:s` to silence this warning.""".stripMargin))
77+
None
78+
}
79+
}
6080
private lazy val startContext = NoContext.make(
6181
Template(List(), noSelfType, List()) setSymbol global.NoSymbol setType global.NoType,
6282
rootMirror.RootClass,
@@ -1228,16 +1248,48 @@ trait Contexts { self: Analyzer =>
12281248
return finishDefSym(constructorSym, cx.enclClass.prefix)
12291249
}
12301250

1251+
var foundInSuper: Boolean = false
1252+
var outerDefSym: Symbol = NoSymbol
1253+
12311254
// cx.scope eq null arises during FixInvalidSyms in Duplicators
12321255
while (defSym == NoSymbol && (cx ne NoContext) && (cx.scope ne null)) {
12331256
pre = cx.enclClass.prefix
12341257
defSym = lookupInScope(cx.owner, cx.enclClass.prefix, cx.scope) match {
1235-
case NoSymbol => searchPrefix
1236-
case found => found
1258+
case NoSymbol =>
1259+
val prefixSym = searchPrefix
1260+
if (currentRun.isScala213 && prefixSym.exists && prefixSym.owner != cx.owner)
1261+
foundInSuper = true
1262+
prefixSym
1263+
case found =>
1264+
found
12371265
}
12381266
if (!defSym.exists)
12391267
cx = cx.outer // push further outward
12401268
}
1269+
1270+
val defPre = pre
1271+
val defCx = cx
1272+
1273+
while (foundInSuper && (cx ne NoContext) && (cx.scope ne null)) {
1274+
pre = cx.enclClass.prefix
1275+
val next = lookupInScope(cx.owner, cx.enclClass.prefix, cx.scope).orElse(searchPrefix)
1276+
if (next.exists && next.owner == cx.owner && thisContext.unit.exists && next.sourceFile == thisContext.unit.source.file) {
1277+
outerDefSym = next
1278+
cx = NoContext
1279+
} else
1280+
cx = cx.outer
1281+
}
1282+
if (outerDefSym.exists) {
1283+
if ((defSym.isAliasType || outerDefSym.isAliasType) && defPre.memberType(defSym) =:= pre.memberType(outerDefSym))
1284+
outerDefSym = NoSymbol
1285+
if (defSym.isStable && outerDefSym.isStable &&
1286+
(pre.memberType(outerDefSym).termSymbol == defSym || defPre.memberType(defSym).termSymbol == outerDefSym))
1287+
outerDefSym = NoSymbol
1288+
}
1289+
1290+
pre = defPre
1291+
cx = defCx
1292+
12411293
if (symbolDepth < 0)
12421294
symbolDepth = cx.depth
12431295

@@ -1305,8 +1357,12 @@ trait Contexts { self: Analyzer =>
13051357
}
13061358

13071359
// At this point only one or the other of defSym and impSym might be set.
1308-
if (defSym.exists) finishDefSym(defSym, pre)
1309-
else if (impSym.exists) {
1360+
if (defSym.exists) {
1361+
val ambiguity =
1362+
if (outerDefSym.exists) ambiguousWithEnclosing(outerDefSym, defSym, cx.enclClass.owner)
1363+
else None
1364+
ambiguity.getOrElse(finishDefSym(defSym, pre))
1365+
} else if (impSym.exists) {
13101366
// If we find a competitor imp2 which imports the same name, possible outcomes are:
13111367
//
13121368
// - same depth, imp1 wild, imp2 explicit: imp2 wins, drop imp1

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5275,6 +5275,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
52755275
case sym => typed1(tree setSymbol sym, mode, pt)
52765276
}
52775277
case LookupSucceeded(qual, sym) =>
5278+
sym.getAndRemoveAttachment[LookupAmbiguityWarning].foreach(w =>
5279+
runReporting.warning(tree.pos, w.msg, WarningCategory.Other, context.owner))
52785280
(// this -> Foo.this
52795281
if (sym.isThisSym)
52805282
typed1(This(sym.owner) setPos tree.pos, mode, pt)

src/reflect/scala/reflect/internal/StdAttachments.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,6 @@ trait StdAttachments {
131131

132132
// When typing a Def with this attachment, change the owner of its RHS from origalOwner to the symbol of the Def
133133
case class ChangeOwnerAttachment(originalOwner: Symbol)
134+
135+
case class LookupAmbiguityWarning(msg: String) extends PlainAttachment
134136
}

src/reflect/scala/reflect/runtime/JavaUniverseForce.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
6868
this.TypeParamVarargsAttachment
6969
this.KnownDirectSubclassesCalled
7070
this.ChangeOwnerAttachment
71+
this.LookupAmbiguityWarning
7172
this.noPrint
7273
this.typeDebug
7374
// inaccessible: this.posAssigner

test/files/neg/t11921-alias.check

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
t11921-alias.scala:18: warning: reference to TT is ambiguous;
2+
it is both defined in the enclosing object O and available in the enclosing class D as type TT (defined in class C)
3+
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
4+
To continue using the symbol from the superclass, write `this.TT`.
5+
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
6+
def n(x: TT) = x // ambiguous
7+
^
8+
t11921-alias.scala:38: warning: reference to c is ambiguous;
9+
it is both defined in the enclosing class B and available in the enclosing anonymous class as value c (defined in class A)
10+
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
11+
To continue using the symbol from the superclass, write `this.c`.
12+
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
13+
def n = c // ambiguous
14+
^
15+
t11921-alias.scala:57: warning: reference to name is ambiguous;
16+
it is both defined in the enclosing method m and available in the enclosing anonymous class as value name (defined in class C)
17+
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
18+
To continue using the symbol from the superclass, write `this.name`.
19+
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
20+
println(name)
21+
^
22+
t11921-alias.scala:67: warning: reference to name is ambiguous;
23+
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)
24+
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
25+
To continue using the symbol from the superclass, write `this.name`.
26+
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
27+
println(name)
28+
^
29+
error: No warnings can be incurred under -Xfatal-warnings.
30+
four warnings found
31+
one error found

test/files/neg/t11921-alias.scala

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// scalac: -Xfatal-warnings -Xsource:2.13
2+
3+
object t1 {
4+
class C[T] { type TT = T }
5+
object O {
6+
type TT = String
7+
class D extends C[TT] {
8+
def n(x: TT) = x // OK
9+
}
10+
}
11+
}
12+
13+
object t2 {
14+
class C[T] { type TT <: T }
15+
object O {
16+
type TT = String
17+
class D extends C[TT] {
18+
def n(x: TT) = x // ambiguous
19+
}
20+
}
21+
}
22+
23+
object t3 {
24+
trait Context
25+
class A[C <: Context](val c: C)
26+
class B(val c: Context) { b =>
27+
val a = new A[c.type](c) {
28+
def n = c // OK
29+
}
30+
}
31+
}
32+
33+
object t4 {
34+
trait Context
35+
class A[C <: Context](val c: C)
36+
class B(val c: Context) { b =>
37+
val a = new A(c) {
38+
def n = c // ambiguous
39+
}
40+
}
41+
}
42+
43+
object t5 {
44+
trait TT
45+
class K[T <: TT](val t: T)
46+
class C {
47+
def f(t: TT) = new K[t.type](t) {
48+
def test = t
49+
}
50+
}
51+
}
52+
53+
object t6 {
54+
class C(val name: String)
55+
object Test {
56+
def m(name: String) = new C(name) {
57+
println(name)
58+
}
59+
}
60+
}
61+
62+
object t7 {
63+
abstract class A(val name: String)
64+
class C(name: String) extends A(name)
65+
object Test {
66+
def m(name: String) = new C(name) {
67+
println(name)
68+
}
69+
}
70+
}

test/files/neg/t11921b.check

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
t11921b.scala:11: warning: reference to x is ambiguous;
2+
it is both defined in the enclosing object Test and available in the enclosing class D as value x (defined in class C)
3+
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
4+
To continue using the symbol from the superclass, write `this.x`.
5+
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
6+
println(x) // error
7+
^
8+
t11921b.scala:15: warning: reference to x is ambiguous;
9+
it is both defined in the enclosing object Test and available in the enclosing anonymous class as value x (defined in class C)
10+
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
11+
To continue using the symbol from the superclass, write `this.x`.
12+
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
13+
println(x) // error
14+
^
15+
t11921b.scala:26: warning: reference to y is ambiguous;
16+
it is both defined in the enclosing method c and available in the enclosing anonymous class as value y (defined in class D)
17+
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
18+
To continue using the symbol from the superclass, write `this.y`.
19+
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
20+
println(y) // error
21+
^
22+
t11921b.scala:38: warning: reference to y is ambiguous;
23+
it is both defined in the enclosing method c and available in the enclosing class E as value y (defined in class D)
24+
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
25+
To continue using the symbol from the superclass, write `this.y`.
26+
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
27+
println(y) // error
28+
^
29+
t11921b.scala:65: warning: reference to global is ambiguous;
30+
it is both defined in the enclosing package <empty> and available in the enclosing object D as value global (defined in class C)
31+
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
32+
To continue using the symbol from the superclass, write `this.global`.
33+
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
34+
println(global) // error
35+
^
36+
t11921b.scala:75: warning: reference to x is ambiguous;
37+
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)
38+
Since Scala 3, symbols inherited from a superclass no longer shadow symbols defined in an outer scope.
39+
To continue using the symbol from the superclass, write `this.x`.
40+
Or use `-Wconf:msg=legacy-binding:s` to silence this warning.
41+
def t = x // ambiguous, message mentions parent B
42+
^
43+
error: No warnings can be incurred under -Xfatal-warnings.
44+
6 warnings found
45+
one error found

test/files/neg/t11921b.scala

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// scalac: -Xfatal-warnings -Xsource:2.13
2+
3+
object test1 {
4+
5+
class C {
6+
val x = 0
7+
}
8+
object Test {
9+
val x = 1
10+
class D extends C {
11+
println(x) // error
12+
}
13+
def f() =
14+
new C {
15+
println(x) // error
16+
}
17+
}
18+
}
19+
20+
object test2 {
21+
def c(y: Float) = {
22+
class D {
23+
val y = 2
24+
}
25+
new D {
26+
println(y) // error
27+
}
28+
}
29+
}
30+
31+
object test3 {
32+
def c(y: Float) = {
33+
class D {
34+
val y = 2
35+
}
36+
class E extends D {
37+
class F {
38+
println(y) // error
39+
}
40+
}
41+
}
42+
}
43+
44+
object test4 {
45+
46+
class C {
47+
val x = 0
48+
}
49+
object Test {
50+
val x = 1
51+
class D extends C {
52+
def x(y: Int) = 3
53+
val y: Int = this.x // OK
54+
val z: Int = x // OK
55+
}
56+
}
57+
}
58+
59+
object global
60+
61+
class C {
62+
val global = 42
63+
}
64+
object D extends C {
65+
println(global) // error
66+
}
67+
68+
object test5 {
69+
class A { val x = 1 }
70+
class B extends A
71+
object Uhu {
72+
val x = 2
73+
class C extends B {
74+
class Inner {
75+
def t = x // ambiguous, message mentions parent B
76+
}
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)