summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala67
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternNodes.scala8
-rw-r--r--src/compiler/scala/tools/nsc/matching/Patterns.scala55
3 files changed, 89 insertions, 41 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index adeaf452fa..cbc7615e7e 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -139,11 +139,7 @@ trait ParallelMatching extends ast.TreeDSL
lazy val tail = ps.tail
lazy val size = ps.length
- lazy val headType = head.tree match {
- case p @ (_:Ident | _:Select) => head.mkSingleton // should be singleton object
- case UnapplyParamType(x) => x
- case _ => head.tpe
- }
+ lazy val headType = head.matchingType
def isCaseHead = head.isCaseClass
def dummies = if (isCaseHead) getDummies(headType.typeSymbol.caseFieldAccessors.length) else Nil
def dummyPatterns = dummies map (x => Pattern(x))
@@ -532,6 +528,14 @@ trait ParallelMatching extends ast.TreeDSL
*/
final class MixSequenceStar(pats: Patterns, rest: Rep) extends MixSequence(pats, rest) {
// in principle, we could optimize more, but variable binding gets complicated (@todo use finite state methods instead)
+ // override def getSubPatterns(minlen: Int, x: Tree): Option[List[Pattern]] = {
+ // implicit val min = minlen
+ // implicit val tpe = scrut.seqType
+ // Pattern(x) match {
+ // case SeqStarSubPatterns(xs) => Some(xs)
+ // case _ => None
+ // }
+ // }
override def getSubPatterns(minlen: Int, x: Tree): Option[List[Pattern]] = condOpt(x) {
case av @ ArrayValue(_,xs) if (!isRightIgnoring(av) && xs.length == minlen) => // Seq(p1,...,pN)
toPats(xs ::: List(gen.mkNil, EmptyTree))
@@ -564,7 +568,7 @@ trait ParallelMatching extends ast.TreeDSL
}
}
- val label = owner.newLabel(scrut.pos, newName(scrut.pos, "failCont%")) // warning, untyped
+ val label = owner.newLabel(scrut.pos, newName(scrut.pos, "failCont%")) // warning, untyped - typed in tree()
val succ = List(
rest.rows.head.insert2(List(NoPattern), head.boundVariables, scrut.sym),
Row(emptyPatterns(1 + rest.tvars.length), NoBinding, NoGuard, shortCut(label))
@@ -612,24 +616,21 @@ trait ParallelMatching extends ast.TreeDSL
// 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[Tree], List[(Int, List[Tree])], List[(Int, Tree)]) = unzip3(
+ val (moreSpecific, subsumed, remaining) : (List[Pattern], List[(Int, List[Pattern])], List[(Int, Pattern)]) = unzip3(
for ((pattern, j) <- pats.pzip()) yield {
- 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
- def isObjectTest = pattern.isObject && eqHead(pattern.mkSingleton)
-
- lazy val dummy = (j, pats.dummies)
- lazy val pass = (j, pattern.boundTree)
- lazy val subs = (j, (pattern subpatterns pats) map (_.boundTree))
-
// scrutinee, head of pattern group
val (s, p) = (pattern.tpe, pats.headType)
def sMatchesP = matches(s, p)
def pMatchesS = matches(p, s)
+ def sEqualsP = p =:= s
+
+ def alts[T](yes: T, no: T): T = if (sEqualsP) yes else no
+ def isObjectTest = pattern.isObject && (pats.headType =:= pattern.mkSingleton)
+
+ lazy val dummy = (j, pats.dummyPatterns)
+ lazy val pass = (j, pattern)
+ lazy val subs = (j, pattern subpatterns pats)
// each pattern will yield a triple of options corresponding to the three lists,
// which will be flattened down to the values
@@ -644,23 +645,23 @@ trait ParallelMatching extends ast.TreeDSL
// (4) never =:= for <equals>
(pattern match {
- case Pattern(LIT(null), _) if !eqHead(pattern.tpe) => (None, None, pass) // (1)
- case x if isObjectTest => (EmptyTree, dummy, None) // (2)
- case Pattern(Typed(pp @ Pattern(_: UnApply, _), _), _) if sMatchesP => (pp, dummy, None) // (3)
- case Pattern(Typed(pp, _), _) if sMatchesP => (alts(pp, pattern.tree), dummy, None) // (4)
- case Pattern(_: UnApply, _) => (EmptyTree, dummy, pass)
- case x if !x.isDefault && sMatchesP => (alts(EmptyTree, pat), subs, None)
- case x if x.isDefault || pMatchesS => (EmptyTree, dummy, pass)
+ case Pattern(LIT(null), _) if !sEqualsP => (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 (once fixed) bugs 425 and 816 with only the small downside
- // of causing 60 other tests to fail.
+ // 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[Tree], Option[(Int, List[Tree])], Option[(Int, Tree)])
+ }) : (Option[Pattern], Option[(Int, List[Pattern])], Option[(Int, Pattern)])
}
) match { case (x,y,z) => (join(x), join(y), join(z)) }
@@ -687,14 +688,14 @@ trait ParallelMatching extends ast.TreeDSL
val accessorVars = if (pats.isCaseHead) mkAccessors else Nil
val newRows =
for ((j, ps) <- subtests) yield
- (rest rows j).insert2(toPats(ps), pats(j).boundVariables, casted.sym)
+ (rest rows j).insert2(ps, pats(j).boundVariables, casted.sym)
Branch(
casted,
// succeeding => transition to translate(subsumed) (taking into account more specific)
make(subtestVars ::: accessorVars ::: rest.tvars, newRows),
// fails => transition to translate(remaining)
- mkFailOpt(remaining map tupled((p1, p2) => rest rows p1 insert Pattern(p2)))
+ mkFailOpt(remaining map tupled((p1, p2) => rest rows p1 insert p2))
)
}
@@ -730,7 +731,7 @@ trait ParallelMatching extends ast.TreeDSL
}
}
- /*** States, Rows, Etc. ***/
+ /*** States, Rows, Etc. ***/
case class Row(pat: List[Pattern], subst: Bindings, guard: Guard, bx: Int) {
def insert(h: Pattern) = copy(pat = h :: pat)
@@ -773,7 +774,7 @@ trait ParallelMatching extends ast.TreeDSL
}
object ExpandedMatrix {
- def unapply(x: ExpandedMatrix) = Some(x.rows, x.targets)
+ def unapply(x: ExpandedMatrix) = Some((x.rows, x.targets))
def apply(rows: List[Row], targets: List[FinalState]) = new ExpandedMatrix(rows, targets)
}
class ExpandedMatrix(val rows: List[Row], val targets: List[FinalState])
@@ -977,7 +978,7 @@ trait ParallelMatching extends ast.TreeDSL
val NoRep = Rep(Nil, Nil)
/** Expands the patterns recursively. */
- final def expand(roots: List[Symbol], cases: List[Tree]): ExpandedMatrix = {
+ final def expand(roots: List[Symbol], cases: List[CaseDef]): ExpandedMatrix = {
val (rows, finals) = List.unzip(
for ((CaseDef(pat, guard, body), index) <- cases.zipWithIndex) yield {
def mkRow(ps: List[Pattern]) = Row(ps, NoBinding, Guard(guard), index)
diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
index 59fe3ed0d7..6a0e48f9c0 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
@@ -60,12 +60,4 @@ trait PatternNodes extends ast.TreeDSL
def normalizedListPattern(pats: List[Tree], tptArg: Type): Tree =
pats.foldRight(gen.mkNil)(listFolder(tptArg))
-
- object UnapplyParamType {
- def unapply(x: Tree): Option[Type] = condOpt(unbind(x)) {
- case UnApply(Apply(fn, _), _) => fn.tpe match {
- case m: MethodType => m.paramTypes.head
- }
- }
- }
}
diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala
index 3c4ea68b1c..393a9df585 100644
--- a/src/compiler/scala/tools/nsc/matching/Patterns.scala
+++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala
@@ -49,6 +49,7 @@ trait Patterns extends ast.TreeDSL {
case class VariablePattern(tree: Ident) extends Pattern {
override def irrefutableFor(tpe: Type) = true
override def simplify(testVar: Symbol) = this.rebindToEqualsCheck()
+ // override def matchingType = mkSingleton ??? XXX
}
// 8.1.1 (b)
@@ -74,11 +75,13 @@ trait Patterns extends ast.TreeDSL {
// 8.1.4
case class StableIdPattern(tree: Ident) extends Pattern {
override def simplify(testVar: Symbol) = this.rebindToEqualsCheck()
+ override def matchingType = mkSingleton
}
// 8.1.4 (b)
case class SelectPattern(tree: Select) extends Pattern {
override def simplify(testVar: Symbol) = this.rebindToEqualsCheck()
+ override def matchingType = mkSingleton
}
// 8.1.5
@@ -130,6 +133,11 @@ trait Patterns extends ast.TreeDSL {
private val MethodType(List(arg, _*), _) = fn.tpe
private def uaTyped = Typed(tree, TypeTree(arg.tpe)) setType arg.tpe
+ override def matchingType = arg.tpe
+
+ // lazy val ua @ UnApply(app, args) = head.tree
+ // lazy val Apply(fxn, _ :: trailingArgs) = app
+
// can fix #1697 here?
override def simplify(testVar: Symbol) =
if (testVar.tpe <:< arg.tpe) this
@@ -314,6 +322,9 @@ trait Patterns extends ast.TreeDSL {
def prefix = tpe.prefix
def isEmpty = tree.isEmpty
+ // this is used when this pattern is the foremost under consideration
+ def matchingType = tpe
+
def isSymValid = (sym != null) && (sym != NoSymbol)
def isModule = sym.isModule || tpe.termSymbol.isModule
def isCaseClass = tpe.typeSymbol hasFlag Flags.CASE
@@ -356,4 +367,48 @@ trait Patterns extends ast.TreeDSL {
}
override def hashCode() = boundTree.hashCode()
}
+
+ /*** Extractors ***/
+
+ object UnapplyParamType {
+ def unapply(x: Tree): Option[Type] = condOpt(unbind(x)) {
+ case UnApply(Apply(fn, _), _) => fn.tpe match {
+ case m: MethodType => m.paramTypes.head
+ }
+ }
+ }
+ //
+ // protected def getSubPatterns(len: Int, x: Tree): Option[List[Pattern]] = condOpt(x) {
+ // case av @ ArrayValue(_,xs) if !isRightIgnoring(av) && xs.length == len => toPats(xs) ::: List(NoPattern)
+ // case av @ ArrayValue(_,xs) if isRightIgnoring(av) && xs.length == len+1 => removeStar(toPats(xs)) // (*)
+ // case EmptyTree | WILD() => emptyPatterns(len + 1)
+ // }
+
+ object SeqStarSubPatterns {
+ def removeStar(xs: List[Tree], seqType: Type): List[Pattern] = {
+ val ps = toPats(xs)
+ ps.init ::: List(ps.last rebindToType seqType)
+ }
+
+ // override def getSubPatterns(minlen: Int, x: Tree): Option[List[Pattern]] = condOpt(x) {
+ // case av @ ArrayValue(_,xs) if (!isRightIgnoring(av) && xs.length == minlen) => // Seq(p1,...,pN)
+ // toPats(xs ::: List(gen.mkNil, EmptyTree))
+ // case av @ ArrayValue(_,xs) if ( isRightIgnoring(av) && xs.length-1 == minlen) => // Seq(p1,...,pN,_*)
+ // removeStar(toPats(xs)) ::: List(NoPattern)
+ // case av @ ArrayValue(_,xs) if ( isRightIgnoring(av) && xs.length-1 < minlen) => // Seq(p1..,pJ,_*) J < N
+ // emptyPatterns(minlen + 1) ::: List(Pattern(x))
+ // case EmptyTree | WILD() =>
+ // emptyPatterns(minlen + 1 + 1)
+ // }
+
+ def unapply(x: Pattern)(implicit min: Int, seqType: Type): Option[List[Pattern]] = x.tree match {
+ case av @ ArrayValue(_, xs) =>
+ if (!isRightIgnoring(av) && xs.length == min) Some(toPats(xs ::: List(gen.mkNil, EmptyTree))) // Seq(p1,...,pN)
+ else if ( isRightIgnoring(av) && xs.length-1 == min) Some(removeStar(xs, seqType) ::: List(NoPattern)) // Seq(p1,...,pN,_*)
+ else if ( isRightIgnoring(av) && xs.length-1 == min) Some(emptyPatterns(min + 1) ::: List(x)) // Seq(p1..,pJ,_*) J < N
+ else None
+ case _ =>
+ if (x.isDefault) Some(emptyPatterns(min + 1 + 1)) else None
+ }
+ }
} \ No newline at end of file