summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala18
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala34
-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
7 files changed, 105 insertions, 16 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala b/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala
index e84ccbf754..1916050dd8 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala
@@ -86,9 +86,25 @@ trait PatternExpander[Pattern, Type] {
* @param fixed The non-sequence types which are extracted
* @param repeated The sequence type which is extracted
*/
- final case class Extractor(whole: Type, fixed: List[Type], repeated: Repeated) {
+ final case class Extractor(whole: Type, fixed: List[Type], repeated: Repeated, typeOfSinglePattern: Type) {
require(whole != NoType, s"expandTypes($whole, $fixed, $repeated)")
+ /** A pattern with arity-1 that doesn't match the arity of the Product-like result of the `get` method,
+ * will match that result in its entirety. Example:
+ *
+ * {{{
+ * warning: there was one deprecation warning; re-run with -deprecation for details
+ * 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
+ * }}}
+ * */
+ def asSinglePattern: Extractor = copy(fixed = List(typeOfSinglePattern))
+
def productArity = fixed.length
def hasSeq = repeated.exists
def elementType = repeated.elementType
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala
index b1783dc81f..55d4366a46 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala
@@ -43,8 +43,9 @@ trait ScalacPatternExpanders {
orElse definitions.elementType(ArrayClass, seq)
)
}
- def newExtractor(whole: Type, fixed: List[Type], repeated: Repeated): Extractor =
- logResult(s"newExtractor($whole, $fixed, $repeated")(Extractor(whole, fixed, repeated))
+ def newExtractor(whole: Type, fixed: List[Type], repeated: Repeated, typeOfSinglePattern: Type): Extractor =
+ logResult(s"newExtractor($whole, $fixed, $repeated, $typeOfSinglePattern")(Extractor(whole, fixed, repeated, typeOfSinglePattern))
+ def newExtractor(whole: Type, fixed: List[Type], repeated: Repeated): Extractor = newExtractor(whole, fixed, repeated, tupleType(fixed))
// Turn Seq[A] into Repeated(Seq[A], A, A*)
def repeatedFromSeq(seqType: Type): Repeated = {
@@ -74,16 +75,17 @@ trait ScalacPatternExpanders {
* it was unapplySeq, so we have to funnel that information in separately.
*/
def unapplyMethodTypes(whole: Type, result: Type, isSeq: Boolean): Extractor = {
- val expanded = (
- if (result =:= BooleanTpe) Nil
- else typeOfMemberNamedGet(result) match {
+ if (result =:= BooleanTpe) newExtractor(whole, Nil, NoRepeated)
+ else {
+ val getResult = typeOfMemberNamedGet(result)
+ val expanded = getResult match {
case rawGet if !hasSelectors(rawGet) => rawGet :: Nil
case rawGet => typesOfSelectors(rawGet)
}
- )
- expanded match {
- case init :+ last if isSeq => newExtractor(whole, init, repeatedFromSeq(last))
- case tps => newExtractor(whole, tps, NoRepeated)
+ expanded match {
+ case init :+ last if isSeq => newExtractor(whole, init, repeatedFromSeq(last), getResult)
+ case tps => newExtractor(whole, tps, NoRepeated, getResult)
+ }
}
}
}
@@ -142,12 +144,14 @@ trait ScalacPatternExpanders {
def acceptMessage = if (extractor.isErroneous) "" else s" to hold ${extractor.offeringString}"
val requiresTupling = isUnapply && patterns.totalArity == 1 && productArity > 1
- if (requiresTupling && effectivePatternArity(args) == 1) {
- val sym = sel.symbol.owner
- currentRun.reporting.deprecationWarning(sel.pos, sym, s"${sym} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)")
- }
-
- val normalizedExtractor = if (requiresTupling) tupleExtractor(extractor) else extractor
+ val normalizedExtractor = if (requiresTupling) {
+ val tupled = extractor.asSinglePattern
+ if (effectivePatternArity(args) == 1 && isTupleType(extractor.typeOfSinglePattern)) {
+ val sym = sel.symbol.owner
+ currentRun.reporting.deprecationWarning(sel.pos, sym, s"${sym} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)")
+ }
+ tupled
+ } else extractor
validateAligned(context, fn, Aligned(patterns, normalizedExtractor))
}
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
+ }
+ }
+}