diff options
author | Paul Phillips <paulp@improving.org> | 2009-10-12 06:09:40 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-10-12 06:09:40 +0000 |
commit | bf9ca9a2b7455164c335a48826143749b6b107eb (patch) | |
tree | e4dbf10225b17d6df33d1689a65e1724a9d79d4a /src/compiler | |
parent | 89a03016abe7e23295fa9cef2f8217cc41f2c194 (diff) | |
download | scala-bf9ca9a2b7455164c335a48826143749b6b107eb.tar.gz scala-bf9ca9a2b7455164c335a48826143749b6b107eb.tar.bz2 scala-bf9ca9a2b7455164c335a48826143749b6b107eb.zip |
Taking a first crack at straightening out MixTy...
Taking a first crack at straightening out MixTypes.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/MatchSupport.scala | 41 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/ParallelMatching.scala | 125 |
2 files changed, 60 insertions, 106 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/MatchSupport.scala b/src/compiler/scala/tools/nsc/matching/MatchSupport.scala index 3ed106cb40..499523bc1a 100644 --- a/src/compiler/scala/tools/nsc/matching/MatchSupport.scala +++ b/src/compiler/scala/tools/nsc/matching/MatchSupport.scala @@ -30,6 +30,23 @@ trait MatchSupport extends ast.TreeDSL import definitions._ implicit def enrichType(x: Type): RichType = new RichType(x) + // 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[matching] def matches(arg1: Type, arg2: Type) = { + val List(t1, t2) = List(arg1, arg2) map decodedEqualsType + def eqSymbols = t1.typeSymbol eq t2.typeSymbol + // note: writing this as "t1.baseTypeSeq exists (_ =:= t2)" does not lead to 1434 passing. + 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 + }) + } + class RichType(undecodedTpe: Type) { def tpe = decodedEqualsType(undecodedTpe) def isAnyRef = tpe <:< AnyRefClass.tpe @@ -135,27 +152,6 @@ trait MatchSupport extends ast.TreeDSL def indentAll(s: Seq[Any]) = s map (" " + _.toString() + "\n") mkString } - /** Transforms a list of triples into a triple of lists. - * - * @param xs the list of triples to unzip - * @return a triple of lists. - */ - def unzip3[A,B,C](xs: List[(A,B,C)]): (List[A], List[B], List[C]) = { - import collection.mutable.ListBuffer - - val b1 = new ListBuffer[A] - val b2 = new ListBuffer[B] - val b3 = new ListBuffer[C] - var xc = xs - while (!xc.isEmpty) { - b1 += xc.head._1 - b2 += xc.head._2 - b3 += xc.head._3 - xc = xc.tail - } - (b1.toList, b2.toList, b3.toList) - } - /** Drops the 'i'th element of a list. */ def dropIndex[T](xs: List[T], n: Int) = { @@ -171,9 +167,6 @@ trait MatchSupport extends ast.TreeDSL /** A tree printer which is stingier about vertical whitespace and unnecessary * punctuation than the standard one. */ - - // lazy val compactTreePrinter = compactTreePrinters.create() - class CompactTreePrinter extends { val trees: global.type = global } with TreePrinters { diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 44c5b4dbb5..7d5850ac27 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -526,77 +526,49 @@ trait ParallelMatching extends ast.TreeDSL override def toString() = "MixEquals(%s == %s)".format(scrut, head) } - /** mixture rule for type tests - **/ + /** Mixture rule for type tests. + * moreSpecific: more specific patterns + * subsumed: more general patterns (subsuming current), rows index and subpatterns + * remaining: remaining, rows index and pattern + */ class MixTypes(val pmatch: PatternMatch, val rest: Rep) extends RuleApplication { - // 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 - // note: writing this as "t1.baseTypeSeq exists (_ =:= t2)" does not lead to 1434 passing. - 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 - }) - } + case class Yes(bx: Int, moreSpecific: Pattern, subsumed: List[Pattern]) + case class No(bx: Int, remaining: Pattern) - // moreSpecific: more specific patterns - // subsumed: more general patterns (subsuming current), rows index and subpatterns - // remaining: remaining, rows index and pattern - def join[T](xs: List[Option[T]]): List[T] = xs.flatMap(x => x) - val (moreSpecific, subsumed, remaining) : (List[Pattern], List[(Int, List[Pattern])], List[(Int, Pattern)]) = unzip3( + val (yeses, noes) : (List[Yes], List[No]) = List.unzip( for ((pattern, j) <- pmatch.pzip()) yield { // scrutinee, head of pattern group - val (s, p) = (pattern.tpe, pmatch.headType) + val (s, p) = (pattern.tpe, head.necessaryType) + + def isEquivalent = head.necessaryType =:= pattern.tpe + def isObjectTest = pattern.isObject && (p =:= pattern.necessaryType) def sMatchesP = matches(s, p) def pMatchesS = matches(p, s) - def alts[T](yes: T, no: T): T = if (p =:= s) yes else no - def isObjectTest = pattern.isObject && (p =:= pattern.necessaryType) + def ifEquiv(yes: Pattern): Pattern = if (isEquivalent) yes else pattern - lazy val dummy = (j, pmatch.dummies) - lazy val pass = (j, pattern) - lazy val subs = (j, pattern subpatterns pmatch) + def passl(p: Pattern = NoPattern, ps: List[Pattern] = pmatch.dummies) = Some(Yes(j, p, ps)) + def passr() = Some( No(j, pattern)) - // 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) - - // Note - at the moment these comments are mostly trivial or nonsensical, but - // they persist from a much earlier time and I still try to read the tea leaves - // - // (1) special case for constant null - // (2) matching an object - // (3) <:< is never <equals> - // (4) never =:= for <equals> + def typed(pp: Tree) = passl(ifEquiv(Pattern(pp))) + def subs() = passl(ifEquiv(NoPattern), pattern subpatterns pmatch) (pattern match { - case Pattern(LIT(null), _) if !(p =:= s) => (None, None, pass) // (1) - case x if isObjectTest => (NoPattern, dummy, None) // (2) - // case Pattern(Typed(pp @ Pattern(_: UnApply, _), _), _) if sMatchesP => (Pattern(pp), dummy, None) // (3) - case Pattern(Typed(pp, _), _) if sMatchesP => (alts(Pattern(pp), pattern), dummy, None) // (4) - case Pattern(_: UnApply, _) => (NoPattern, dummy, pass) - case x if !x.isDefault && sMatchesP => (alts(NoPattern, pattern), subs, None) - case x if x.isDefault || pMatchesS => (NoPattern, dummy, pass) - case _ => (None, None, pass) - - // The below (back when the surrounding code looked much different) 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> - // else if (isDef) (EmptyTree, dummy, pass) - // else (None, None, pass) - - }) : (Option[Pattern], Option[(Int, List[Pattern])], Option[(Int, Pattern)]) + case Pattern(LIT(null), _) if !(p =:= s) => (None, passr) // (1) + case x if isObjectTest => (passl(), None) // (2) + case Pattern(Typed(pp, _), _) if sMatchesP => (typed(pp), None) // (4) + case Pattern(_: UnApply, _) => (passl(), passr) + case x if !x.isDefault && sMatchesP => (subs(), None) + case x if x.isDefault || pMatchesS => (passl(), passr) + case _ => (None, passr) + }) : (Option[Yes], Option[No]) } - ) match { case (x,y,z) => (join(x), join(y), join(z)) } + ) match { case (x,y) => (x.flatten, y.flatten) } + + val moreSpecific = yeses map (_.moreSpecific) + val subsumed = yeses map (x => (x.bx, x.subsumed)) + val remaining = noes map (x => (x.bx, x.remaining)) // temporary checks so we're less crashy while we determine what to implement. def checkErroneous(scrut: Scrutinee): Type = { @@ -608,38 +580,27 @@ trait ParallelMatching extends ast.TreeDSL } } - override def toString = { - val msgs = List( - "moreSpecific: " + pp(moreSpecific), - " subsumed: " + pp(subsumed), - " remaining: " + pp(remaining) - ) - - super.toString() + "\n" + indentAll(msgs) - } - - private def isAnyMoreSpecific = moreSpecific exists (x => !x.isEmpty) - private def mkZipped = moreSpecific zip subsumed map { - case (mspat, (j, pmatch)) => (j, mspat :: pmatch) - } + private def mkZipped = + for (Yes(j, moreSpecific, subsumed) <- yeses) yield + j -> (moreSpecific :: subsumed) lazy val casted = scrut castedTo pmatch.headType lazy val cond = condition(checkErroneous(casted), scrut) - lazy val success = { - val (subtests, subtestVars) = - if (isAnyMoreSpecific) (mkZipped, List(casted.pv)) - else (subsumed, Nil) + private def isAnyMoreSpecific = yeses exists (x => !x.moreSpecific.isEmpty) + lazy val (subtests, subtestVars) = + if (isAnyMoreSpecific) (mkZipped, List(casted.pv)) + else (subsumed, Nil) - val newRows = - for ((j, ps) <- subtests) yield - (rest rows j).insert2(ps, pmatch(j).boundVariables, casted.sym) - - val srep = - remake(newRows, subtestVars ::: casted.accessorPatternVars, includeScrut = false) + lazy val newRows = + for ((j, ps) <- subtests) yield + (rest rows j).insert2(ps, pmatch(j).boundVariables, casted.sym) + lazy val success = { + val srep = remake(newRows, subtestVars ::: casted.accessorPatternVars, includeScrut = false) squeezedBlock(casted.allValDefs, srep.toTree) } + lazy val failure = mkFail(remaining map tupled((p1, p2) => rest rows p1 insert p2)) |