Skip to content

Commit 7d4e103

Browse files
committed
Include top-level symbols from same file in outer ambiguity error
When checking if an inherited definition is ambiguous with an outer definition, include top-level outer definitions defined in the same compilation unit.
1 parent 0df5ae2 commit 7d4e103

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
@@ -366,11 +366,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
366366
// Does reference `tp` refer only to inherited symbols?
367367
def isInherited(denot: Denotation) =
368368
def isCurrent(mbr: SingleDenotation): Boolean =
369-
!mbr.symbol.exists || mbr.symbol.owner == ctx.owner
369+
!mbr.symbol.exists || mbr.symbol.owner == ctx.owner || ctx.owner.is(Package)
370370
denot match
371371
case denot: SingleDenotation => !isCurrent(denot)
372372
case denot => !denot.hasAltWith(isCurrent)
373373

374+
/* It is an error if an identifier x is available as an inherited member in an inner scope
375+
* and the same name x is defined in an outer scope in the same source file, unless
376+
* the inherited member (has an overloaded alternative that) coincides with
377+
* (an overloaded alternative of) the definition x.
378+
*/
374379
def checkNoOuterDefs(denot: Denotation, last: Context, prevCtx: Context): Unit =
375380
def sameTermOrType(d1: SingleDenotation, d2: Denotation) =
376381
d2.containsSym(d1.symbol) || d2.hasUniqueSym && {
@@ -387,9 +392,15 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
387392
val owner = outer.owner
388393
if (owner eq last.owner) && (outer.scope eq last.scope) then
389394
checkNoOuterDefs(denot, outer, prevCtx)
390-
else if !owner.is(Package) then
391-
val scope = if owner.isClass then owner.info.decls else outer.scope
392-
val competing = scope.denotsNamed(name).filterWithFlags(required, excluded)
395+
else if !owner.isRoot then
396+
val found =
397+
if owner.is(Package) then
398+
owner.denot.asClass.membersNamed(name)
399+
.filterWithPredicate(d => !d.symbol.is(Package) && d.symbol.source == denot.symbol.source)
400+
else
401+
val scope = if owner.isClass then owner.info.decls else outer.scope
402+
scope.denotsNamed(name)
403+
val competing = found.filterWithFlags(required, excluded | Synthetic)
393404
if competing.exists then
394405
val symsMatch = competing
395406
.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)