summaryrefslogtreecommitdiff
path: root/test/files/run/patmat_unapp_abstype-new.scala
diff options
context:
space:
mode:
Diffstat (limited to 'test/files/run/patmat_unapp_abstype-new.scala')
-rw-r--r--test/files/run/patmat_unapp_abstype-new.scala83
1 files changed, 83 insertions, 0 deletions
diff --git a/test/files/run/patmat_unapp_abstype-new.scala b/test/files/run/patmat_unapp_abstype-new.scala
new file mode 100644
index 0000000000..45496f08a2
--- /dev/null
+++ b/test/files/run/patmat_unapp_abstype-new.scala
@@ -0,0 +1,83 @@
+// abstract types and extractors, oh my!
+trait TypesAPI {
+ trait Type
+
+ // an alternative fix (implemented in the virtual pattern matcher, is to replace the isInstanceOf by a manifest-based run-time test)
+ // that's what typeRefMani is for
+ type TypeRef <: Type //; implicit def typeRefMani: Manifest[TypeRef]
+ val TypeRef: TypeRefExtractor; trait TypeRefExtractor {
+ def apply(x: Int): TypeRef
+ def unapply(x: TypeRef): Option[(Int)]
+ }
+
+ // just for illustration, should follow the same pattern as TypeRef
+ case class MethodType(n: Int) extends Type
+}
+
+// user should not be exposed to the implementation
+trait TypesUser extends TypesAPI {
+ def shouldNotCrash(tp: Type): Unit = {
+ tp match {
+ case TypeRef(x) => println("TypeRef")
+ // the above checks tp.isInstanceOf[TypeRef], which is erased to tp.isInstanceOf[Type]
+ // before calling TypeRef.unapply(tp), which will then crash unless tp.isInstanceOf[TypesImpl#TypeRef] (which is not implied by tp.isInstanceOf[Type])
+ // tp.isInstanceOf[TypesImpl#TypeRef] is equivalent to classOf[TypesImpl#TypeRef].isAssignableFrom(tp.getClass)
+ // this is equivalent to manifest
+ // it is NOT equivalent to manifest[Type] <:< typeRefMani
+ case MethodType(x) => println("MethodType")
+ case _ => println("none of the above")
+ }
+ }
+}
+
+trait TypesImpl extends TypesAPI {
+ object TypeRef extends TypeRefExtractor // this will have a bridged unapply(x: Type) = unapply(x.asInstanceOf[TypeRef])
+ case class TypeRef(n: Int) extends Type // this has a bridge from TypesAPI#Type to TypesImpl#TypeRef
+ // --> the cast in the bridge will fail because the pattern matcher can't type test against the abstract types in TypesUser
+ //lazy val typeRefMani = manifest[TypeRef]
+}
+
+trait Foos {
+ trait Bar
+ type Foo <: Bar
+ trait FooExtractor {
+ def unapply(foo: Foo): Option[Int]
+ }
+ val Foo: FooExtractor
+}
+
+trait RealFoos extends Foos {
+ class Foo(val x: Int) extends Bar
+ object Foo extends FooExtractor {
+ def unapply(foo: Foo): Option[Int] = Some(foo.x)
+ }
+}
+
+trait Intermed extends Foos {
+ def crash(bar: Bar): Unit =
+ bar match {
+ case Foo(x) => println("Foo")
+ case _ => println("Bar")
+ }
+}
+
+object TestUnappStaticallyKnownSynthetic extends TypesImpl with TypesUser {
+ def test() = {
+ shouldNotCrash(TypeRef(10)) // should and does print "TypeRef"
+ // once #1697/#2337 are fixed, this should generate the correct output
+ shouldNotCrash(MethodType(10)) // should print "MethodType" but prints "none of the above" -- good one, pattern matcher!
+ }
+}
+
+object TestUnappDynamicSynth extends RealFoos with Intermed {
+ case class FooToo(n: Int) extends Bar
+ def test() = {
+ crash(FooToo(10))
+ crash(new Foo(5))
+ }
+}
+
+object Test extends App {
+ TestUnappStaticallyKnownSynthetic.test()
+ TestUnappDynamicSynth.test()
+}