Description
When testing against an inner class, the pattern matcher needs to test outer pointers. Consider the following program:
class Outer {
case class Inner()
val inner: Inner = new Inner
def checkInstance(o: Outer) =
o.inner.isInstanceOf[this.Inner]
def checkPattern1(i: Any) =
i match {
case _: Inner => true
case _ => false
}
def checkPattern2(i: Any) =
i match {
case Inner() => true
case _ => false
}
def checkEquals(o: Outer) =
o.inner == inner
}
object Test {
def main(args: Array[String]) = {
val o1 = new Outer
val o2 = new Outer
assert(o1.checkInstance(o2)) // ok
assert(!o1.checkPattern1(o2.inner)) // ok under scalac, fails for dotc-compiled code
assert(!o1.checkPattern2(o2.inner)) // ok under scalac, fails for dotc-compiled code
assert(!o1.checkEquals(o2)) // ok under scalac, fails for dotc-compiled code
}
}
We expect the isInstanceOf
test in checkInstance
to return true
but the other three tests should return false
. Yes, I know it's contorted, but these Scala rules were a compromise between
not losing performance and being precise. Essentially we accept that we lose precision in isInstanceOf
because otherwise there would be no way to avoid the "outer test tax". But we demand that pattern matchers test outer pointers. Indeed you will find specific code doing that after patmat when you compile the code with scalac
:
if (x1.isInstanceOf[Outer.this.Inner].&&
((x1.asInstanceOf[Outer.this.Inner]: Outer.this.Inner).<outer>.eq(Outer.this)))
But such code is currently not emitted by dotc
which is why the last three asserts fail.
The discrepancy is the reason why the semantic names PR fails the bootstrap.