Skip to content
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

ClassCastException: ConcreteNode cannot be cast to scala.runtime.Null$ #8634

Open
scabug opened this issue May 29, 2014 · 2 comments
Open

ClassCastException: ConcreteNode cannot be cast to scala.runtime.Null$ #8634

scabug opened this issue May 29, 2014 · 2 comments

Comments

@scabug
Copy link

scabug commented May 29, 2014

The following code will fail at runtime with a ClassCastException triggered by identity(<value>) in processContainer().

trait SelfTyped {
  type Self
}

sealed trait Container { self =>
  type Child = SelfTyped { type Self <: self.ChildSelf }
  type ChildSelf
  def children: List[Child]
}

sealed trait ExampleChild extends SelfTyped

case class Example (children: List[Example#Child]) extends Container {
  type Self = Example
  type ChildSelf = ExampleChild
}

sealed trait AbstractNode extends ExampleChild { }
sealed case class ConcreteNode () extends AbstractNode { override type Self = ConcreteNode }

object ProofOfConcept {
  def processContainer [C <: Container] (container: C): Unit = {
    container.children.foreach {
      case n: ConcreteNode =>
        identity(n) // java.lang.ClassCastException: ConcreteNode cannot be cast to scala.runtime.Null$
      case _ =>
    }
  }
}
ProofOfConcept.processContainer(Example(List(ConcreteNode())))
@scabug
Copy link
Author

scabug commented May 29, 2014

Imported From: https://issues.scala-lang.org/browse/SI-8634?orig=1
Reporter: Landon Fuller (landonf)
Affected Versions: 2.10.4, 2.11.0

@scabug
Copy link
Author

scabug commented May 29, 2014

@retronym said:
Taking a quick look at this:

A slightly leaner test case:

trait SelfTyped {
  type Self
}
 
sealed trait Container { self =>
  type Child = SelfTyped { type Self <: self.ChildSelf }
  type ChildSelf
  def child: Child
}
 
sealed trait ExampleChild extends SelfTyped
 
case class Example (child: Example#Child) extends Container {
  type Self = Example
  type ChildSelf = ExampleChild
}
 
sealed trait AbstractNode extends ExampleChild { }
sealed case class ConcreteNode () extends AbstractNode { override type Self = ConcreteNode }
 
object ProofOfConcept {
  def processContainer(container: Container): Unit = {
    val c: container.Child = container.child
    c match {
      case n: ConcreteNode => // java.lang.ClassCastException: ConcreteNode cannot be cast to scala.runtime.Null$
        n
    }
  }
}
object Test extends App {
  ProofOfConcept.processContainer(Example(ConcreteNode()))
}

Internally, I think the failure comes from our imprecise LUB/GLB computation:

this = {scala.tools.nsc.transform.patmat.MatchTranslation$MatchTranslator$BoundTree@3642}"x1: <empty>.this.SelfTyped{type Self <: container.ChildSelf} with <empty>.this.ConcreteNode{} (binder: <empty>.this.SelfTyped{type Self <: container.ChildSelf}) @ (_: <empty>.this.ConcreteNode)"

// private def typeTestStep(sub: Symbol, subPt: Type)     = step(TypeTestTreeMaker(sub, binder, subPt, glbWith(subPt))(pos))()

glb(
  SelfTyped{type Self <: container.ChildSelf} with ConcreteNode{},
  container.Child
) = Null	

A workaround is to upcast the scrutinee of the pattern match to Any before the type test on _: ConcreteNode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant