diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index c1cb474a3405..8ca6cedf43a2 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -644,7 +644,7 @@ object Trees { /** >: lo <: hi */ case class TypeBoundsTree[-T >: Untyped] private[ast] (lo: Tree[T], hi: Tree[T]) - extends Tree[T] { + extends TypTree[T] { type ThisTree[-T >: Untyped] = TypeBoundsTree[T] } diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index d46a8387fdf0..da8263ac1a3f 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -715,10 +715,28 @@ class TypeComparer(initctx: Context) extends DotClass { /** Two types are the same if are mutual subtypes of each other */ def isSameType(tp1: Type, tp2: Type): Boolean = - if (tp1 == NoType || tp2 == NoType) false + if (tp1 eq NoType) false else if (tp1 eq tp2) true else isSubType(tp1, tp2) && isSubType(tp2, tp1) + /** Same as `isSameType` but also can be applied to overloaded TermRefs, where + * two overloaded refs are the same if they have pairwise equal alternatives + */ + def isSameRef(tp1: Type, tp2: Type): Boolean = ctx.traceIndented(s"isSameRef($tp1, $tp2") { + def isSubRef(tp1: Type, tp2: Type): Boolean = tp1 match { + case tp1: TermRef if tp1.isOverloaded => + tp1.alternatives forall (isSubRef(_, tp2)) + case _ => + tp2 match { + case tp2: TermRef if tp2.isOverloaded => + tp2.alternatives exists (isSubRef(tp1, _)) + case _ => + isSubType(tp1, tp2) + } + } + isSubRef(tp1, tp2) && isSubRef(tp2, tp1) + } + /** The greatest lower bound of two types */ def glb(tp1: Type, tp2: Type): Type = /*>|>*/ ctx.traceIndented(s"glb(${tp1.show}, ${tp2.show})", typr, show = true) /*<|<*/ { if (tp1 eq tp2) tp1 diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index f9c8aad5cb68..bb30d9a9c7a6 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -1140,7 +1140,7 @@ object Types { override def isOverloaded(implicit ctx: Context) = denot.isOverloaded private def rewrap(sd: SingleDenotation)(implicit ctx: Context) = - TermRef(prefix, name, sd) + TermRef.withSig(prefix, name, sd.signature, sd) def alternatives(implicit ctx: Context): List[TermRef] = denot.alternatives map rewrap diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 6cc3a226e3d5..4c4920e5ba40 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -88,7 +88,6 @@ class Typer extends Namer with Applications with Implicits { if (reallyExists(mbr)) site.select(name, mbr) else { if (!site.isErroneous) { - typr.println(s"site = $site, baseClasses = ${site.baseClasses}") ctx.error( if (name == nme.CONSTRUCTOR) i"$site does not have a constructor" else i"$name is not a member of $site", pos) @@ -139,8 +138,7 @@ class Typer extends Namer with Applications with Implicits { } val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else "" val whyNot = new StringBuffer - val addendum = - alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot)) + alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot)) if (!tpe.isError) ctx.error(i"$what cannot be accessed as a member of $pre$where.$whyNot", pos) ErrorType @@ -245,7 +243,7 @@ class Typer extends Namer with Applications with Implicits { * does properly shadow the new one from an outer context. */ def checkNewOrShadowed(found: Type, newPrec: Int): Type = - if (!previous.exists || (previous =:= found)) found + if (!previous.exists || ctx.typeComparer.isSameRef(previous, found)) found else if ((prevCtx.scope eq ctx.scope) && (newPrec == definition || newPrec == namedImport && prevPrec == wildImport)) { diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 88c39231b97f..9914485ac3cb 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -41,6 +41,7 @@ class tests extends CompilerTest { @Test def pos_templateParents() = compileFile(posDir, "templateParents") @Test def pos_structural() = compileFile(posDir, "structural") @Test def pos_i39 = compileFile(posDir, "i39") + @Test def pos_overloadedAccess = compileFile(posDir, "overloadedAccess") @Test def neg_blockescapes() = compileFile(negDir, "blockescapesNeg", xerrors = 1) @Test def neg_typedapply() = compileFile(negDir, "typedapply", xerrors = 4) diff --git a/tests/pos/overloadedAccess.scala b/tests/pos/overloadedAccess.scala new file mode 100644 index 000000000000..a2d72f583ea2 --- /dev/null +++ b/tests/pos/overloadedAccess.scala @@ -0,0 +1,18 @@ +object overloadedAccess { + + trait ST { + def f(x: Object): Int = 1 + def f(x: Int): Unit = () + } + + object O extends ST { + def f(x: String): Unit = () + } + + class C extends ST { + import O._ // needs to pick inherited member because they are made visible in same scope. + val x = f("abc") + val y: Int = x + } + +}