@@ -474,112 +474,83 @@ object PatternMatcher {
474
474
refCounter.count
475
475
}
476
476
477
- /** Merge identical tests from consecutive cases .
477
+ /** Merge identical consecutive tests .
478
478
*
479
479
* When we have the following shape:
480
480
*
481
- * caseM: {
482
- * if (testA) plan1 else plan2
483
- * }
484
- * caseN: {
485
- * if (testA) plan3 else plan4
486
- * }
487
- * nextPlan
481
+ * if (testA) plan1
482
+ * if (testA) plan2
483
+ * nextPlan?
488
484
*
489
485
* transform it to
490
486
*
491
- * caseN: {
492
- * if (testA) {
493
- * case M: {
494
- * plan1
495
- * }
496
- * plan3
497
- * } else {
498
- * case M2: {
499
- * plan2[caseM2/caseM]
500
- * }
501
- * plan4
502
- * }
487
+ * if (testA) {
488
+ * plan1
489
+ * plan2
503
490
* }
504
- * nextPlan
491
+ * nextPlan?
505
492
*
506
- * where plan2[caseM2/caseM] means substituting caseM2 for caseM in plan2.
493
+ * Similarly, when we have equivalent let bindings:
507
494
*
508
- * We use some tricks to identify a let pointing to an unapply and the
509
- * NonEmptyTest that follows it as a single `UnappTest` test.
495
+ * let x1 = rhs1 in plan1
496
+ * let x2 = rhs2 in plan2
497
+ * nextPlan?
498
+ *
499
+ * and rhs1 and rhs2 are equivalent, transform it to
500
+ *
501
+ * let x1 = rhs1 in {
502
+ * plan1
503
+ * plan2[x1/x2]
504
+ * }
505
+ *
506
+ * where plan2[x1/x2] means substituting x1 for x2 in plan2.
510
507
*/
511
- /*
512
508
def mergeTests (plan : Plan ): Plan = {
513
- def isUnapply(sym: Symbol) = sym.name == nme.unapply || sym.name == nme.unapplySeq
514
-
515
- /** A locally used test value that represents combos of
516
- *
517
- * let x = X.unapply(...) in if !x.isEmpty then ... else ...
518
- */
519
- case object UnappTest extends Test
520
-
521
- /** If `plan` is the NonEmptyTest part of an unapply, the corresponding UnappTest
522
- * otherwise the original plan
523
- */
524
- def normalize(plan: TestPlan): TestPlan = plan.scrutinee match {
525
- case id: Ident
526
- if plan.test == NonEmptyTest &&
527
- isPatmatGenerated(id.symbol) &&
528
- isUnapply(initializer(id.symbol).symbol) =>
529
- TestPlan(UnappTest, initializer(id.symbol), plan.pos, plan.onSuccess, plan.onFailure)
530
- case _ =>
531
- plan
532
- }
533
-
534
- /** Extractor for Let/NonEmptyTest combos that represent unapplies */
535
- object UnappTestPlan {
536
- def unapply(plan: Plan): Option[TestPlan] = plan match {
537
- case LetPlan(sym, body: TestPlan) =>
538
- val RHS = initializer(sym)
539
- normalize(body) match {
540
- case normPlan @ TestPlan(UnappTest, RHS, _, _, _) => Some(normPlan)
541
- case _ => None
542
- }
543
- case _ => None
544
- }
545
- }
546
-
547
- class SubstituteLabel(from: TermSymbol, to: TermSymbol) extends PlanTransform {
548
- override def apply(plan: ReturnPlan): Plan = {
549
- if (plan.label == from)
550
- plan.label = to
551
- plan
509
+ class SubstituteIdent (from : TermSymbol , to : TermSymbol ) extends PlanTransform {
510
+ override val treeMap = new TreeMap {
511
+ override def transform (tree : Tree )(implicit ctx : Context ) = tree match {
512
+ case tree : Ident if tree.symbol == from => ref(to)
513
+ case _ => super .transform(tree)
514
+ }
552
515
}
553
516
}
554
517
555
518
class MergeTests extends PlanTransform {
556
- override def apply(plan: LabeledPlan): Plan = {
557
- plan.next = apply(plan.next)
558
- plan match {
559
- case LabeledPlan(label1, testPlan1: TestPlan, LabeledPlan(label2, testPlan2: TestPlan, nextNext)) =>
560
- val normTestPlan1 = normalize(testPlan1)
561
- val normTestPlan2 = normalize(testPlan2)
562
- if (normTestPlan1 == normTestPlan2) {
563
- val onFailure = labeledAbstract2(testPlan2.onFailure) { label12 =>
564
- new SubstituteLabel(label1, label12)(testPlan1.onFailure)
565
- }
566
- val onSuccess = LabeledPlan(label1, testPlan1.onSuccess, testPlan2.onSuccess)
567
- testPlan1.onSuccess = apply(onSuccess)
568
- testPlan1.onFailure = apply(onFailure)
569
- LabeledPlan(label2, testPlan1, nextNext)
570
- } else {
571
- plan.expr = apply(plan.expr)
572
- plan
519
+ override def apply (plan : SeqPlan ): Plan = {
520
+ def tryMerge (plan1 : Plan , plan2 : Plan ): Option [Plan ] = {
521
+ (plan1, plan2) match {
522
+ case (plan1 : TestPlan , plan2 : TestPlan ) if plan1 == plan2 =>
523
+ plan1.onSuccess = SeqPlan (plan1.onSuccess, plan2.onSuccess)
524
+ Some (plan1)
525
+
526
+ case (plan1 : LetPlan , plan2 : LetPlan ) if isPatmatGenerated(plan2.sym) && initializer(plan1.sym) === initializer(plan2.sym) =>
527
+ val newPlan2Body = new SubstituteIdent (plan2.sym, plan1.sym)(plan2.body)
528
+ plan1.body = SeqPlan (plan1.body, newPlan2Body)
529
+ Some (plan1)
530
+
531
+ case _ =>
532
+ None
533
+ }
534
+ }
535
+
536
+ plan.head = apply(plan.head)
537
+ plan.tail = apply(plan.tail)
538
+ plan.tail match {
539
+ case SeqPlan (tailHead, tailTail) =>
540
+ tryMerge(plan.head, tailHead) match {
541
+ case Some (merged) => SeqPlan (apply(merged), tailTail)
542
+ case none => plan
543
+ }
544
+ case tail =>
545
+ tryMerge(plan.head, tail) match {
546
+ case Some (merged) => apply(merged)
547
+ case none => plan
573
548
}
574
- case _ =>
575
- plan.expr = apply(plan.expr)
576
- plan
577
549
}
578
550
}
579
551
}
580
552
new MergeTests ()(plan)
581
553
}
582
- */
583
554
584
555
/** Eliminate tests that are redundant (known to be true or false).
585
556
* Two parts:
@@ -1077,7 +1048,7 @@ object PatternMatcher {
1077
1048
}
1078
1049
1079
1050
val optimizations : List [(String , Plan => Plan )] = List (
1080
- // "mergeTests" -> mergeTests
1051
+ " mergeTests" -> mergeTests
1081
1052
/*
1082
1053
"hoistLabels" -> hoistLabels,
1083
1054
"elimRedundantTests" -> elimRedundantTests,
0 commit comments