Skip to content

Fix of #39 #42

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

Merged
merged 1 commit into from
Mar 6, 2014
Merged
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/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ object Denotations {
exists && p(this)

def accessibleFrom(pre: Type, superAccess: Boolean)(implicit ctx: Context): Denotation =
if (symbol isAccessibleFrom (pre, superAccess)) this else NoDenotation
if (!symbol.exists || symbol.isAccessibleFrom(pre, superAccess)) this else NoDenotation

def atSignature(sig: Signature)(implicit ctx: Context): SingleDenotation =
if (sig matches signature) this else NoDenotation
Expand Down
69 changes: 36 additions & 33 deletions src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,40 +116,43 @@ class Typer extends Namer with Applications with Implicits {
* current context. Return the type with those alternatives as denotations
* which are accessible.
*/
def checkAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = tpe match {
case tpe: NamedType =>
val pre = tpe.prefix
val name = tpe.name
val d = tpe.denot.accessibleFrom(pre, superAccess)
if (!d.exists) {
val d2 = pre.nonPrivateMember(name)
if (reallyExists(d2) && (d2 ne tpe.denot))
checkAccessible(pre.select(name, d2), superAccess, pos)
else {
val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists)
val what = alts match {
case Nil =>
name.toString
case sym :: Nil =>
if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated
case _ =>
i"none of the overloaded alternatives named $name"
def checkAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = {
def test(tpe: Type, firstTry: Boolean): Type = tpe match {
case tpe: NamedType =>
val pre = tpe.prefix
val name = tpe.name
val d = tpe.denot.accessibleFrom(pre, superAccess)
if (!d.exists) {
// it could be that we found an inaccessbile private member, but there is
// an inherited non-private member with the same name and signature.
val d2 = pre.nonPrivateMember(name)
if (reallyExists(d2) && firstTry) test(pre.select(name, d2), false)
else {
val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists)
val what = alts match {
case Nil =>
name.toString
case sym :: Nil =>
if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated
case _ =>
i"none of the overloaded alternatives named $name"
}
val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else ""
val whyNot = new StringBuffer
val addendum =
alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot))
Copy link
Contributor

Choose a reason for hiding this comment

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

why do you assign Unit to a val?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. I will do a shortcut in the interest of time and fix it in the next commit.

if (!tpe.isError)
ctx.error(i"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
ErrorType
}
val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else ""
val whyNot = new StringBuffer
val addendum =
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
}
}
else if (d.symbol is TypeParamAccessor) // always dereference type param accessors
checkAccessible(d.info.bounds.hi, superAccess, pos)
else
tpe withDenot d
case _ =>
tpe
} else if (d.symbol is TypeParamAccessor) // always dereference type param accessors
checkAccessible(d.info.bounds.hi, superAccess, pos)
else
tpe withDenot d
case _ =>
tpe
}
test(tpe, true)
}

/** The enclosing class, except if we are in a super call, in which case
Expand Down
2 changes: 2 additions & 0 deletions test/dotc/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class tests extends CompilerTest {
@Test def pos_overloaded() = compileFile(posDir, "overloaded")
@Test def pos_templateParents() = compileFile(posDir, "templateParents")
@Test def pos_structural() = compileFile(posDir, "structural")
@Test def pos_i39 = compileFile(posDir, "i39")
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be good to have a http link for this issue on github, as "i39" is not so obvious.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think should have a naming convention for issue tests, then it will become obvious. Scala 2 has t123, should we do the same or stick with i123?

Copy link
Contributor

Choose a reason for hiding this comment

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

Having such convention seems good idea.
I'd prefer i123.


@Test def neg_blockescapes() = compileFile(negDir, "blockescapesNeg", xerrors = 1)
@Test def neg_typedapply() = compileFile(negDir, "typedapply", xerrors = 4)
Expand All @@ -49,6 +50,7 @@ class tests extends CompilerTest {
@Test def neg_privates() = compileFile(negDir, "privates", xerrors = 2)
@Test def neg_rootImports = compileFile(negDir, "rootImplicits", xerrors = 2)
@Test def neg_templateParents() = compileFile(negDir, "templateParents", xerrors = 3)
@Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here


@Test def dotc = compileDir(dotcDir + "tools/dotc")
@Test def dotc_ast = compileDir(dotcDir + "tools/dotc/ast")
Expand Down
19 changes: 19 additions & 0 deletions tests/neg/i39.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
object i39neg {

trait B {
type D <: { type T }
def d: D
}

val bc: B = new B {
def d: D = ???
private def pd: D = ???
}

val d: bc.D = bc.d
val pd: bc.D = bc.pd

// infinite loop in Typer
val asT: d.T = ???

}
17 changes: 17 additions & 0 deletions tests/pos/i39.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
object i39 {

trait B {
type D <: { type T }
def d: D
}

val bc: B = new B {
def d: D = ???
}

val d: bc.D = bc.d

// infinite loop in Typer
val asT: d.T = ???

}