Permalink
Browse files

Closes SI-5354.

The reason why the test case compiled without error is pretty  devious: When checking the `Foo.x' implicit, a CyclicReference error occurs which causes the alternative to be discarded. Why a CylicReference? Because the inferencer tries to decide whether the owner of `z` is a subclass of the owner od `x`. To do this, it computed the info of the owner of `z1`, which is not complete because no result type for `f1` was given. Hence a CyclicReference error.

The fix is twofold: (1) We make isNonBottomSubClass smarter so that it always returns false if the symbol in question is not a type; hence the info need not be computed. (2) It's dubious to swallow CyclicReference errors anywhere, but I deemed it too risky to propagate them. But at least the CyclicReference is now logged if -Ylog-implicit is true. This hopefully spares future maintainers the same detective work I had to go through when digging this out.
  • Loading branch information...
odersky committed Jan 4, 2012
1 parent 471a63a commit fafbffc2950aa3f25f91575786093e044f9af549
@@ -1244,12 +1244,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
final def isNestedIn(that: Symbol): Boolean =
owner == that || owner != NoSymbol && (owner isNestedIn that)
/** Is this class symbol a subclass of that symbol? */
final def isNonBottomSubClass(that: Symbol): Boolean = (
(this eq that) || this.isError || that.isError ||
info.baseTypeIndex(that) >= 0
)
/** Is this class symbol a subclass of that symbol,
* and is this class symbol also different from Null or Nothing? */
def isNonBottomSubClass(that: Symbol): Boolean = false
/** Overridden in NullClass and NothingClass for custom behavior.
*/
@@ -2226,6 +2224,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
super.info_=(tp)
}
final override def isNonBottomSubClass(that: Symbol): Boolean = (
(this eq that) || this.isError || that.isError ||
info.baseTypeIndex(that) >= 0
)
override def reset(completer: Type) {
super.reset(completer)
tpePeriod = NoPeriod
@@ -816,7 +816,14 @@ trait Implicits {
val newPending = undoLog undo {
is filterNot (alt => alt == i || {
try improves(i, alt)
catch { case e: CyclicReference => true }
catch {
case e: CyclicReference =>
if (printInfers) {
println(i+" discarded because cyclic reference occurred")
e.printStackTrace()
}
true
}
})
}
rankImplicits(newPending, i :: acc)
@@ -0,0 +1,7 @@
t5354.scala:9: error: ambiguous implicit values:
both method x123 in package foo of type => foo.Bippy
and method z of type => foo.Bippy
match expected type foo.Bippy
implicitly[Bippy]
^
one error found
@@ -0,0 +1,15 @@
package object foo {
implicit def x123: Bippy = new Bippy("x")
}
package foo {
class Bippy(override val toString: String){ }
class Dingus {
def f1 = {
implicit def z: Bippy = new Bippy("z")
implicitly[Bippy]
}
}
object Test extends App {
println(new Dingus().f1)
}
}

0 comments on commit fafbffc

Please sign in to comment.