Skip to content

Fix/overloaded access #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}

Expand Down
20 changes: 19 additions & 1 deletion src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 2 additions & 4 deletions src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is executed just for side-effects?

if (!tpe.isError)
ctx.error(i"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
ErrorType
Expand Down Expand Up @@ -245,7 +243,7 @@ class Typer extends Namer with Applications with Implicits {
* does properly shadow the new one from an outer context.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have trouble understanding how checkNewOrShadowed works. It seems there are two types: a "previously found result from an inner context", and a "new one from an outer context". One is called found, and the other is called previous, I guess. But which one is which? Both ways do not (yet ;-)) make sense for me...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

found is new one.

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)) {
Expand Down
1 change: 1 addition & 0 deletions test/dotc/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
18 changes: 18 additions & 0 deletions tests/pos/overloadedAccess.scala
Original file line number Diff line number Diff line change
@@ -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
}

}