Skip to content

Commit 6e2b576

Browse files
authored
Include top-level symbols from same file in outer ambiguity error (#17033)
2 parents 2a1e3de + 7d4e103 commit 6e2b576

File tree

5 files changed

+54
-7
lines changed

5 files changed

+54
-7
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -408,11 +408,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
408408
// Does reference `tp` refer only to inherited symbols?
409409
def isInherited(denot: Denotation) =
410410
def isCurrent(mbr: SingleDenotation): Boolean =
411-
!mbr.symbol.exists || mbr.symbol.owner == ctx.owner
411+
!mbr.symbol.exists || mbr.symbol.owner == ctx.owner || ctx.owner.is(Package)
412412
denot match
413413
case denot: SingleDenotation => !isCurrent(denot)
414414
case denot => !denot.hasAltWith(isCurrent)
415415

416+
/* It is an error if an identifier x is available as an inherited member in an inner scope
417+
* and the same name x is defined in an outer scope in the same source file, unless
418+
* the inherited member (has an overloaded alternative that) coincides with
419+
* (an overloaded alternative of) the definition x.
420+
*/
416421
def checkNoOuterDefs(denot: Denotation, last: Context, prevCtx: Context): Unit =
417422
def sameTermOrType(d1: SingleDenotation, d2: Denotation) =
418423
d2.containsSym(d1.symbol) || d2.hasUniqueSym && {
@@ -429,9 +434,15 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
429434
val owner = outer.owner
430435
if (owner eq last.owner) && (outer.scope eq last.scope) then
431436
checkNoOuterDefs(denot, outer, prevCtx)
432-
else if !owner.is(Package) then
433-
val scope = if owner.isClass then owner.info.decls else outer.scope
434-
val competing = scope.denotsNamed(name).filterWithFlags(required, excluded)
437+
else if !owner.isRoot then
438+
val found =
439+
if owner.is(Package) then
440+
owner.denot.asClass.membersNamed(name)
441+
.filterWithPredicate(d => !d.symbol.is(Package) && d.symbol.source == denot.symbol.source)
442+
else
443+
val scope = if owner.isClass then owner.info.decls else outer.scope
444+
scope.denotsNamed(name)
445+
val competing = found.filterWithFlags(required, excluded | Synthetic)
435446
if competing.exists then
436447
val symsMatch = competing
437448
.filterWithPredicate(sd => sameTermOrType(sd, denot))

tests/neg/ambiref.check

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,19 @@
3030
| and inherited subsequently in class E
3131
|
3232
| longer explanation available when compiling with `-explain`
33+
-- [E049] Reference Error: tests/neg/ambiref.scala:43:10 ---------------------------------------------------------------
34+
43 | println(global) // error
35+
| ^^^^^^
36+
| Reference to global is ambiguous.
37+
| It is both defined in package <empty>
38+
| and inherited subsequently in object D
39+
|
40+
| longer explanation available when compiling with `-explain`
41+
-- [E049] Reference Error: tests/neg/ambiref.scala:49:16 ---------------------------------------------------------------
42+
49 | def t = new T { } // error
43+
| ^
44+
| Reference to T is ambiguous.
45+
| It is both defined in package p
46+
| and inherited subsequently in class C
47+
|
48+
| longer explanation available when compiling with `-explain`

tests/neg/ambiref.scala

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,24 @@ val global = 0
4040
class C:
4141
val global = 1
4242
object D extends C:
43-
println(global) // OK, since global is defined in package
43+
println(global) // error
44+
45+
package p:
46+
class T
47+
trait P { trait T }
48+
class C extends P:
49+
def t = new T { } // error
50+
51+
package scala:
52+
trait P { trait Option[+A] }
53+
class C extends P:
54+
def t = new Option[String] { } // OK, competing scala.Option is not defined in the same compilation unit
55+
56+
object test5:
57+
class Mu // generates a synthetic companion object with an apply method
58+
trait A {
59+
val Mu = 1
60+
}
61+
trait B extends A {
62+
def t = Mu // don't warn about synthetic companion
63+
}

tests/pos-special/fatal-warnings/i9260.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ end AstImpl
1010

1111
object untpd extends AstImpl[Null]:
1212

13-
def DefDef(ast: Ast): DefDef = ast match
13+
def DefDef(ast: this.Ast): DefDef = ast match
1414
case ast: DefDef => ast
1515

1616
end untpd

tests/run/protectedacc.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ package p {
134134

135135
abstract class X[T] extends PolyA[T] {
136136

137-
trait Inner extends B {
137+
trait Inner extends this.B {
138138
def self: T;
139139
def self2: Node;
140140
def getB: Inner;

0 commit comments

Comments
 (0)