Skip to content

Commit

Permalink
Include top-level symbols from same file in outer ambiguity error
Browse files Browse the repository at this point in the history
When checking if an inherited definition is ambiguous with an
outer definition, include top-level outer definitions defined
in the same compilation unit.
  • Loading branch information
lrytz committed Mar 8, 2023
1 parent 0df5ae2 commit 7d4e103
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 7 deletions.
19 changes: 15 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -366,11 +366,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
// Does reference `tp` refer only to inherited symbols?
def isInherited(denot: Denotation) =
def isCurrent(mbr: SingleDenotation): Boolean =
!mbr.symbol.exists || mbr.symbol.owner == ctx.owner
!mbr.symbol.exists || mbr.symbol.owner == ctx.owner || ctx.owner.is(Package)
denot match
case denot: SingleDenotation => !isCurrent(denot)
case denot => !denot.hasAltWith(isCurrent)

/* It is an error if an identifier x is available as an inherited member in an inner scope
* and the same name x is defined in an outer scope in the same source file, unless
* the inherited member (has an overloaded alternative that) coincides with
* (an overloaded alternative of) the definition x.
*/
def checkNoOuterDefs(denot: Denotation, last: Context, prevCtx: Context): Unit =
def sameTermOrType(d1: SingleDenotation, d2: Denotation) =
d2.containsSym(d1.symbol) || d2.hasUniqueSym && {
Expand All @@ -387,9 +392,15 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
val owner = outer.owner
if (owner eq last.owner) && (outer.scope eq last.scope) then
checkNoOuterDefs(denot, outer, prevCtx)
else if !owner.is(Package) then
val scope = if owner.isClass then owner.info.decls else outer.scope
val competing = scope.denotsNamed(name).filterWithFlags(required, excluded)
else if !owner.isRoot then
val found =
if owner.is(Package) then
owner.denot.asClass.membersNamed(name)
.filterWithPredicate(d => !d.symbol.is(Package) && d.symbol.source == denot.symbol.source)
else
val scope = if owner.isClass then owner.info.decls else outer.scope
scope.denotsNamed(name)
val competing = found.filterWithFlags(required, excluded | Synthetic)
if competing.exists then
val symsMatch = competing
.filterWithPredicate(sd => sameTermOrType(sd, denot))
Expand Down
16 changes: 16 additions & 0 deletions tests/neg/ambiref.check
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,19 @@
| and inherited subsequently in class E
|
| longer explanation available when compiling with `-explain`
-- [E049] Reference Error: tests/neg/ambiref.scala:43:10 ---------------------------------------------------------------
43 | println(global) // error
| ^^^^^^
| Reference to global is ambiguous.
| It is both defined in package <empty>
| and inherited subsequently in object D
|
| longer explanation available when compiling with `-explain`
-- [E049] Reference Error: tests/neg/ambiref.scala:49:16 ---------------------------------------------------------------
49 | def t = new T { } // error
| ^
| Reference to T is ambiguous.
| It is both defined in package p
| and inherited subsequently in class C
|
| longer explanation available when compiling with `-explain`
22 changes: 21 additions & 1 deletion tests/neg/ambiref.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,24 @@ val global = 0
class C:
val global = 1
object D extends C:
println(global) // OK, since global is defined in package
println(global) // error

package p:
class T
trait P { trait T }
class C extends P:
def t = new T { } // error

package scala:
trait P { trait Option[+A] }
class C extends P:
def t = new Option[String] { } // OK, competing scala.Option is not defined in the same compilation unit

object test5:
class Mu // generates a synthetic companion object with an apply method
trait A {
val Mu = 1
}
trait B extends A {
def t = Mu // don't warn about synthetic companion
}
2 changes: 1 addition & 1 deletion tests/pos-special/fatal-warnings/i9260.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ end AstImpl

object untpd extends AstImpl[Null]:

def DefDef(ast: Ast): DefDef = ast match
def DefDef(ast: this.Ast): DefDef = ast match
case ast: DefDef => ast

end untpd
2 changes: 1 addition & 1 deletion tests/run/protectedacc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ package p {

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

trait Inner extends B {
trait Inner extends this.B {
def self: T;
def self2: Node;
def getB: Inner;
Expand Down

0 comments on commit 7d4e103

Please sign in to comment.