diff options
author | Martin Odersky <odersky@gmail.com> | 2014-03-04 13:49:45 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-03-04 13:49:50 +0100 |
commit | f196e074c41f7ccde118dcf6764898a2c26fda3a (patch) | |
tree | 7427249f21c5879dff53d9dbaf1f17736944e9fb | |
parent | 340ec6150b205287e1c0f5a0422d2186c29bc086 (diff) | |
download | dotty-f196e074c41f7ccde118dcf6764898a2c26fda3a.tar.gz dotty-f196e074c41f7ccde118dcf6764898a2c26fda3a.tar.bz2 dotty-f196e074c41f7ccde118dcf6764898a2c26fda3a.zip |
Fix of #39
Two fixes:
1) Avoid the infinite recursion in checkAccessible if the accessibility check fails.
2) Make accessibility succeed for the test, and in general if the target denotation does not have a symbol.
Added original test in pos and a negative test which makes accessibility fail.
-rw-r--r-- | src/dotty/tools/dotc/core/Denotations.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 69 | ||||
-rw-r--r-- | test/dotc/tests.scala | 2 | ||||
-rw-r--r-- | tests/neg/i39.scala | 19 | ||||
-rw-r--r-- | tests/pos/i39.scala | 17 |
5 files changed, 75 insertions, 34 deletions
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 9c8de3829..00b6815e7 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -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 diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 96fe73e7d..6cc3a226e 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -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)) + 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 diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 4e7d277dd..88c39231b 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -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") @Test def neg_blockescapes() = compileFile(negDir, "blockescapesNeg", xerrors = 1) @Test def neg_typedapply() = compileFile(negDir, "typedapply", xerrors = 4) @@ -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) @Test def dotc = compileDir(dotcDir + "tools/dotc") @Test def dotc_ast = compileDir(dotcDir + "tools/dotc/ast") diff --git a/tests/neg/i39.scala b/tests/neg/i39.scala new file mode 100644 index 000000000..250947df9 --- /dev/null +++ b/tests/neg/i39.scala @@ -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 = ??? + +} diff --git a/tests/pos/i39.scala b/tests/pos/i39.scala new file mode 100644 index 000000000..5cbaee35d --- /dev/null +++ b/tests/pos/i39.scala @@ -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 = ??? + +} |