Skip to content

Pattern matcher needs to check for outer #2156

Closed
@odersky

Description

@odersky

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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions