diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 458e60ddfa38..3bace406b19e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -408,12 +408,17 @@ 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) - def checkNoOuterDefs(denot: Denotation, last: Context, prevCtx: Context): Unit = + /* 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, ctx: Context, origCtx: Context): Unit = def sameTermOrType(d1: SingleDenotation, d2: Denotation) = d2.containsSym(d1.symbol) || d2.hasUniqueSym && { val sym1 = d1.symbol @@ -425,27 +430,39 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer else (sym1.isAliasType || sym2.isAliasType) && d1.info =:= d2.info } - val outer = last.outer - 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) + val outerCtx = ctx.outer + val outerOwner = outerCtx.owner + if (outerOwner eq ctx.owner) && (outerCtx.scope eq ctx.scope) then + checkNoOuterDefs(denot, outerCtx, origCtx) + else if !outerOwner.isRoot then + val found = + if outerOwner.is(Package) then + def notInPackageObject(sym: Symbol) = + sym.owner == outerOwner || // sym.owner.isPackageObject is false if sym is defined in a parent of the package object + sym.owner.isPackageObject && sym.owner.name.endsWith(str.TOPLEVEL_SUFFIX) // top-level definitions + outerOwner.denot.asClass.membersNamed(name) + .filterWithPredicate(d => !d.symbol.is(Package) + && notInPackageObject(d.symbol) + && d.symbol.source.exists + && isDefinedInCurrentUnit(d)) + else + val scope = if outerOwner.isClass then outerOwner.info.decls else outerCtx.scope + scope.denotsNamed(name) + val competing = found.filterWithFlags(required, excluded | Synthetic) if competing.exists then val symsMatch = competing .filterWithPredicate(sd => sameTermOrType(sd, denot)) .exists if !symsMatch && !suppressErrors then report.errorOrMigrationWarning( - AmbiguousReference(name, Definition, Inheritance, prevCtx)(using outer), + AmbiguousReference(name, Definition, Inheritance, origCtx)(using outerCtx), pos, from = `3.0`) if migrateTo3 then patch(Span(pos.span.start), - if prevCtx.owner == refctx.owner.enclosingClass then "this." - else s"${prevCtx.owner.name}.this.") + if origCtx.owner == refctx.owner.enclosingClass then "this." + else s"${origCtx.owner.name}.this.") else - checkNoOuterDefs(denot, outer, prevCtx) + checkNoOuterDefs(denot, outerCtx, origCtx) if isNewDefScope then val defDenot = ctx.denotNamed(name, required, excluded) diff --git a/tests/neg/ambiref.check b/tests/neg/ambiref.check index 5d701b3b3b71..32b4078f1346 100644 --- a/tests/neg/ambiref.check +++ b/tests/neg/ambiref.check @@ -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 + | 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` diff --git a/tests/neg/ambiref.scala b/tests/neg/ambiref.scala index e7a5d5efbd7e..bb48997cd465 100644 --- a/tests/neg/ambiref.scala +++ b/tests/neg/ambiref.scala @@ -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 \ No newline at end of file + 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 + } diff --git a/tests/neg/i17433.check b/tests/neg/i17433.check new file mode 100644 index 000000000000..7b2bac13b767 --- /dev/null +++ b/tests/neg/i17433.check @@ -0,0 +1,8 @@ +-- [E049] Reference Error: tests/neg/i17433.scala:9:10 ----------------------------------------------------------------- +9 | def g = f(42) // error + | ^ + | Reference to f is ambiguous. + | It is both defined in package + | and inherited subsequently in class D + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg/i17433.scala b/tests/neg/i17433.scala new file mode 100644 index 000000000000..e500c8226f0f --- /dev/null +++ b/tests/neg/i17433.scala @@ -0,0 +1,12 @@ + +class C: + def f(i: Int) = i + 1 + def f(s: String) = s + "_1" + +def f = 42 + +class D extends C: + def g = f(42) // error + +@main def test() = println: + D().g diff --git a/tests/neg/t12186.scala b/tests/neg/t12186.scala new file mode 100644 index 000000000000..040ef568f82b --- /dev/null +++ b/tests/neg/t12186.scala @@ -0,0 +1,36 @@ +package object p extends p.U { + def b: Int = 0 + trait Y +} + +package p { + trait U { + def a: Int = 0 + trait X + } + + object c + def c1 = 0 // top-level def + trait Z + trait T { + def a = 1 + def b = 1 + def c = 1 + def c1 = 1 + + trait X + trait Y + trait Z + } + + trait RR extends T { + def m1 = a // ok + def m2 = b // ok + def m3 = c // error + def m4 = c1 // error + + def n1: X // ok + def n2: Y // ok + def n3: Z // error + } +} diff --git a/tests/neg/t12186b/A.scala b/tests/neg/t12186b/A.scala new file mode 100644 index 000000000000..e1b46e235727 --- /dev/null +++ b/tests/neg/t12186b/A.scala @@ -0,0 +1,4 @@ +package object p extends p.U { + def b: Int = 0 + trait Y +} diff --git a/tests/neg/t12186b/B.scala b/tests/neg/t12186b/B.scala new file mode 100644 index 000000000000..84637fdea7d4 --- /dev/null +++ b/tests/neg/t12186b/B.scala @@ -0,0 +1,31 @@ +package p { + trait U { + def a: Int = 0 + trait X + } + + object c + def c1 = 0 // top-level def + trait Z + trait T { + def a = 1 + def b = 1 + def c = 1 + def c1 = 1 + + trait X + trait Y + trait Z + } + + trait RR extends T { + def m1 = a // ok + def m2 = b // ok + def m3 = c // error + def m4 = c1 // error + + def n1: X // ok + def n2: Y // ok + def n3: Z // error + } +} diff --git a/tests/pos-special/fatal-warnings/i9260.scala b/tests/pos-special/fatal-warnings/i9260.scala index df548f393eea..0392c1c96fa8 100644 --- a/tests/pos-special/fatal-warnings/i9260.scala +++ b/tests/pos-special/fatal-warnings/i9260.scala @@ -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 diff --git a/tests/pos/i17433a/A_1.scala b/tests/pos/i17433a/A_1.scala new file mode 100644 index 000000000000..575ef4b244e9 --- /dev/null +++ b/tests/pos/i17433a/A_1.scala @@ -0,0 +1,3 @@ +package p + +object Value diff --git a/tests/pos/i17433a/B_2.scala b/tests/pos/i17433a/B_2.scala new file mode 100644 index 000000000000..9a45c6e50d2e --- /dev/null +++ b/tests/pos/i17433a/B_2.scala @@ -0,0 +1,5 @@ +package p + +object B extends Enumeration { + val A = Value +} diff --git a/tests/pos/i17433b/p.scala b/tests/pos/i17433b/p.scala new file mode 100644 index 000000000000..42313d79f79b --- /dev/null +++ b/tests/pos/i17433b/p.scala @@ -0,0 +1,7 @@ + +package p: + trait T: + def t(i: Int) = i + 1 + def t(s: String) = s + "_1" + + package object q extends T diff --git a/tests/pos/i17433b/q.scala b/tests/pos/i17433b/q.scala new file mode 100644 index 000000000000..3923854ae2f9 --- /dev/null +++ b/tests/pos/i17433b/q.scala @@ -0,0 +1,6 @@ + +package p +package q + + class C extends T: + def c = t(42) diff --git a/tests/pos/i17433c.scala b/tests/pos/i17433c.scala new file mode 100644 index 000000000000..c091c4637e5a --- /dev/null +++ b/tests/pos/i17433c.scala @@ -0,0 +1,11 @@ + +package p: + trait T: + def t(i: Int) = i + 1 + + package object q extends T + + package q: + + class C extends T: + def c = t(42) // OK diff --git a/tests/pos/i17433d.scala b/tests/pos/i17433d.scala new file mode 100644 index 000000000000..45179966d015 --- /dev/null +++ b/tests/pos/i17433d.scala @@ -0,0 +1,13 @@ + +package p: + trait T: + def t(i: Int) = i + 1 + + package object q extends T: + override def t(i: Int) = i + 2 + def t(s: String) = s + "_2" + + package q: + + class C extends T: + def c = t(42) // OK diff --git a/tests/pos/i17433e.scala b/tests/pos/i17433e.scala new file mode 100644 index 000000000000..135eb61a3b81 --- /dev/null +++ b/tests/pos/i17433e.scala @@ -0,0 +1,12 @@ + +package p: + trait T: + def t(i: Int) = i + 1 + def t(s: String) = s + "_1" + + package object q extends T + + package q: + + class C extends T: + def c = t(42) // OK diff --git a/tests/run/protectedacc.scala b/tests/run/protectedacc.scala index a08e7201fd15..85aa3438faa3 100644 --- a/tests/run/protectedacc.scala +++ b/tests/run/protectedacc.scala @@ -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;