summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala65
-rw-r--r--test/files/neg/patmat-type-check.check14
-rw-r--r--test/files/neg/patmat-type-check.scala7
-rw-r--r--test/files/neg/t3692.check12
-rw-r--r--test/files/neg/t3692.scala2
-rw-r--r--test/files/run/bug2755.check21
-rw-r--r--test/files/run/bug2755.scala58
7 files changed, 137 insertions, 42 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 62f78eddfe..dd6d7b23a6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -1342,8 +1342,8 @@ trait Infer {
check(tp, List())
}
- /** Type intersection of simple type <code>tp1</code> with general
- * type <code>tp2</code>. The result eliminates some redundancies.
+ /** Type intersection of simple type tp1 with general type tp2.
+ * The result eliminates some redundancies.
*/
def intersect(tp1: Type, tp2: Type): Type = {
if (tp1 <:< tp2) tp1
@@ -1351,7 +1351,7 @@ trait Infer {
else {
val reduced2 = tp2 match {
case rtp @ RefinedType(parents2, decls2) =>
- copyRefinedType(rtp, parents2 filter (p2 => !(tp1 <:< p2)), decls2)
+ copyRefinedType(rtp, parents2 filterNot (tp1 <:< _), decls2)
case _ =>
tp2
}
@@ -1360,36 +1360,57 @@ trait Infer {
}
def inferTypedPattern(pos: Position, pattp: Type, pt0: Type): Type = {
- val pt = widen(pt0)
+ val pt = widen(pt0)
+ val ptparams = freeTypeParamsOfTerms.collect(pt)
+ val tpparams = freeTypeParamsOfTerms.collect(pattp)
+
+ def ptMatchesPattp = pt matchesPattern pattp
+ def pattpMatchesPt = pattp matchesPattern pt
- /** If we can absolutely rule out a match we can fail fast. */
- if (pt.isFinalType && !(pt matchesPattern pattp))
- error(pos, "scrutinee is incompatible with pattern type"+foundReqMsg(pattp, pt))
+ /** If we can absolutely rule out a match we can fail early.
+ * This is the case if the scrutinee has no unresolved type arguments
+ * and is a "final type", meaning final + invariant in all type parameters.
+ */
+ if (pt.isFinalType && ptparams.isEmpty && !ptMatchesPattp)
+ error(pos, "scrutinee is incompatible with pattern type" + foundReqMsg(pattp, pt))
checkCheckable(pos, pattp, "pattern ")
- if (!(pattp <:< pt)) {
- val tpparams = freeTypeParamsOfTerms.collect(pattp)
- if (settings.debug.value) log("free type params (1) = " + tpparams)
+ if (pattp <:< pt) ()
+ else {
+ if (settings.debug.value)
+ log("free type params (1) = " + tpparams)
+
var tvars = tpparams map freshVar
- var tp = pattp.instantiateTypeParams(tpparams, tvars)
- if (!((tp <:< pt) && isInstantiatable(tvars))) {
+ var tp = pattp.instantiateTypeParams(tpparams, tvars)
+
+ if ((tp <:< pt) && isInstantiatable(tvars)) ()
+ else {
tvars = tpparams map freshVar
- tp = pattp.instantiateTypeParams(tpparams, tvars)
- val ptparams = freeTypeParamsOfTerms.collect(pt)
- if (settings.debug.value) log("free type params (2) = " + ptparams)
+ tp = pattp.instantiateTypeParams(tpparams, tvars)
+
+ if (settings.debug.value)
+ log("free type params (2) = " + ptparams)
+
val ptvars = ptparams map freshVar
- val pt1 = pt.instantiateTypeParams(ptparams, ptvars)
- // See ticket #2486 we have this example of code which would incorrectly
- // fail without verifying that !(pattp matchesPattern pt)
- if (!(isPopulated(tp, pt1) && isInstantiatable(tvars ::: ptvars)) && !(pattp matchesPattern pt)) {
- error(pos, "pattern type is incompatible with expected type"+foundReqMsg(pattp, pt))
+ val pt1 = pt.instantiateTypeParams(ptparams, ptvars)
+
+ // See ticket #2486 for an example of code which would incorrectly
+ // fail if we didn't allow for pattpMatchesPt.
+ if (isPopulated(tp, pt1) && isInstantiatable(tvars ++ ptvars) || pattpMatchesPt)
+ ptvars foreach instantiateTypeVar
+ else {
+ error(pos, "pattern type is incompatible with expected type" + foundReqMsg(pattp, pt))
return pattp
}
- ptvars foreach instantiateTypeVar
}
tvars foreach instantiateTypeVar
}
- intersect(pt, pattp)
+ /** If the scrutinee has free type parameters but the pattern does not,
+ * we have to flip the arguments so the expected type is treated as more
+ * general when calculating the intersection. See run/bug2755.scala.
+ */
+ if (tpparams.isEmpty && ptparams.nonEmpty) intersect(pattp, pt)
+ else intersect(pt, pattp)
}
def inferModulePattern(pat: Tree, pt: Type) =
diff --git a/test/files/neg/patmat-type-check.check b/test/files/neg/patmat-type-check.check
index ab638b616d..8f81cede8f 100644
--- a/test/files/neg/patmat-type-check.check
+++ b/test/files/neg/patmat-type-check.check
@@ -1,21 +1,21 @@
-patmat-type-check.scala:18: error: scrutinee is incompatible with pattern type;
+patmat-type-check.scala:22: error: scrutinee is incompatible with pattern type;
found : Seq[A]
required: java.lang.String
def f1 = "bob".reverse match { case Seq('b', 'o', 'b') => true } // fail
^
-patmat-type-check.scala:19: error: scrutinee is incompatible with pattern type;
+patmat-type-check.scala:23: error: scrutinee is incompatible with pattern type;
found : Seq[A]
required: Array[Char]
def f2 = "bob".toArray match { case Seq('b', 'o', 'b') => true } // fail
^
-patmat-type-check.scala:23: error: scrutinee is incompatible with pattern type;
+patmat-type-check.scala:27: error: scrutinee is incompatible with pattern type;
found : Seq[A]
required: Test.Bop2
def f3(x: Bop2) = x match { case Seq('b', 'o', 'b') => true } // fail
^
-patmat-type-check.scala:27: error: scrutinee is incompatible with pattern type;
+patmat-type-check.scala:30: error: scrutinee is incompatible with pattern type;
found : Seq[A]
- required: Test.Bop3[T]
- def f4[T](x: Bop3[T]) = x match { case Seq('b', 'o', 'b') => true } // fail
- ^
+ required: Test.Bop3[Char]
+ def f4[T](x: Bop3[Char]) = x match { case Seq('b', 'o', 'b') => true } // fail
+ ^
four errors found
diff --git a/test/files/neg/patmat-type-check.scala b/test/files/neg/patmat-type-check.scala
index c6c689b256..26d0409fa0 100644
--- a/test/files/neg/patmat-type-check.scala
+++ b/test/files/neg/patmat-type-check.scala
@@ -14,6 +14,10 @@ object Test
final class Bop5[T, U, -V]
def s4[T1, T2](x: Bop5[_, T1, T2]) = x match { case Seq('b', 'o', 'b') => true }
+ // free type parameter, allowed
+ final class Bop3[T]
+ def f4[T](x: Bop3[T]) = x match { case Seq('b', 'o', 'b') => true }
+
// String and Array are final/invariant, disallowed
def f1 = "bob".reverse match { case Seq('b', 'o', 'b') => true } // fail
def f2 = "bob".toArray match { case Seq('b', 'o', 'b') => true } // fail
@@ -23,6 +27,5 @@ object Test
def f3(x: Bop2) = x match { case Seq('b', 'o', 'b') => true } // fail
// final, invariant type parameter, should be disallowed
- final class Bop3[T]
- def f4[T](x: Bop3[T]) = x match { case Seq('b', 'o', 'b') => true } // fail
+ def f4[T](x: Bop3[Char]) = x match { case Seq('b', 'o', 'b') => true } // fail
}
diff --git a/test/files/neg/t3692.check b/test/files/neg/t3692.check
index ce89a6563d..96ddd2a461 100644
--- a/test/files/neg/t3692.check
+++ b/test/files/neg/t3692.check
@@ -1,14 +1,4 @@
-t3692.scala:11: warning: type Integer in package scala is deprecated: use <code>java.lang.Integer</code> instead
- case m0: Map[Int, Int] => new java.util.HashMap[Integer, Integer]
- ^
-t3692.scala:12: warning: type Integer in package scala is deprecated: use <code>java.lang.Integer</code> instead
- case m1: Map[Int, V] => new java.util.HashMap[Integer, V]
- ^
-t3692.scala:13: warning: type Integer in package scala is deprecated: use <code>java.lang.Integer</code> instead
- case m2: Map[T, Int] => new java.util.HashMap[T, Integer]
- ^
-t3692.scala:13: error: unreachable code
+t3692.scala:15: error: unreachable code
case m2: Map[T, Int] => new java.util.HashMap[T, Integer]
^
-three warnings found
one error found
diff --git a/test/files/neg/t3692.scala b/test/files/neg/t3692.scala
index 78b0e4b843..151535ae94 100644
--- a/test/files/neg/t3692.scala
+++ b/test/files/neg/t3692.scala
@@ -1,3 +1,5 @@
+import java.lang.Integer
+
object ManifestTester {
def main(args: Array[String]) = {
val map = Map("John" -> 1, "Josh" -> 2)
diff --git a/test/files/run/bug2755.check b/test/files/run/bug2755.check
new file mode 100644
index 0000000000..4905c0052d
--- /dev/null
+++ b/test/files/run/bug2755.check
@@ -0,0 +1,21 @@
+1
+2
+3
+4
+5
+6
+7
+1
+2
+3
+4
+5
+6
+7
+1
+2
+3
+4
+5
+6
+7
diff --git a/test/files/run/bug2755.scala b/test/files/run/bug2755.scala
new file mode 100644
index 0000000000..8d10b56734
--- /dev/null
+++ b/test/files/run/bug2755.scala
@@ -0,0 +1,58 @@
+// Test cases: the only place we can cut and paste without crying
+// ourself to sleep.
+object Test {
+ def f1(a: Any) = a match {
+ case x: Array[Int] => x(0)
+ case x: Array[Double] => 2
+ case x: Array[Float] => x.sum.toInt
+ case x: Array[String] => x.size
+ case x: Array[AnyRef] => 5
+ case x: Array[_] => 6
+ case _ => 7
+ }
+ def f2(a: Array[_]) = a match {
+ case x: Array[Int] => x(0)
+ case x: Array[Double] => 2
+ case x: Array[Float] => x.sum.toInt
+ case x: Array[String] => x.size
+ case x: Array[AnyRef] => 5
+ case x: Array[_] => 6
+ case _ => 7
+ }
+ def f3[T](a: Array[T]) = a match {
+ case x: Array[Int] => x(0)
+ case x: Array[Double] => 2
+ case x: Array[Float] => x.sum.toInt
+ case x: Array[String] => x.size
+ case x: Array[AnyRef] => 5
+ case x: Array[_] => 6
+ case _ => 7
+ }
+
+
+ def main(args: Array[String]): Unit = {
+ println(f1(Array(1, 2, 3)))
+ println(f1(Array(1.0, -2.0, 3.0, 1.0)))
+ println(f1(Array(1.0f, 2.0f, 3.0f, -3.0f)))
+ println(f1((1 to 4).toArray map (_.toString)))
+ println(f1(new Array[Any](10))) // should match as Array[AnyRef]
+ println(f1(Array(1L)))
+ println(f1(null))
+
+ println(f2(Array(1, 2, 3)))
+ println(f2(Array(1.0, -2.0, 3.0, 1.0)))
+ println(f2(Array(1.0f, 2.0f, 3.0f, -3.0f)))
+ println(f2((1 to 4).toArray map (_.toString)))
+ println(f2(new Array[Any](10))) // should match as Array[AnyRef]
+ println(f2(Array(1L)))
+ println(f2(null))
+
+ println(f3(Array(1, 2, 3)))
+ println(f3(Array(1.0, -2.0, 3.0, 1.0)))
+ println(f3(Array(1.0f, 2.0f, 3.0f, -3.0f)))
+ println(f3((1 to 4).toArray map (_.toString)))
+ println(f3(new Array[Any](10))) // should match as Array[AnyRef]
+ println(f3(Array(1L)))
+ println(f3(null))
+ }
+}