summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-10-04 05:28:27 +0000
committerPaul Phillips <paulp@improving.org>2010-10-04 05:28:27 +0000
commita7fd7d6dc257e396cf2cf22a9e0a60c3ce44a992 (patch)
tree24dab3548d8cef970a748d149ebd566cce808e64 /src
parentafea859ef64122f71525405625d0006150d87fb0 (diff)
downloadscala-a7fd7d6dc257e396cf2cf22a9e0a60c3ce44a992.tar.gz
scala-a7fd7d6dc257e396cf2cf22a9e0a60c3ce44a992.tar.bz2
scala-a7fd7d6dc257e396cf2cf22a9e0a60c3ce44a992.zip
Pattern matching on Array types, working for re...
Pattern matching on Array types, working for reals. def f[T](a: Array[T]) = a match { case x: Array[Int] => x(0) case x: Array[Double] => 2 // etc. } I'd also like to thank "instantiateTypeVar" for displacing the mechanical spiders and giant squid beings which used to fill my nightmares. Now that I know true horror, I welcome the squid. Closes #2755, review by odersky.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala65
1 files changed, 43 insertions, 22 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) =