<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -12,7 +12,7 @@ import util.Position
 import transform.ExplicitOuter
 import symtab.Flags
 import collection._
-import mutable.{ BitSet, HashMap, ListBuffer }
+import mutable.ListBuffer
 import immutable.IntMap
 import annotation.elidable
 import Function.tupled
@@ -209,22 +209,26 @@ trait ParallelMatching extends ast.TreeDSL
     val NoGuard = Guard(EmptyTree)
 
     /***** Rule Applications *****/
+    
+    trait RuleApplicationFormal extends RuleApplication {
+      def cond: Tree
+      def success: Tree
+      def failure: Tree
+      
+      def codegen: Tree = IF (cond) THEN (success) ELSE (failure)
+    }    
 
     sealed abstract class RuleApplication {
       def pmatch: PatternMatch
       def rest: Rep
+      
       lazy val PatternMatch(scrut, patterns) = pmatch
       lazy val head = pmatch.head
-
-      /** Creates Some(fail rule) even if xs == Nil. */
-      def mkFail(xs: List[Row]): Option[Rep] = Some(make(scrut.sym :: rest.tvars, xs))
       
-      /** Returns None if xs == Nil, Some(fail rule) otherwise. */
-      def mkFailOpt(xs: List[Row]): Option[Rep] = if (xs.isEmpty) None else mkFail(xs)
-        
-      /** Splices scrutinee's symbol in between the given lists */
-      def mkNewRep(pre: List[Symbol], post: List[Symbol], rows: List[Row]) =
-        make(pre ::: scrut.sym :: post, rows)
+      def mkFail(xs: List[Row]): Tree = xs match {
+        case Nil  =&gt; failTree
+        case _    =&gt; make(scrut.sym :: rest.tvars, xs).toTree
+      }
 
       /** translate outcome of the rule application into code (possible involving recursive application of rewriting) */
       def tree(): Tree
@@ -331,84 +335,90 @@ trait ParallelMatching extends ast.TreeDSL
     /** mixture rule for unapply pattern
      */
     class MixUnapply(val pmatch: PatternMatch, val rest: Rep, typeTest: Boolean) extends RuleApplication {
-      // Note: trailingArgs is not necessarily Nil, because unapply can take implicit parameters.
+      val uapattern = head match { case x: UnapplyPattern =&gt; x ; case _ =&gt; abort(&quot;XXX&quot;) }
       val ua @ UnApply(app, args) = head.tree
-      val Apply(fxn, _ :: trailingArgs) = app
 
+      lazy val zipped      = pmatch pzip rest.rows
+
+      // Note: trailingArgs is not necessarily Nil, because unapply can take implicit parameters.      
+      val Apply(fxn, _ :: trailingArgs) = app
+      
+      lazy val unapplyVar   = newVar(ua.pos, app.tpe, scrut.flags)
+      lazy val unapplyRHS   = Apply(fxn, scrut.id :: trailingArgs) setType unapplyVar.tpe
+      lazy val unapplyCall  = typedValDef(unapplyVar, unapplyRHS)
+      
+      /** Create a Boolean representing whether the unapply succeeded */
+      def unapplyToCond(t: Tree): Tree =
+        if (unapplyCall.symbol.tpe.isBoolean) ID(t.symbol)
+        else t.symbol IS_DEFINED
+      
+      // XXX in transition.
       object sameUnapplyCall {
         private def sameFunction(fn1: Tree) = fxn.symbol == fn1.symbol &amp;&amp; (fxn equalsStructure fn1)
-        
+
         def unapply(p: Pattern) = condOpt(p) {
           case Pattern(UnApply(Apply(fn1, _), args), _) if sameFunction(fn1)  =&gt; args
         }
+      }      
+      object SameUnapply {
+        def unapply(p: Pattern) = p match {
+          case x: UnapplyPattern if uapattern isSameUnapply x =&gt; Some(args)
+          case _                                              =&gt; None
+        }
       }
-
-    /** returns (un)apply-call, success-rep, optional fail-rep */
-      final def getTransition(): Branch[UnapplyCall] = {
-        val unapplyRes  = newVar(ua.pos, app.tpe, scrut.flags)
-        val rhs         = Apply(fxn, scrut.id :: trailingArgs) setType unapplyRes.tpe
-        val zipped      = pmatch pzip rest.rows
-        val nrowsOther  = zipped.tail flatMap { 
-          case (sameUnapplyCall(_), _)  =&gt; Nil
-          case (pat, r)                 =&gt; List(r insert pat)
+      def isSameUnapply(p: Pattern) = SameUnapply.unapply(p).isDefined
+      
+      // Second argument is number of dummies to prepend in the default case
+      def mkNewRows(sameFilter: (List[Tree]) =&gt; List[Tree], dum: Int) =
+        for ((pat, r) &lt;- zipped) yield pat match {
+          case sameUnapplyCall(args)  =&gt; r.insert2(toPats(sameFilter(args)) ::: List(NoPattern), pat.boundVariables, scrut.sym)
+          case _                      =&gt; r insert (emptyPatterns(dum) ::: List(pat))
         }
+      def mkGet(s: Symbol) = typedValDef(s, fn(ID(unapplyVar), nme.get))
+      def mkVar(tpe: Type) = newVar(ua.pos, tpe, scrut.flags)
 
-        def mkTransition(vdefs: List[Tree], ntemps: List[Symbol], nrows: List[Row]) =
-          Branch(
-            UnapplyCall(typedValDef(unapplyRes, rhs), vdefs),
-            mkNewRep(ntemps, rest.tvars, nrows),
-            mkFailOpt(nrowsOther)
-          )
-
-        // Second argument is number of dummies to prepend in the default case
-        def mkNewRows(sameFilter: (List[Tree]) =&gt; List[Tree], dum: Int) =
-          for ((pat, r) &lt;- zipped) yield pat match {
-            case sameUnapplyCall(args)  =&gt; r.insert2(toPats(sameFilter(args)) ::: List(NoPattern), pat.boundVariables, scrut.sym)
-            case _                      =&gt; r insert (emptyPatterns(dum) ::: List(pat))
-          }
-        def mkGet(s: Symbol) = typedValDef(s, fn(ID(unapplyRes), nme.get))
-        def mkVar(tpe: Type) = newVar(ua.pos, tpe, scrut.flags)
+      final def tree() = {
+        val failRows = zipped.tail filterNot (x =&gt; isSameUnapply(x._1)) map { case (pat, r) =&gt; r insert pat }
 
         // 0 args =&gt; Boolean, 1 =&gt; Option[T], &gt;1 =&gt; Option[? &lt;: ProductN[T1,...,Tn]]
-        args.length match {
-          case 0  =&gt;
-            mkTransition(Nil, Nil, mkNewRows((xs) =&gt; Nil, 0))
-
-          case 1 =&gt;
-            val vsym  = mkVar(app.tpe typeArgs 0)
-            val nrows = mkNewRows(xs =&gt; List(xs.head), 1)
-            val vdef  = mkGet(vsym)
+        
+        val (vdefs, ntemps, nrows) =
+          args.length match {
+            case 0  =&gt;
+              (Nil, Nil, mkNewRows((xs) =&gt; Nil, 0))
 
-            mkTransition(List(vdef), List(vsym), nrows)
+            case 1 =&gt;
+              val vsym  = mkVar(app.tpe typeArgs 0)
+              val nrows = mkNewRows(xs =&gt; List(xs.head), 1)
+              val vdef  = mkGet(vsym)
 
-          case _ =&gt;
-            val uresGet   = mkVar(app.tpe typeArgs 0)
-            val vdefHead  = mkGet(uresGet)
-            val ts        = getProductArgs(uresGet.tpe).get
-            val nrows     = mkNewRows(identity, ts.size)
+              (List(vdef), List(vsym), nrows)
 
-            val (vdefs: List[Tree], vsyms: List[Symbol]) = List.unzip(
-              for ((vtpe, i) &lt;- ts.zipWithIndex) yield {
-                val vchild  = mkVar(vtpe)
-                val accSym  = productProj(uresGet, i+1)
-                val rhs     = fn(ID(uresGet), accSym)
+            case _ =&gt;
+              val uresGet   = mkVar(app.tpe typeArgs 0)
+              val vdefHead  = mkGet(uresGet)
+              val ts        = getProductArgs(uresGet.tpe).get
+              val nrows     = mkNewRows(identity, ts.size)
 
-                (typedValDef(vchild, rhs), vchild)
-              })
+              val (vdefs: List[Tree], vsyms: List[Symbol]) = List.unzip(
+                for ((vtpe, i) &lt;- ts.zipWithIndex) yield {
+                  val vchild  = mkVar(vtpe)
+                  val accSym  = productProj(uresGet, i+1)
+                  val rhs     = fn(ID(uresGet), accSym)
 
-            mkTransition(vdefHead :: vdefs, vsyms, nrows)
-        }
-      } /* def getTransition(...) */
+                  (typedValDef(vchild, rhs), vchild)
+                })
 
-      final def tree() = {
-        val Branch(uacall @ UnapplyCall(ua, vdefs), srep, frep) = this.getTransition
-        val cond = uacall.matchCondition        
-        val succ = srep.toTree
-        val fail = frep map (_.toTree) getOrElse (failTree)
+              (vdefHead :: vdefs, vsyms, nrows)
+          }
+          
+        val cond = unapplyToCond(unapplyCall)
+        val success = make(ntemps ::: scrut.sym :: rest.tvars, nrows).toTree
+        val failure = mkFail(failRows)
 
         squeezedBlock(
-          List(handleOuter(ua)),
-          IF (cond) THEN squeezedBlock(vdefs, succ) ELSE fail
+          List(handleOuter(unapplyCall)),
+          IF (cond) THEN squeezedBlock(vdefs, success) ELSE failure
         )
       }
     }
@@ -451,7 +461,6 @@ trait ParallelMatching extends ast.TreeDSL
           emptyPatterns(pivot.elemPatterns.length + 1)
       }
 
-      // context (to be used in IF), success and failure Rep 
       final def tree(): Tree = {
         assert(scrut.tpe &lt;:&lt; head.tpe, &quot;fatal: %s is not &lt;:&lt; %s&quot;.format(scrut, head.tpe))
         
@@ -480,31 +489,34 @@ trait ParallelMatching extends ast.TreeDSL
     }
 
     // @todo: equals test for same constant
-    class MixEquals(val pmatch: PatternMatch, val rest: Rep) extends RuleApplication {
-      private lazy val label =
-        owner.newLabel(scrut.pos, newName(scrut.pos, &quot;failCont%&quot;)) setInfo MethodType(Nil, fail.tpe)
+    class MixEquals(val pmatch: PatternMatch, val rest: Rep) extends RuleApplicationFormal {
+      private def mkNewRep(rows: List[Row]) =
+        make(scrut.sym :: rest.tvars, rows).toTree
+        
+      private lazy val labelBody =
+        mkNewRep(List.map2(rest.rows.tail, pmatch.tail)(_ insert _))
+        
+      private lazy val rhs =
+        decodedEqualsType(head.tpe) match {
+          case SingleType(pre, sym) =&gt; REF(pre, sym)
+          case PseudoType(o)        =&gt; o.duplicate
+        }      
+
+      lazy val label =
+        owner.newLabel(scrut.pos, newName(scrut.pos, &quot;failCont%&quot;)) setInfo MethodType(Nil, labelBody.tpe)
       
-      private lazy val succ = {
-        val xs = List(
+      lazy val cond =
+        handleOuter(scrut.id MEMBER_== rhs)
+
+      lazy val success =
+        mkNewRep(List(
           rest.rows.head.insert2(List(NoPattern), head.boundVariables, scrut.sym),
           Row(emptyPatterns(1 + rest.tvars.length), NoBinding, NoGuard, shortCut(label))
-        )
-        make(scrut.sym :: rest.tvars, xs).toTree
-      }
-      private lazy val fail = {
-        val xs = List.map2(rest.rows.tail, pmatch.tail)(_ insert _)
-        make(scrut.sym :: rest.tvars, xs).toTree
-      }
+        ))
+ 
+      lazy val failure = LabelDef(label, Nil, labelBody)
 
-      final def tree() = {
-        val value = decodedEqualsType(head.tpe) match {
-          case SingleType(pre, sym) =&gt; REF(pre, sym)
-          case PseudoType(o)        =&gt; o.duplicate
-        }
-        val cond = scrut.id MEMBER_== value
-        
-        IF (handleOuter(cond)) THEN succ ELSE LabelDef(label, Nil, fail)
-      }
+      final def tree() = codegen
       override def toString() = &quot;MixEquals(%s == %s)&quot;.format(scrut, head)
     }
 
@@ -591,7 +603,7 @@ trait ParallelMatching extends ast.TreeDSL
       }
 
       /** returns casted symbol, success matrix and optionally fail matrix for type test on the top of this column */
-      final def getTransition(): Branch[Scrutinee] = {
+      final def getTransition() = {
         val casted = scrut castedTo pmatch.headType
         
         val isAnyMoreSpecific = moreSpecific exists (x =&gt; !x.isEmpty)
@@ -605,14 +617,11 @@ trait ParallelMatching extends ast.TreeDSL
         val newRows =
           for ((j, ps) &lt;- subtests) yield 
             (rest rows j).insert2(ps, pmatch(j).boundVariables, casted.sym)
+
+        val success = make(subtestVars ::: casted.accessorVars ::: rest.tvars, newRows)
+        val failure = mkFail(remaining map tupled((p1, p2) =&gt; rest rows p1 insert p2))
           
-        Branch(
-          casted,
-          // succeeding =&gt; transition to translate(subsumed) (taking into account more specific)
-          make(subtestVars ::: casted.accessorVars ::: rest.tvars, newRows),
-          // fails      =&gt; transition to translate(remaining)
-          mkFailOpt(remaining map tupled((p1, p2) =&gt; rest rows p1 insert p2))
-        )
+        (casted, success, failure)
       }
       
       // temporary checks so we're less crashy while we determine what to implement.
@@ -626,11 +635,10 @@ trait ParallelMatching extends ast.TreeDSL
       }
 
       final def tree(): Tree = {
-        val Branch(casted, srep, frep) = this.getTransition
+        val (casted, srep, fail) = this.getTransition
         val castedTpe = checkErroneous(casted)
         val cond = condition(castedTpe, scrut)
         val succ = srep.toTree
-        val fail = frep map (_.toTree) getOrElse (failTree)
 
         // dig out case field accessors that were buried in (***)
         val cfa         = if (pmatch.isCaseHead) casted.accessors else Nil
@@ -687,6 +695,7 @@ trait ParallelMatching extends ast.TreeDSL
       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]) {
       require(rows.size == targets.size)
       
@@ -694,6 +703,8 @@ trait ParallelMatching extends ast.TreeDSL
         &quot;ExpandedMatrix(%d)&quot;.format(rows.size) + pp(rows zip targets, true)
     }
     
+    case class Branch[T](action: T, succ: Rep, fail: Option[Rep])
+    
     abstract class State {
       def body: Tree
       def freeVars: List[Symbol]
@@ -765,12 +776,6 @@ trait ParallelMatching extends ast.TreeDSL
       
       override def toString() = pp(&quot;Final%d%s&quot;.format(bx, pp(freeVars)) -&gt; body)
     }
-    case class Branch[T](action: T, succ: Rep, fail: Option[Rep])
-    case class UnapplyCall(ua: Tree, vdefs: List[Tree]) {
-      def matchCondition: Tree =
-        if (ua.symbol.tpe.isBoolean) ID(ua.symbol)
-        else ua.symbol IS_DEFINED
-    }
 
     case class Rep(val tvars: List[Symbol], val rows: List[Row]) {      
       lazy val Row(pats, subst, guard, index) = rows.head
@@ -877,12 +882,13 @@ trait ParallelMatching extends ast.TreeDSL
 
     /** adds a test comparing the dynamic outer to the static outer */
     final def addOuterCondition(cond: Tree, tpe2test: Type, scrut: Tree) = {
-      val theRef = handleOuter(tpe2test match {
-        case TypeRef(NoPrefix, _, _)          =&gt; abort(&quot;assertion failed: NoPrefix&quot;)
-        case TypeRef(ThisType(clazz), _, _)   =&gt; THIS(clazz)
-        case TypeRef(prefix, _, _)            =&gt; REF(prefix.prefix, prefix.termSymbol)
+      val TypeRef(prefix, _, _) = tpe2test
+      val theRef = handleOuter(prefix match {
+        case NoPrefix         =&gt; abort(&quot;assertion failed: NoPrefix&quot;)
+        case ThisType(clazz)  =&gt; THIS(clazz)
+        case pre              =&gt; REF(pre.prefix, pre.termSymbol)
       })
-    
+
       outerAccessor(tpe2test.typeSymbol) match {
         case NoSymbol =&gt; ifDebug(cunit.warning(scrut.pos, &quot;no outer acc for &quot; + tpe2test.typeSymbol)) ; cond
         case outerAcc =&gt; cond AND (((scrut AS_ANY tpe2test) DOT outerAcc)() ANY_EQ theRef)</diff>
      <filename>src/compiler/scala/tools/nsc/matching/ParallelMatching.scala</filename>
    </modified>
    <modified>
      <diff>@@ -408,6 +408,13 @@ trait Patterns extends ast.TreeDSL {
   sealed trait UnapplyPattern extends Pattern {
     lazy val UnApply(unfn, args) = tree
     override def subpatternsForVars: List[Pattern] = toPats(args)
+    
+    private def isSameFunction(f1: Tree, f2: Tree) =
+      (f1.symbol == f2.symbol) &amp;&amp; (f1 equalsStructure f2)
+      
+    // XXX args
+    def isSameUnapply(other: UnapplyPattern) =
+      isSameFunction(unfn, other.unfn)
   }
 
   sealed trait ApplyPattern extends Pattern {</diff>
      <filename>src/compiler/scala/tools/nsc/matching/Patterns.scala</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>90e106a4a8bafccc910f52406cf228f4026bbb5b</id>
    </parent>
  </parents>
  <author>
    <name>extempore</name>
    <email>extempore@5e8d7ff9-d8ef-0310-90f0-a4852d11357a</email>
  </author>
  <url>http://github.com/paulp/scala/commit/2ae11504f698aff5c980fc4bd192ae639c405f83</url>
  <id>2ae11504f698aff5c980fc4bd192ae639c405f83</id>
  <committed-date>2009-10-09T11:19:37-07:00</committed-date>
  <authored-date>2009-10-09T11:19:37-07:00</authored-date>
  <message>Amazing how much code becomes unnecessary when you use
immutable data wherever you can.  Continuing to break
down the last few environments inside the pattern matcher
which bugs find hospitable.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@19018 5e8d7ff9-d8ef-0310-90f0-a4852d11357a</message>
  <tree>465d1ade2be27ca0664c79591baf8f574cb72ecf</tree>
  <committer>
    <name>extempore</name>
    <email>extempore@5e8d7ff9-d8ef-0310-90f0-a4852d11357a</email>
  </committer>
</commit>
