summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2015-08-29 21:42:29 +1000
committerJason Zaugg <jzaugg@gmail.com>2015-09-21 14:00:09 +1000
commitf1e553ecfbea25bcc7e13294f6104d599336f460 (patch)
tree9720ff6c481398e63700833001e82190c684c097 /test
parent0f72dd37f85bbcaa07cfb325685dc019e6bc1c26 (diff)
downloadscala-f1e553ecfbea25bcc7e13294f6104d599336f460.tar.gz
scala-f1e553ecfbea25bcc7e13294f6104d599336f460.tar.bz2
scala-f1e553ecfbea25bcc7e13294f6104d599336f460.zip
SI-9029 Fix regression in extractor patterns
The unified treatment of classical and named-based pattern matching does not correctly handle the generalization of "tuple capture". By "tuple capture", I mean: ``` scala> object Extractor { def unapply(a: Any): Option[(Int, String)] = Some((1, "2")) } defined object Extractor scala> "" match { case Extractor(x: Int, y: String) => } scala> "" match { case Extractor(xy : (Int, String)) => } warning: there was one deprecation warning; re-run with -deprecation for details scala> :warnings <console>:9: warning: object Extractor expects 2 patterns to hold (Int, String) but crushing into 2-tuple to fit single pattern (SI-6675) "" match { case Extractor(xy : (Int, String)) => } ^ ``` Name based pattern matching, new in Scala 2.11, allows one to deconstruct the elements that structurally resembles `ProductN`: ``` scala> class P2(val _1: Int, val _2: String) defined class P2 scala> object Extractor { def unapply(a: Any): Option[P2] = Some(new P2(1, "2")) } defined object Extractor scala> "" match { case Extractor(x: Int, y: String) => } ``` However, attempting to extract the `P2` in its entirety leads to an internal error: ``` scala> "" match { case Extractor(p2: P2) => } <console>:10: warning: fruitless type test: a value of type (Int, String) cannot also be a P2 "" match { case Extractor(p2: P2) => } ^ <console>:10: error: error during expansion of this match (this is a scalac bug). The underlying error was: type mismatch; found : P2 required: (Int, String) "" match { case Extractor(p2: P2) => } ^ ``` Note that this match was legal and warning free in 2.10. This commit avoids the hard-coded assumption that the "tuple capture" results in a `TupleN`, and instead keeps track of the product-ish type from which we extracted the element types. I have also opted not to limit the deprecation warning to `TupleN` extractors.
Diffstat (limited to 'test')
-rw-r--r--test/files/run/t9029.flags1
-rw-r--r--test/files/run/t9029.scala15
-rw-r--r--test/files/run/t9029b.check1
-rw-r--r--test/files/run/t9029b.scala31
-rw-r--r--test/files/run/t9029c.scala21
5 files changed, 69 insertions, 0 deletions
diff --git a/test/files/run/t9029.flags b/test/files/run/t9029.flags
new file mode 100644
index 0000000000..dcc59ebe32
--- /dev/null
+++ b/test/files/run/t9029.flags
@@ -0,0 +1 @@
+-deprecation
diff --git a/test/files/run/t9029.scala b/test/files/run/t9029.scala
new file mode 100644
index 0000000000..c01033b76e
--- /dev/null
+++ b/test/files/run/t9029.scala
@@ -0,0 +1,15 @@
+class Y(val _2: Int, val _1: String)
+
+object X { def unapply(u: Unit): Option[Y] = Some(new Y(42, "!")) }
+
+object Test {
+ def test1 = {
+ val X(y) = ()
+ val yy: Y = y
+ assert(yy._1 == "!")
+ assert(yy._2 == 42)
+ }
+ def main(args: Array[String]): Unit = {
+ test1
+ }
+}
diff --git a/test/files/run/t9029b.check b/test/files/run/t9029b.check
new file mode 100644
index 0000000000..aeb2d5e239
--- /dev/null
+++ b/test/files/run/t9029b.check
@@ -0,0 +1 @@
+Some(1)
diff --git a/test/files/run/t9029b.scala b/test/files/run/t9029b.scala
new file mode 100644
index 0000000000..764d0771ec
--- /dev/null
+++ b/test/files/run/t9029b.scala
@@ -0,0 +1,31 @@
+class Foo(val x: Bar) {
+ def isEmpty = false
+ def get = x
+}
+
+object Foo {
+ def unapply(x: Foo) = x
+}
+
+class Bar(val x: Option[Int], val y: Option[Int]) {
+ def isEmpty = false
+ def get = this
+ def _1 = x
+ def _2 = y
+}
+
+object Bar {
+ def unapply(x: Bar) = x
+}
+
+object Test {
+ def nameBased: Unit = {
+ val x: AnyRef = new Foo(new Bar(Some(1), Some(2)))
+ x match {
+ case Foo(Bar(x1, x2)) => println(x1)
+ }
+ }
+ def main(args: Array[String]): Unit = {
+ nameBased
+ }
+}
diff --git a/test/files/run/t9029c.scala b/test/files/run/t9029c.scala
new file mode 100644
index 0000000000..ccb51e23ae
--- /dev/null
+++ b/test/files/run/t9029c.scala
@@ -0,0 +1,21 @@
+object Extractor {
+ def unapply(a: Any): Option[Product2[Int, String]] = Some(new P2(1, "2"))
+}
+class P2[A, B](val _1: A, val _2: B) extends Product2[A, B] {
+ def canEqual(other: Any) = true
+ def isP2 = true
+}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ "" match {
+ case Extractor(p) =>
+ val pp: Product2[Int, String] = p
+ }
+ "" match {
+ case Extractor(x, y) =>
+ val xx: Int = x
+ val yy: String = y
+ }
+ }
+}