diff options
author | Paul Phillips <paulp@improving.org> | 2009-10-03 17:26:36 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-10-03 17:26:36 +0000 |
commit | eb4d0290ac44df272eaf4c4ca231deea813cf940 (patch) | |
tree | 84db3e408313fc65aed71fb42a2f6343dfed850d | |
parent | aad82c0521ebf08b759b3080a56451be435c02b3 (diff) | |
download | scala-eb4d0290ac44df272eaf4c4ca231deea813cf940.tar.gz scala-eb4d0290ac44df272eaf4c4ca231deea813cf940.tar.bz2 scala-eb4d0290ac44df272eaf4c4ca231deea813cf940.zip |
Moving pattern related logic into Patterns and ...
Moving pattern related logic into Patterns and type related logic into
MixTypes.
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/ParallelMatching.scala | 73 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/Patterns.scala | 23 |
2 files changed, 46 insertions, 50 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index a904b9026d..6d7e4e56a9 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -153,8 +153,9 @@ trait ParallelMatching extends ast.TreeDSL def zip[T](others: List[T]) = trees zip others def pzip[T](others: List[T]) = ps zip others - def isObjectTest(pat: Pattern) = pat isObjectTest headType - def isObjectTest(pat: Tree) = Pattern(pat) isObjectTest headType + /** returns true if pattern tests an object */ + def isObjectTest(pat: Pattern) = + pat.isSymValid && pat.prefix.isStable && (headType =:= pat.mkSingleton) def extractSimpleSwitch(): Option[(List[Tree], Option[Tree])] = { def isSwitchableTag(tag: Int) = cond(tag) { case ByteTag | ShortTag | IntTag | CharTag => true } @@ -591,12 +592,21 @@ trait ParallelMatching extends ast.TreeDSL /** mixture rule for type tests **/ class MixTypes(val pats: Patterns, val rest: Rep) extends RuleApplication { - private def subpatterns(p: Pattern): List[Pattern] = - p.tree match { - case app @ Apply(fn, ps) if isCaseClass(app.tpe) && fn.isType => if (pats.isCaseHead) toPats(ps) else pats.dummyPatterns - case Apply(fn, xs) if !xs.isEmpty || fn.isType => abort("strange Apply") - case _ => pats.dummyPatterns - } + // see bug1434.scala for an illustration of why "x <:< y" is insufficient. + // this code is definitely inadequate at best. Inherited comment: + // + // an approximation of _tp1 <:< tp2 that ignores _ types. this code is wrong, + // ideally there is a better way to do it, and ideally defined in Types.scala + private def matches(arg1: Type, arg2: Type) = { + val List(t1, t2) = List(arg1, arg2) map decodedEqualsType + def eqSymbols = t1.typeSymbol eq t2.typeSymbol + def isSubtype = t1.baseTypeSeq exists (_.typeSymbol eq t2.typeSymbol) + + (t1 <:< t2) || ((t1, t2) match { + case (_: TypeRef, _: TypeRef) => !t1.isArray && (t1.prefix =:= t2.prefix) && (eqSymbols || isSubtype) + case _ => false + }) + } // moreSpecific: more specific patterns // subsumed: more general patterns (subsuming current), rows index and subpatterns @@ -604,42 +614,38 @@ trait ParallelMatching extends ast.TreeDSL def join[T](xs: List[Option[T]]): List[T] = xs.flatMap(x => x) val (moreSpecific, subsumed, remaining) : (List[Tree], List[(Int, List[Tree])], List[(Int, Tree)]) = unzip3( for ((pattern, j) <- pats.pzip()) yield { - val spat: Tree = pattern.tree - val pat: Tree = pattern.boundTree + def spat: Tree = pattern.tree + def pat: Tree = pattern.boundTree def eqHead(tpe: Type) = pats.headType =:= tpe def alts(yes: Tree, no: Tree) = if (eqHead(pat.tpe)) yes else no - lazy val isDef = isDefaultPattern(pat) - lazy val dummy = (j, pats.dummies) - lazy val pass = (j, pat) - lazy val subs = (j, subpatterns(Pattern(pat)) map (_.boundTree)) - - lazy val cmpOld: TypeComp = spat.tpe cmp pats.headType // contains type info about pattern's type vs. head pattern - import cmpOld.{ erased } - - def erased_xIsaY = erased.xIsaY - def erased_yIsaX = erased.yIsaX + def isDef = pattern.isDefault + lazy val dummy = (j, pats.dummies) + lazy val pass = (j, pat) + lazy val subs = (j, pattern.subpatterns(pats) map (_.boundTree)) // scrutinee, pattern - val (s, p) = (decodedEqualsType(spat.tpe), decodedEqualsType(pats.headType)) - def xIsaY = s <:< p - def yIsaX = p <:< s + val (s, p) = (spat.tpe, pats.headType) + + def sMatchesP = matches(s, p) + def pMatchesS = matches(p, s) // each pattern will yield a triple of options corresponding to the three lists, // which will be flattened down to the values implicit def mkOpt[T](x: T): Option[T] = Some(x) // limits noise from Some(value) (spat match { - case LIT(null) if !eqHead(spat.tpe) => (None, None, pass) // special case for constant null - case _ if pats.isObjectTest(pat) => (EmptyTree, dummy, None) // matching an object - case Typed(p @ Stripped(_: UnApply), _) if xIsaY => (p, dummy, None) // <:< is never <equals> - case q @ Typed(pp, _) if xIsaY => (alts(pp, q), dummy, None) // never =:= for <equals> - // case z: UnApply => (None, None, pass) - case z: UnApply => (EmptyTree, dummy, pass) - case _ if erased.xIsaY || xIsaY && !isDef => (alts(EmptyTree, pat), subs, None) // never =:= for <equals> - case _ if erased.yIsaX || yIsaX || isDef => (EmptyTree, dummy, pass) // subsuming (matched *and* remaining pattern) - case _ => (None, None, pass) - // The below fixes bugs 425 and 816 with only the small downside + case LIT(null) if !eqHead(spat.tpe) => (None, None, pass) // special case for constant null + case _ if pats.isObjectTest(pattern) => (EmptyTree, dummy, None) // matching an object + case Typed(pp @ Stripped(_: UnApply), _) if sMatchesP => (pp, dummy, None) // <:< is never <equals> + case q @ Typed(pp, _) if sMatchesP => (alts(pp, q), dummy, None) // never =:= for <equals> + case z: UnApply => (EmptyTree, dummy, pass) + case _ => + if (sMatchesP && !pattern.isDefault) (alts(EmptyTree, pat), subs, None) + else if (pMatchesS || pattern.isDefault) (EmptyTree, dummy, pass) + else (None, None, pass) + + // The below (once fixed) bugs 425 and 816 with only the small downside // of causing 60 other tests to fail. // case _ => // if (erased_xIsaY || xIsaY && !isDef) (alts(EmptyTree, pat), subs, None) // never =:= for <equals> @@ -707,7 +713,6 @@ trait ParallelMatching extends ast.TreeDSL def castedScrut = typedValDef(casted.sym, scrut.id AS_ANY castedTpe) def needCast = if (casted.sym ne scrut.sym) List(castedScrut) else Nil - val vdefs = needCast ::: ( for ((tmp, accessor) <- caseTemps zip cfa) yield typedValDef(tmp, typer typed fn(casted.id, accessor)) diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index 6c72caed0c..078c0862e7 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -83,7 +83,11 @@ trait Patterns extends ast.TreeDSL { // 8.1.5 case class ConstructorPattern(tree: Apply) extends ApplyPattern { - require(fn.isType) + require(fn.isType && isCaseClass(tpe)) + + override def subpatterns(pats: MatchMatrix#Patterns) = + if (pats.isCaseHead) args map Pattern.apply + else super.subpatterns(pats) override def simplify(testVar: Symbol) = if (args.isEmpty) this rebindToEmpty tree.tpe @@ -158,7 +162,7 @@ trait Patterns extends ast.TreeDSL { // 8.1.10 case class AlternativePattern(tree: Alternative) extends Pattern { private val Alternative(subtrees) = tree - override def subpatterns(pats: MatchMatrix#Patterns) = subtrees map Pattern.apply + // override def subpatterns(pats: MatchMatrix#Patterns) = subtrees map Pattern.apply } // 8.1.11 @@ -235,15 +239,6 @@ trait Patterns extends ast.TreeDSL { sealed abstract class ApplyPattern extends Pattern { protected lazy val Apply(fn, args) = tree private def isCaseClass = tree.tpe.typeSymbol hasFlag Flags.CASE - - override def subpatterns(pats: MatchMatrix#Patterns): List[Pattern] = - if (isConstructorPattern && isCaseClass) { - if (pats.isCaseHead) args map Pattern.apply - else pats.dummyPatterns - } - else if (isConstructorPattern && !args.isEmpty) abort("Strange Apply") - else pats.dummyPatterns - def isConstructorPattern = fn.isType } // trait SimplePattern extends Pattern { @@ -256,7 +251,7 @@ trait Patterns extends ast.TreeDSL { def simplify(testVar: Symbol): Pattern = this def simplify(): Pattern = this simplify NoSymbol - def subpatterns(pats: MatchMatrix#Patterns): List[Pattern] = Nil + def subpatterns(pats: MatchMatrix#Patterns): List[Pattern] = pats.dummyPatterns // 8.1.13 // A pattern p is irrefutable for type T if any of the following applies: @@ -327,10 +322,6 @@ trait Patterns extends ast.TreeDSL { final def isAlternative = cond(tree) { case Alternative(_) => true } final def isRightIgnoring = cond(tree) { case ArrayValue(_, xs) if !xs.isEmpty => Pattern(xs.last).isStar } - /** returns true if pattern tests an object */ - final def isObjectTest(head: Type) = - isSymValid && prefix.isStable && (head =:= mkSingleton) - /** Helpers **/ private def strip(t: Tree): List[Symbol] = t match { case b @ Bind(_, pat) => b.symbol :: strip(pat) |