From 1cd7a9e840158dab17a3aafc0ce849605706a561 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 17 Aug 2013 09:58:54 -0700 Subject: New tests for name-based pattern matcher. --- test/files/jvm/opt_value_class.check | 2 + test/files/jvm/opt_value_class/Value_1.scala | 28 +++++ test/files/jvm/opt_value_class/test.scala | 16 +++ test/files/neg/t7214neg.check | 7 ++ test/files/neg/t7214neg.scala | 57 ++++++++++ test/files/neg/t7721.check | 21 ++++ test/files/neg/t7721.flags | 1 + test/files/neg/t7721.scala | 140 +++++++++++++++++++++++++ test/files/pos/extractor-types.scala | 30 ++++++ test/files/pos/optmatch.scala | 33 ++++++ test/files/pos/overloaded-unapply.scala | 8 ++ test/files/run/name-based-patmat.check | 10 ++ test/files/run/name-based-patmat.scala | 75 +++++++++++++ test/files/run/patmat-behavior-2.check | 24 +++++ test/files/run/patmat-behavior-2.scala | 50 +++++++++ test/files/run/patmat-behavior.check | 90 ++++++++++++++++ test/files/run/patmat-behavior.scala | 95 +++++++++++++++++ test/files/run/value-class-extractor-2.check | 8 ++ test/files/run/value-class-extractor-2.scala | 108 +++++++++++++++++++ test/files/run/value-class-extractor-seq.check | 3 + test/files/run/value-class-extractor-seq.scala | 59 +++++++++++ test/files/run/value-class-extractor.check | 9 ++ test/files/run/value-class-extractor.scala | 91 ++++++++++++++++ 23 files changed, 965 insertions(+) create mode 100644 test/files/jvm/opt_value_class.check create mode 100644 test/files/jvm/opt_value_class/Value_1.scala create mode 100644 test/files/jvm/opt_value_class/test.scala create mode 100644 test/files/neg/t7214neg.check create mode 100644 test/files/neg/t7214neg.scala create mode 100644 test/files/neg/t7721.check create mode 100644 test/files/neg/t7721.flags create mode 100644 test/files/neg/t7721.scala create mode 100644 test/files/pos/extractor-types.scala create mode 100644 test/files/pos/optmatch.scala create mode 100644 test/files/pos/overloaded-unapply.scala create mode 100644 test/files/run/name-based-patmat.check create mode 100644 test/files/run/name-based-patmat.scala create mode 100644 test/files/run/patmat-behavior-2.check create mode 100644 test/files/run/patmat-behavior-2.scala create mode 100644 test/files/run/patmat-behavior.check create mode 100644 test/files/run/patmat-behavior.scala create mode 100644 test/files/run/value-class-extractor-2.check create mode 100644 test/files/run/value-class-extractor-2.scala create mode 100644 test/files/run/value-class-extractor-seq.check create mode 100644 test/files/run/value-class-extractor-seq.scala create mode 100644 test/files/run/value-class-extractor.check create mode 100644 test/files/run/value-class-extractor.scala (limited to 'test/files') diff --git a/test/files/jvm/opt_value_class.check b/test/files/jvm/opt_value_class.check new file mode 100644 index 0000000000..a0c18c5ca0 --- /dev/null +++ b/test/files/jvm/opt_value_class.check @@ -0,0 +1,2 @@ +[ok] ()V public +[ok] unapply (Ljava/lang/Object;)Ljava/lang/String; public (Ljava/lang/Object;)Ljava/lang/String; diff --git a/test/files/jvm/opt_value_class/Value_1.scala b/test/files/jvm/opt_value_class/Value_1.scala new file mode 100644 index 0000000000..2440609b9e --- /dev/null +++ b/test/files/jvm/opt_value_class/Value_1.scala @@ -0,0 +1,28 @@ +final class Opt[+A >: Null](val value: A) extends AnyVal { + def get: A = value + def isEmpty = value == null +} +object Opt { + final val None = new Opt[Null](null) + def unapply[A >: Null](x: A): Opt[A] = if (x == null) None else Opt(x) + def empty[A >: Null] = None + def apply[A >: Null](value: A): Opt[A] = if (value == null) None else new Opt[A](value) +} + +class ValueExtract { + def unapply(x: Any): Opt[String] = x match { + case _: String => Opt("String") + case _: List[_] => Opt("List") + case _: Int => Opt("Int") + case _ => Opt.None + } +} + +class Direct { + def unapply(x: Any): String = x match { + case _: String => "String" + case _: List[_] => "List" + case _: Int => "Int" + case _ => null + } +} diff --git a/test/files/jvm/opt_value_class/test.scala b/test/files/jvm/opt_value_class/test.scala new file mode 100644 index 0000000000..7aea7deb99 --- /dev/null +++ b/test/files/jvm/opt_value_class/test.scala @@ -0,0 +1,16 @@ +import scala.tools.partest.BytecodeTest + +// import scala.tools.nsc.util.JavaClassPath +// import java.io.InputStream +// import scala.tools.asm +// import asm.ClassReader +// import asm.tree.{ClassNode, InsnList} +// import scala.collection.JavaConverters._ + +object Test extends BytecodeTest { + def show: Unit = { + val classNode1 = loadClassNode("ValueExtract") + val classNode2 = loadClassNode("Direct") + sameMethodAndFieldDescriptors(classNode1, classNode2) + } +} diff --git a/test/files/neg/t7214neg.check b/test/files/neg/t7214neg.check new file mode 100644 index 0000000000..0660cccd02 --- /dev/null +++ b/test/files/neg/t7214neg.check @@ -0,0 +1,7 @@ +t7214neg.scala:28: error: wrong number of patterns for object Extractor offering Any: expected 1, found 0 + case Extractor() => + ^ +t7214neg.scala:28: error: wrong number of patterns for object Extractor offering Any: expected 1, found 0 + case Extractor() => + ^ +two errors found diff --git a/test/files/neg/t7214neg.scala b/test/files/neg/t7214neg.scala new file mode 100644 index 0000000000..ff1ea8082d --- /dev/null +++ b/test/files/neg/t7214neg.scala @@ -0,0 +1,57 @@ +// pattern matcher crashes here trying to synthesize an uneeded outer test. +// no-symbol does not have an owner +// at scala.reflect.internal.SymbolTable.abort(SymbolTable.scala:49) +// at scala.tools.nsc.Global.abort(Global.scala:253) +// at scala.reflect.internal.Symbols$NoSymbol.owner(Symbols.scala:3248) +// at scala.reflect.internal.Symbols$Symbol.effectiveOwner(Symbols.scala:678) +// at scala.reflect.internal.Symbols$Symbol.isDefinedInPackage(Symbols.scala:664) +// at scala.reflect.internal.TreeGen.mkAttributedSelect(TreeGen.scala:188) +// at scala.reflect.internal.TreeGen.mkAttributedRef(TreeGen.scala:124) +// at scala.tools.nsc.ast.TreeDSL$CODE$.REF(TreeDSL.scala:308) +// at scala.tools.nsc.typechecker.PatternMatching$TreeMakers$TypeTestTreeMaker$treeCondStrategy$.outerTest(PatternMatching.scala:1209) +class Crash { + type Alias = C#T + + val c = new C + val t = new c.T + + // Crash via a Typed Pattern... + (t: Any) match { + case e: Alias => + } + + // ... or via a Typed Extractor Pattern. + object Extractor { + def unapply(a: Alias): Option[Any] = None + } + (t: Any) match { + case Extractor() => + case _ => + } + + // checking that correct outer tests are applied when + // aliases for path dependent types are involved. + val c2 = new C + type CdotT = c.T + type C2dotT = c2.T + + val outerField = t.getClass.getDeclaredFields.find(_.getName contains ("outer")).get + outerField.setAccessible(true) + + (t: Any) match { + case _: C2dotT => + println(s"!!! wrong match. t.outer=${outerField.get(t)} / c2 = $c2") // this matches on 2.10.0 + case _: CdotT => + case _ => + println(s"!!! wrong match. t.outer=${outerField.get(t)} / c = $c") + } +} + +class C { + class T +} + +object Test extends App { + new Crash +} + diff --git a/test/files/neg/t7721.check b/test/files/neg/t7721.check new file mode 100644 index 0000000000..e056b9a293 --- /dev/null +++ b/test/files/neg/t7721.check @@ -0,0 +1,21 @@ +t7721.scala:11: warning: abstract type pattern A.this.Foo is unchecked since it is eliminated by erasure + case x: Foo with Concrete => x.bippy + x.conco + ^ +t7721.scala:15: warning: abstract type pattern A.this.Foo is unchecked since it is eliminated by erasure + case x: Concrete with Foo => x.bippy + x.conco + ^ +t7721.scala:19: warning: abstract type pattern A.this.Foo is unchecked since it is eliminated by erasure + case x: Foo with Bar => x.bippy + x.barry + ^ +t7721.scala:39: warning: abstract type pattern B.this.Foo is unchecked since it is eliminated by erasure + case x: Foo with Concrete => x.bippy + x.dingo + x.conco + ^ +t7721.scala:43: warning: abstract type pattern B.this.Foo is unchecked since it is eliminated by erasure + case x: Concrete with Foo => x.bippy + x.dingo + x.conco + ^ +t7721.scala:47: warning: abstract type pattern B.this.Foo is unchecked since it is eliminated by erasure + case x: Foo with Bar with Concrete => x.bippy + x.barry + x.dingo + x.conco + x.bongo + ^ +error: No warnings can be incurred under -Xfatal-warnings. +6 warnings found +one error found diff --git a/test/files/neg/t7721.flags b/test/files/neg/t7721.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/t7721.flags @@ -0,0 +1 @@ +-Xfatal-warnings \ No newline at end of file diff --git a/test/files/neg/t7721.scala b/test/files/neg/t7721.scala new file mode 100644 index 0000000000..27884c9e35 --- /dev/null +++ b/test/files/neg/t7721.scala @@ -0,0 +1,140 @@ +import scala.language.reflectiveCalls + +trait A { + trait Concrete { def conco: Int = 1 } + type Foo <: { def bippy: Int } + type Bar <: { def barry: Int } + + implicit def barTag: scala.reflect.ClassTag[Bar] + + def f1(x: Any) = x match { + case x: Foo with Concrete => x.bippy + x.conco + case _ => -1 + } + def f2(x: Any) = x match { + case x: Concrete with Foo => x.bippy + x.conco + case _ => -1 + } + def f3(x: Any) = x match { + case x: Foo with Bar => x.bippy + x.barry + case _ => -1 + } + def f4(x: Any) = x match { + case x: (Foo @unchecked) => x.bippy // warns, suppressed + case _ => -1 + } + def f5(x: Any) = x match { + case x: (Bar @unchecked) => x.barry // warns (but about the "outer reference"), suppressed + case _ => -1 + } +} + +trait B extends A { + type Foo <: { def bippy: Int ; def dingo: Int } + type Bar <: { def barry: Int ; def bongo: Int } + + override implicit def barTag: scala.reflect.ClassTag[Bar] + + override def f1(x: Any) = x match { + case x: Foo with Concrete => x.bippy + x.dingo + x.conco + case _ => -1 + } + override def f2(x: Any) = x match { + case x: Concrete with Foo => x.bippy + x.dingo + x.conco + case _ => -1 + } + override def f3(x: Any) = x match { + case x: Foo with Bar with Concrete => x.bippy + x.barry + x.dingo + x.conco + x.bongo + case _ => -1 + } + override def f4(x: Any) = x match { + case x: (Foo @unchecked) => x.bippy + x.dingo // warns, suppressed + case _ => -1 + } + override def f5(x: Any) = x match { + case x: (Bar @unchecked) => x.barry + x.bongo // warns (but about the "outer reference"), suppressed + case _ => -1 + } +} + +object Test { + abstract class Base extends A { + trait Foo { + def bippy = 2 + def dingo = 3 + } + trait Bar { + def barry = 2 + def bongo = 3 + } + implicit def barTag: scala.reflect.ClassTag[Bar] = scala.reflect.ClassTag(classOf[Bar]) + + def run() { + println("f1") + wrap(f1(new Concrete {})) + wrap(f1(new Foo {})) + wrap(f1(new Bar {})) + wrap(f1(new Foo with Concrete {})) + wrap(f1(new Concrete with Foo {})) + + println("\nf2") + wrap(f2(new Concrete {})) + wrap(f2(new Foo {})) + wrap(f2(new Bar {})) + wrap(f2(new Foo with Concrete {})) + wrap(f2(new Concrete with Foo {})) + wrap(f2(new Bar with Concrete {})) + wrap(f2(new Concrete with Bar {})) + wrap(f2(new Concrete with Foo with Bar {})) + wrap(f2(new Foo with Bar with Concrete {})) + + println("\nf3") + wrap(f3(new Concrete {})) + wrap(f3(new Foo {})) + wrap(f3(new Bar {})) + wrap(f3(new Foo with Concrete {})) + wrap(f3(new Concrete with Foo {})) + wrap(f3(new Bar with Concrete {})) + wrap(f3(new Concrete with Bar {})) + wrap(f3(new Concrete with Foo with Bar {})) + wrap(f3(new Foo with Bar with Concrete {})) + + println("\nf4") + wrap(f4(new Concrete {})) + wrap(f4(new Foo {})) + wrap(f4(new Bar {})) + wrap(f4(new Foo with Concrete {})) + wrap(f4(new Concrete with Foo {})) + wrap(f4(new Bar with Concrete {})) + wrap(f4(new Concrete with Bar {})) + wrap(f4(new Concrete with Foo with Bar {})) + wrap(f4(new Foo with Bar with Concrete {})) + + println("\nf5") + wrap(f5(new Concrete {})) + wrap(f5(new Foo {})) + wrap(f5(new Bar {})) + wrap(f5(new Foo with Concrete {})) + wrap(f5(new Concrete with Foo {})) + wrap(f5(new Bar with Concrete {})) + wrap(f5(new Concrete with Bar {})) + wrap(f5(new Concrete with Foo with Bar {})) + wrap(f5(new Foo with Bar with Concrete {})) + } + } + + object ao extends Base + object bo extends Base with B + + private def wrap(body: => Any) { + try println(body) + catch { case ex: NoSuchMethodException => println(ex) } + } + + def main(args: Array[String]) { + ao.run() + bo.run() + } +} + +// java.lang.NoSuchMethodException: Test$$anon$1.bippy() \ No newline at end of file diff --git a/test/files/pos/extractor-types.scala b/test/files/pos/extractor-types.scala new file mode 100644 index 0000000000..bb9659a13c --- /dev/null +++ b/test/files/pos/extractor-types.scala @@ -0,0 +1,30 @@ +package p1 { + object Ex { def unapply(p: Any): Option[_ <: Int] = null } + object Foo { val Ex(_) = null } +} +// a.scala:2: error: error during expansion of this match (this is a scalac bug). +// The underlying error was: type mismatch; +// found : Some[_$1(in value x$1)] where type _$1(in value x$1) +// required: Some[_$1(in method unapply)] +// object Foo { val Ex(_) = null } +// ^ +// one error found + +package p2 { + trait Other { + class Quux + object Baz { def unapply(x: Any): Option[Quux] = None } + } + trait Reifiers { + def f() { + val u2: Other = null + (null: Any) match { case u2.Baz(x) => println(x) } //: u2.Quux) } + // The underlying error was: type mismatch; + // found : Other#Quux + // required: u2.Quux + // x match { case u2.Baz(x) => println(x: u2.Quux) } + // ^ + // one error found + } + } +} diff --git a/test/files/pos/optmatch.scala b/test/files/pos/optmatch.scala new file mode 100644 index 0000000000..354be65da7 --- /dev/null +++ b/test/files/pos/optmatch.scala @@ -0,0 +1,33 @@ +// final case class NonZeroLong(value: Long) extends AnyVal { +// def get: Long = value +// def isEmpty: Boolean = get == 0l +// } + +class NonZeroLong(val value: Long) extends AnyVal { + def get: Long = value + def isEmpty: Boolean = get == 0l +} +object NonZeroLong { + def unapply(value: Long): NonZeroLong = new NonZeroLong(value) +} + + +object Foo { + def unapply(x: Int): NonZeroLong = new NonZeroLong(1L << x) + // public long unapply(int); + // 0: lconst_1 + // 1: iload_1 + // 2: lshl + // 3: lreturn +} + +object Test { + def f(x: Int): Int = x match { + case Foo(1024l) => 1 + case _ => 2 + } + def main(args: Array[String]): Unit = { + println(f(10)) + println(f(11)) + } +} diff --git a/test/files/pos/overloaded-unapply.scala b/test/files/pos/overloaded-unapply.scala new file mode 100644 index 0000000000..4105a25f10 --- /dev/null +++ b/test/files/pos/overloaded-unapply.scala @@ -0,0 +1,8 @@ +trait Baz { + type Type >: Null + + case class HoleType(a: String, b: String, c: String) + object HoleType { def unapply(tpe: Type): Option[HoleType] = ??? } + + (null: Type) match { case HoleType(holeTpe) => holeTpe } +} diff --git a/test/files/run/name-based-patmat.check b/test/files/run/name-based-patmat.check new file mode 100644 index 0000000000..1cc605ea3d --- /dev/null +++ b/test/files/run/name-based-patmat.check @@ -0,0 +1,10 @@ +catdog +2 catdogs! A ha ha! +3 catdogs! A ha ha! +catdog +2 catdogs! A ha ha! +3 catdogs! A ha ha! +1 +1 +2 +3 diff --git a/test/files/run/name-based-patmat.scala b/test/files/run/name-based-patmat.scala new file mode 100644 index 0000000000..2c429c141f --- /dev/null +++ b/test/files/run/name-based-patmat.scala @@ -0,0 +1,75 @@ +final class MiniSome[T](val get: T) extends AnyVal { def isEmpty = false } + +package p1 { + class Triple(val x: Any) extends AnyRef with Product3[String, String, String] { + private def s = "" + x + override def canEqual(x: Any) = this eq x.asInstanceOf[AnyRef] + def isEmpty = false + def get = this + def _1 = s + def _2 = "2 " + s + "s! A ha ha!" + def _3 = "3 " + s + "s! A ha ha!" + + override def toString = s"Triple(${_1}, ${_2}, ${_3})" + } + + object Triple { + def unapply(x: Any): Triple = new Triple(x) + } +} + +package p2 { + class Triple(val x: Any) { + private def s = "" + x + def isEmpty = false + def get = this + def _1 = s + def _2 = "2 " + s + "s! A ha ha!" + def _3 = "3 " + s + "s! A ha ha!" + override def toString = s"Triple(${_1}, ${_2}, ${_3})" + } + + object Triple { + def unapply(x: Any): Triple = new Triple(x) + } +} + +package p3 { + case class Foo(x: Int, y: Int, zs: Int*) + + object Bar { + def f(x: Foo) = x match { + case Foo(5, 10, 15, 20, _*) => 1 + case Foo(5, 10, 15, _*) => 2 + case Foo(5, 10, _*) => 3 + case Foo(5, 10) => 4 // should warn unreachable + case _ => 5 + } + } +} + +object Test { + + // def f(x: Any) = x match { + // case p1.Foo(x, y, z) => println((x, y, z)) + // case x => println(x) + // } + + def main(args: Array[String]): Unit = { + "catdog" match { + case p1.Triple(x, y, z) => List(x, y, z) foreach println + case x => println("fail: " + x) + } + // TODO + "catdog" match { + case p2.Triple(x, y, z) => List(x, y, z) foreach println + case x => println("fail: " + x) + } + + println(p3.Bar.f(p3.Foo(5, 10, 15, 20, 25))) + println(p3.Bar.f(p3.Foo(5, 10, 15, 20))) + println(p3.Bar.f(p3.Foo(5, 10, 15))) + println(p3.Bar.f(p3.Foo(5, 10))) + // println(p3.Bar.f(p3.Foo(5))) + } +} diff --git a/test/files/run/patmat-behavior-2.check b/test/files/run/patmat-behavior-2.check new file mode 100644 index 0000000000..a928fe7918 --- /dev/null +++ b/test/files/run/patmat-behavior-2.check @@ -0,0 +1,24 @@ +f1(Foo(1)) == true +f1(Foo(1, 2)) == false +f1(Foo(1, 2, 3)) == false + +f2(Foo(1)) == false +f2(Foo(1, 2)) == true +f2(Foo(1, 2, 3)) == false + +f3(Foo(1)) == false +f3(Foo(1, 2)) == false +f3(Foo(1, 2, 3)) == true + +f1seq(Foo(1)) == true +f1seq(Foo(1, 2)) == true +f1seq(Foo(1, 2, 3)) == true + +f2seq(Foo(1)) == false +f2seq(Foo(1, 2)) == true +f2seq(Foo(1, 2, 3)) == true + +f3seq(Foo(1)) == false +f3seq(Foo(1, 2)) == false +f3seq(Foo(1, 2, 3)) == true + diff --git a/test/files/run/patmat-behavior-2.scala b/test/files/run/patmat-behavior-2.scala new file mode 100644 index 0000000000..b31f773772 --- /dev/null +++ b/test/files/run/patmat-behavior-2.scala @@ -0,0 +1,50 @@ +case class Foo(x: Int, ys: Int*) { + // We write our own toString because of SI-7735 + override def toString = (x +: ys).mkString("Foo(", ", ", ")") +} + +object Test { + def f1(x: Any) = x match { + case Foo(x) => true + case _ => false + } + def f2(x: Any) = x match { + case Foo(x, y) => true + case _ => false + } + def f3(x: Any) = x match { + case Foo(x, y, z) => true + case _ => false + } + def f1seq(x: Any) = x match { + case Foo(x, ys @ _*) => true + case _ => false + } + def f2seq(x: Any) = x match { + case Foo(x, y, zs @ _*) => true + case _ => false + } + def f3seq(x: Any) = x match { + case Foo(x, y, z, qs @ _*) => true + case _ => false + } + + val x1 = Foo(1) + val x2 = Foo(1, 2) + val x3 = Foo(1, 2, 3) + + val fs = List[Any => Boolean](f1, f2, f3) + val fseqs = List[Any => Boolean](f1seq, f2seq, f3seq) + val xs = List[Foo](x1, x2, x3) + + def main(args: Array[String]): Unit = { + for ((f, i) <- fs.zipWithIndex) { + xs foreach (x => println(s"f${i+1}($x) == ${f(x)}")) + println("") + } + for ((f, i) <- fseqs.zipWithIndex) { + xs foreach (x => println(s"f${i+1}seq($x) == ${f(x)}")) + println("") + } + } +} diff --git a/test/files/run/patmat-behavior.check b/test/files/run/patmat-behavior.check new file mode 100644 index 0000000000..273a1434fb --- /dev/null +++ b/test/files/run/patmat-behavior.check @@ -0,0 +1,90 @@ +patmat-behavior.scala:82: warning: fruitless type test: a value of type s.C00[A] cannot also be a s.C10[A] + def gd1[A](x: C00[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:82: warning: fruitless type test: a value of type s.C00[A] cannot also be a s.C20[A] + def gd1[A](x: C00[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:82: warning: fruitless type test: a value of type s.C00[A] cannot also be a s.C01[A] + def gd1[A](x: C00[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:82: warning: fruitless type test: a value of type s.C00[A] cannot also be a s.C11[A] + def gd1[A](x: C00[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:82: warning: fruitless type test: a value of type s.C00[A] cannot also be a s.C21[A] + def gd1[A](x: C00[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:83: warning: fruitless type test: a value of type s.C10[A] cannot also be a s.C00[A] + def gd2[A](x: C10[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:83: warning: fruitless type test: a value of type s.C10[A] cannot also be a s.C20[A] + def gd2[A](x: C10[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:83: warning: fruitless type test: a value of type s.C10[A] cannot also be a s.C01[A] + def gd2[A](x: C10[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:83: warning: fruitless type test: a value of type s.C10[A] cannot also be a s.C11[A] + def gd2[A](x: C10[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:83: warning: fruitless type test: a value of type s.C10[A] cannot also be a s.C21[A] + def gd2[A](x: C10[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:84: warning: fruitless type test: a value of type s.C20[A] cannot also be a s.C00[A] + def gd3[A](x: C20[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:84: warning: fruitless type test: a value of type s.C20[A] cannot also be a s.C10[A] + def gd3[A](x: C20[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:84: warning: fruitless type test: a value of type s.C20[A] cannot also be a s.C01[A] + def gd3[A](x: C20[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:84: warning: fruitless type test: a value of type s.C20[A] cannot also be a s.C11[A] + def gd3[A](x: C20[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:84: warning: fruitless type test: a value of type s.C20[A] cannot also be a s.C21[A] + def gd3[A](x: C20[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:85: warning: fruitless type test: a value of type s.C01[A] cannot also be a s.C00[A] + def gd4[A](x: C01[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:85: warning: fruitless type test: a value of type s.C01[A] cannot also be a s.C10[A] + def gd4[A](x: C01[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:85: warning: fruitless type test: a value of type s.C01[A] cannot also be a s.C20[A] + def gd4[A](x: C01[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:85: warning: fruitless type test: a value of type s.C01[A] cannot also be a s.C11[A] + def gd4[A](x: C01[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:85: warning: fruitless type test: a value of type s.C01[A] cannot also be a s.C21[A] + def gd4[A](x: C01[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:86: warning: fruitless type test: a value of type s.C11[A] cannot also be a s.C00[A] + def gd5[A](x: C11[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:86: warning: fruitless type test: a value of type s.C11[A] cannot also be a s.C10[A] + def gd5[A](x: C11[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:86: warning: fruitless type test: a value of type s.C11[A] cannot also be a s.C20[A] + def gd5[A](x: C11[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:86: warning: fruitless type test: a value of type s.C11[A] cannot also be a s.C01[A] + def gd5[A](x: C11[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:86: warning: fruitless type test: a value of type s.C11[A] cannot also be a s.C21[A] + def gd5[A](x: C11[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:87: warning: fruitless type test: a value of type s.C21[A] cannot also be a s.C00[A] + def gd6[A](x: C21[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:87: warning: fruitless type test: a value of type s.C21[A] cannot also be a s.C10[A] + def gd6[A](x: C21[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:87: warning: fruitless type test: a value of type s.C21[A] cannot also be a s.C20[A] + def gd6[A](x: C21[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:87: warning: fruitless type test: a value of type s.C21[A] cannot also be a s.C01[A] + def gd6[A](x: C21[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ +patmat-behavior.scala:87: warning: fruitless type test: a value of type s.C21[A] cannot also be a s.C11[A] + def gd6[A](x: C21[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + ^ diff --git a/test/files/run/patmat-behavior.scala b/test/files/run/patmat-behavior.scala new file mode 100644 index 0000000000..8b6370d796 --- /dev/null +++ b/test/files/run/patmat-behavior.scala @@ -0,0 +1,95 @@ +package s { + sealed trait C[+A] + + case class C00[+A]() extends C[A] + case class C10[+A](x: A) extends C[A] + case class C20[+A](x: A, y: A) extends C[A] + case class C01[+A](xs: A*) extends C[A] + case class C11[+A](x: A, ys: A*) extends C[A] + case class C21[+A](x: A, y: A, zs: A*) extends C[A] + + object E00 { def unapply[A](x: Any): Boolean = ??? } + object E10 { def unapply[A](x: Any): Option[A] = ??? } + object E20 { def unapply[A](x: Any): Option[(A, A)] = ??? } + object E01 { def unapplySeq[A](x: Any): Option[Seq[A]] = ??? } + object E11 { def unapplySeq[A](x: Any): Option[(A, Seq[A])] = ??? } + object E21 { def unapplySeq[A](x: Any): Option[(A, A, Seq[A])] = ??? } + + object F00 { def unapply[A](x: C[A]): Boolean = ??? } + object F10 { def unapply[A](x: C[A]): Option[A] = ??? } + object F20 { def unapply[A](x: C[A]): Option[(A, A)] = ??? } + object F01 { def unapplySeq[A](x: C[A]): Option[Seq[A]] = ??? } + object F11 { def unapplySeq[A](x: C[A]): Option[(A, Seq[A])] = ??? } + object F21 { def unapplySeq[A](x: C[A]): Option[(A, A, Seq[A])] = ??? } + + object G00 { def unapply[A](x: C00[A]): Boolean = ??? } + object G10 { def unapply[A](x: C10[A]): Option[A] = ??? } + object G20 { def unapply[A](x: C20[A]): Option[(A, A)] = ??? } + object G01 { def unapplySeq[A](x: C01[A]): Option[Seq[A]] = ??? } + object G11 { def unapplySeq[A](x: C11[A]): Option[(A, Seq[A])] = ??? } + object G21 { def unapplySeq[A](x: C21[A]): Option[(A, A, Seq[A])] = ??? } +} +import s._ + +package pos { + object Test { + def ga1(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 } + def ga2(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 } + def ga3(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 } + def ga4(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 } + def ga5(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 } + def ga6(x: Any) = x match { case C00() => 1 ; case C10(x) => 2 ; case C20(x, y) => 3 ; case C01(xs) => 4 ; case C11(x, ys) => 5 ; case C21(x, y, zs) => 6 } + + def gb1[A](x: C[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + def gb2[A](x: C[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + def gb3[A](x: C[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + def gb4[A](x: C[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + def gb5[A](x: C[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + def gb6[A](x: C[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + + def gc1[A](x: C[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gc2[A](x: C[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gc3[A](x: C[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gc4[A](x: C[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gc5[A](x: C[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gc6[A](x: C[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + + def gd1[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gd2[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gd3[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gd4[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gd5[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gd6[A, B <: C[A]](x: B) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + } +} + +package neg { + object Fail { + def gb1[A](x: C00[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + def gb2[A](x: C10[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + def gb3[A](x: C20[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + def gb4[A](x: C01[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + def gb5[A](x: C11[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + def gb6[A](x: C21[A]) = x match { case E00() => ??? ; case E10(x) => x ; case E20(x, y) => x ; case E01(xs @ _*) => xs.head ; case E11(x, ys @ _*) => x ; case E21(x, y, zs @ _*) => x } + + def gc1[A](x: C00[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gc2[A](x: C10[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gc3[A](x: C20[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gc4[A](x: C01[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gc5[A](x: C11[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + def gc6[A](x: C21[A]) = x match { case F00() => ??? ; case F10(x) => x ; case F20(x, y) => x ; case F01(xs @ _*) => xs.head ; case F11(x, ys @ _*) => x ; case F21(x, y, zs @ _*) => x } + + def gd1[A](x: C00[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + def gd2[A](x: C10[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + def gd3[A](x: C20[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + def gd4[A](x: C01[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + def gd5[A](x: C11[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + def gd6[A](x: C21[A]) = x match { case G00() => ??? ; case G10(x) => x ; case G20(x, y) => x ; case G01(xs @ _*) => xs.head ; case G11(x, ys @ _*) => x ; case G21(x, y, zs @ _*) => x } + } +} + +object Test { + def main(args: Array[String]): Unit = { + + } +} diff --git a/test/files/run/value-class-extractor-2.check b/test/files/run/value-class-extractor-2.check new file mode 100644 index 0000000000..5903b996b6 --- /dev/null +++ b/test/files/run/value-class-extractor-2.check @@ -0,0 +1,8 @@ +String +List +Int +Something else +String +List +Int +Something else diff --git a/test/files/run/value-class-extractor-2.scala b/test/files/run/value-class-extractor-2.scala new file mode 100644 index 0000000000..d776c35eda --- /dev/null +++ b/test/files/run/value-class-extractor-2.scala @@ -0,0 +1,108 @@ +final class Opt[+A >: Null](val value: A) extends AnyVal { + def get: A = value + def isEmpty = value == null +} +object Opt { + final val None = new Opt[Null](null) + def apply[A >: Null](value: A): Opt[A] = if (value == null) None else new Opt[A](value) +} + +object ValueOpt { + // public java.lang.String unapply(java.lang.Object); + // 0: aload_1 + // 1: instanceof #16 // class java/lang/String + // 4: ifeq 21 + // 7: getstatic #21 // Field Opt$.MODULE$:LOpt$; + // 10: astore_2 + // 11: ldc #23 // String String + // 13: checkcast #16 // class java/lang/String + // 16: astore 5 + // 18: goto 71 + // 21: aload_1 + // 22: instanceof #25 // class scala/collection/immutable/List + // 25: ifeq 42 + // 28: getstatic #21 // Field Opt$.MODULE$:LOpt$; + // 31: astore_3 + // 32: ldc #27 // String List + // 34: checkcast #16 // class java/lang/String + // 37: astore 5 + // 39: goto 71 + // 42: aload_1 + // 43: instanceof #29 // class java/lang/Integer + // 46: ifeq 64 + // 49: getstatic #21 // Field Opt$.MODULE$:LOpt$; + // 52: astore 4 + // 54: ldc #31 // String Int + // 56: checkcast #16 // class java/lang/String + // 59: astore 5 + // 61: goto 71 + // 64: getstatic #21 // Field Opt$.MODULE$:LOpt$; + // 67: pop + // 68: aconst_null + // 69: astore 5 + // 71: aload 5 + // 73: areturn + def unapply(x: Any): Opt[String] = x match { + case _: String => Opt("String") + case _: List[_] => Opt("List") + case _: Int => Opt("Int") + case _ => Opt.None + } +} +object RegularOpt { + // public scala.Option unapply(java.lang.Object); + // 0: aload_1 + // 1: instanceof #16 // class java/lang/String + // 4: ifeq 20 + // 7: new #18 // class scala/Some + // 10: dup + // 11: ldc #20 // String String + // 13: invokespecial #23 // Method scala/Some."":(Ljava/lang/Object;)V + // 16: astore_2 + // 17: goto 64 + // 20: aload_1 + // 21: instanceof #25 // class scala/collection/immutable/List + // 24: ifeq 40 + // 27: new #18 // class scala/Some + // 30: dup + // 31: ldc #27 // String List + // 33: invokespecial #23 // Method scala/Some."":(Ljava/lang/Object;)V + // 36: astore_2 + // 37: goto 64 + // 40: aload_1 + // 41: instanceof #29 // class java/lang/Integer + // 44: ifeq 60 + // 47: new #18 // class scala/Some + // 50: dup + // 51: ldc #31 // String Int + // 53: invokespecial #23 // Method scala/Some."":(Ljava/lang/Object;)V + // 56: astore_2 + // 57: goto 64 + // 60: getstatic #36 // Field scala/None$.MODULE$:Lscala/None$; + // 63: astore_2 + // 64: aload_2 + // 65: areturn + def unapply(x: Any): Option[String] = x match { + case _: String => Some("String") + case _: List[_] => Some("List") + case _: Int => Some("Int") + case _ => None + } +} + +object Test { + def f(x: Any) = x match { + case ValueOpt(s) => s + case _ => "Something else" + } + def g(x: Any) = x match { + case RegularOpt(s) => s + case _ => "Something else" + } + val xs = List("abc", Nil, 5, Test) + + def main(args: Array[String]): Unit = { + xs map f foreach println + xs map g foreach println + } +} diff --git a/test/files/run/value-class-extractor-seq.check b/test/files/run/value-class-extractor-seq.check new file mode 100644 index 0000000000..84552a7aa5 --- /dev/null +++ b/test/files/run/value-class-extractor-seq.check @@ -0,0 +1,3 @@ +Bip(1, 2, 3) +Bip(1, 2, c @ Array(3, 4, 5): _*) +class [I diff --git a/test/files/run/value-class-extractor-seq.scala b/test/files/run/value-class-extractor-seq.scala new file mode 100644 index 0000000000..f17a5314f2 --- /dev/null +++ b/test/files/run/value-class-extractor-seq.scala @@ -0,0 +1,59 @@ +import scala.runtime.ScalaRunTime.stringOf + +final class ArrayOpt[T](val xs: Array[T]) extends AnyVal { + def isEmpty = xs == null + def get = xs +} + +object Bip { + def mkInts(xs: Array[Short]) = xs map (_.toInt) + def unapplySeq(x: Any): ArrayOpt[Int] = x match { + case xs: Array[Int] => new ArrayOpt(xs) + case xs: Array[Short] => new ArrayOpt(mkInts(xs)) + case _ => new ArrayOpt(null) + } + // public int[] unapplySeq(java.lang.Object); + // 0: aload_1 + // 1: astore_2 + // 2: aload_2 + // 3: instanceof #52 // class "[I" + // 6: ifeq 20 + // 9: aload_2 + // 10: checkcast #52 // class "[I" + // 13: astore_3 + // 14: aload_3 + // 15: astore 4 + // 17: goto 47 + // 20: aload_2 + // 21: instanceof #58 // class "[S" + // 24: ifeq 44 + // 27: aload_2 + // 28: checkcast #58 // class "[S" + // 31: astore 5 + // 33: aload_0 + // 34: aload 5 + // 36: invokevirtual #60 // Method mkInts:([S)[I + // 39: astore 4 + // 41: goto 47 + // 44: aconst_null + // 45: astore 4 + // 47: aload 4 + // 49: areturn +} + +object Test { + def f(x: Any) = x match { + case Bip(a, b, c) => s"Bip($a, $b, $c)" + case Bip(a, b, c @ _*) => s"Bip($a, $b, c @ ${stringOf(c)}: _*)" + case _ => "" + x.getClass + } + + def main(args: Array[String]): Unit = { + println(f(Array[Int](1,2,3))) + println(f(Array[Int](1,2,3,4,5))) + println(f(Array[Int](1))) + } + // Bip(1, 2, 3) + // Bip(1, 2, c @ [I@782be20e: _*) + // class [I +} diff --git a/test/files/run/value-class-extractor.check b/test/files/run/value-class-extractor.check new file mode 100644 index 0000000000..e16447118c --- /dev/null +++ b/test/files/run/value-class-extractor.check @@ -0,0 +1,9 @@ +'a' +'b' +'c' +NoChar +Some(a) +Some(b) +Some(c) +None +9 diff --git a/test/files/run/value-class-extractor.scala b/test/files/run/value-class-extractor.scala new file mode 100644 index 0000000000..3eaffa0c23 --- /dev/null +++ b/test/files/run/value-class-extractor.scala @@ -0,0 +1,91 @@ +final class NonNullChar(val get: Char) extends AnyVal { + def isEmpty = get == 0.toChar + override def toString = if (isEmpty) "NoChar" else s"'$get'" +} +object NonNullChar { + @inline final val None = new NonNullChar(0.toChar) +} + +final class SomeProduct extends Product3[String, Int, List[String]] { + def canEqual(x: Any) = x.isInstanceOf[SomeProduct] + def _1 = "abc" + def _2 = 5 + def _3 = List("bippy") + def isEmpty = false + def get = this +} +object SomeProduct { + def unapply(x: SomeProduct) = x +} + +object Test { + def prod(x: SomeProduct): Int = x match { + case SomeProduct(x, y, z) => x.length + y + z.length + case _ => -1 + } + + def f(x: Char): NonNullChar = x match { + case 'a' => new NonNullChar('a') + case 'b' => new NonNullChar('b') + case 'c' => new NonNullChar('c') + case _ => NonNullChar.None + } + // public char f(char); + // 0: iload_1 + // 1: tableswitch { // 97 to 99 + // 97: 47 + // 98: 42 + // 99: 37 + // default: 28 + // } + // 28: getstatic #19 // Field NonNullChar$.MODULE$:LNonNullChar$; + // 31: invokevirtual #23 // Method NonNullChar$.None:()C + // 34: goto 49 + // 37: bipush 99 + // 39: goto 49 + // 42: bipush 98 + // 44: goto 49 + // 47: bipush 97 + // 49: ireturn + def g(x: Char): Option[Char] = x match { + case 'a' => Some('a') + case 'b' => Some('b') + case 'c' => Some('c') + case _ => None + } + // public scala.Option g(char); + // 0: iload_1 + // 1: tableswitch { // 97 to 99 + // 97: 64 + // 98: 49 + // 99: 34 + // default: 28 + // } + // 28: getstatic #33 // Field scala/None$.MODULE$:Lscala/None$; + // 31: goto 76 + // 34: new #35 // class scala/Some + // 37: dup + // 38: bipush 99 + // 40: invokestatic #41 // Method scala/runtime/BoxesRunTime.boxToCharacter:(C)Ljava/lang/Character; + // 43: invokespecial #44 // Method scala/Some."":(Ljava/lang/Object;)V + // 46: goto 76 + // 49: new #35 // class scala/Some + // 52: dup + // 53: bipush 98 + // 55: invokestatic #41 // Method scala/runtime/BoxesRunTime.boxToCharacter:(C)Ljava/lang/Character; + // 58: invokespecial #44 // Method scala/Some."":(Ljava/lang/Object;)V + // 61: goto 76 + // 64: new #35 // class scala/Some + // 67: dup + // 68: bipush 97 + // 70: invokestatic #41 // Method scala/runtime/BoxesRunTime.boxToCharacter:(C)Ljava/lang/Character; + // 73: invokespecial #44 // Method scala/Some."":(Ljava/lang/Object;)V + // 76: areturn + def main(args: Array[String]): Unit = { + "abcd" foreach (ch => println(f(ch))) + "abcd" foreach (ch => println(g(ch))) + println(prod(new SomeProduct)) + } +} + + -- cgit v1.2.3