1
1
package dotty .tools .dotc
2
2
package transform
3
3
4
+ import scala .annotation .tailrec
4
5
import core ._
5
6
import MegaPhase ._
6
7
import collection .mutable
@@ -757,47 +758,49 @@ object PatternMatcher {
757
758
}
758
759
}
759
760
761
+ @ tailrec
762
+ private def canFallThrough (plan : Plan ): Boolean = plan match {
763
+ case _:ReturnPlan | _:ResultPlan => false
764
+ case _:TestPlan | _:LabeledPlan => true
765
+ case LetPlan (_, body) => canFallThrough(body)
766
+ case SeqPlan (_, tail) => canFallThrough(tail)
767
+ }
768
+
760
769
/** Collect longest list of plans that represent possible cases of
761
770
* a switch, including a last default case, by starting with this
762
771
* plan and following onSuccess plans.
763
772
*/
764
- /*
765
- private def collectSwitchCases(plan: TestPlan): List[Plan] = {
773
+ private def collectSwitchCases (scrutinee : Tree , plan : SeqPlan ): List [Plan ] = {
766
774
def isSwitchableType (tpe : Type ): Boolean =
767
775
(tpe isRef defn.IntClass ) ||
768
776
(tpe isRef defn.ByteClass ) ||
769
777
(tpe isRef defn.ShortClass ) ||
770
778
(tpe isRef defn.CharClass )
771
779
772
- val scrutinee = plan.scrutinee
773
-
774
780
def isIntConst (tree : Tree ) = tree match {
775
781
case Literal (const) => const.isIntRange
776
782
case _ => false
777
783
}
778
784
779
785
def recur (plan : Plan ): List [Plan ] = plan match {
780
- case TestPlan(EqualTest(tree), scrut, _, _, onf )
781
- if scrut === scrutinee && isIntConst(tree) =>
782
- plan :: recur(onf )
786
+ case SeqPlan (testPlan @ TestPlan (EqualTest (tree), scrut, _, ons), tail )
787
+ if scrut === scrutinee && isIntConst(tree) && ! canFallThrough(ons) =>
788
+ testPlan :: recur(tail )
783
789
case _ =>
784
790
plan :: Nil
785
791
}
786
792
787
793
if (isSwitchableType(scrutinee.tpe.widen)) recur(plan)
788
794
else Nil
789
795
}
790
- */
791
796
792
797
/** Emit cases of a switch */
793
- /*
794
798
private def emitSwitchCases (cases : List [Plan ]): List [CaseDef ] = (cases : @ unchecked) match {
795
799
case (default : Plan ) :: Nil =>
796
800
CaseDef (Underscore (defn.IntType ), EmptyTree , emit(default)) :: Nil
797
- case TestPlan(EqualTest(tree), _, _, ons, _ ) :: cases1 =>
801
+ case TestPlan (EqualTest (tree), _, _, ons) :: cases1 =>
798
802
CaseDef (tree, EmptyTree , emit(ons)) :: emitSwitchCases(cases1)
799
803
}
800
- */
801
804
802
805
/** If selfCheck is `true`, used to check whether a tree gets generated twice */
803
806
private val emitted = mutable.Set [Int ]()
@@ -810,55 +813,61 @@ object PatternMatcher {
810
813
}
811
814
plan match {
812
815
case plan : TestPlan =>
813
- /* val switchCases = collectSwitchCases(plan)
814
- if (switchCases.lengthCompare(MinSwitchCases) >= 0) // at least 3 cases + default
815
- Match(plan.scrutinee, emitSwitchCases(switchCases))
816
- else*/ {
817
- /** Merge nested `if`s that have the same `else` branch into a single `if`.
818
- * This optimization targets calls to label defs for case failure jumps to next case.
819
- *
820
- * Plan for
821
- * ```
822
- * val x1: Int = ...
823
- * val x2: Int = ...
824
- * if (x1 == y1) {
825
- * if (x2 == y2) someCode
826
- * else label$1()
827
- * } else label$1()
828
- * ```
829
- * is emitted as
830
- * ```
831
- * val x1: Int = ...
832
- * val x2: Int = ...
833
- * if (x1 == y1 && x2 == y2) someCode
834
- * else label$1()
835
- * ```
836
- */
837
- def emitWithMashedConditions (plans : List [TestPlan ]): Tree = {
838
- val plan = plans.head
839
- plan.onSuccess match {
840
- case plan2 : TestPlan =>
841
- emitWithMashedConditions(plan2 :: plans)
842
- case _ =>
843
- def emitCondWithPos (plan : TestPlan ) = emitCondition(plan).withPos(plan.pos)
844
- val conditions =
845
- plans.foldRight[Tree ](EmptyTree ) { (otherPlan, acc) =>
846
- if (acc.isEmpty) emitCondWithPos(otherPlan)
847
- else acc.select(nme.ZAND ).appliedTo(emitCondWithPos(otherPlan))
848
- }
849
- If (conditions, emit(plan.onSuccess), unitLiteral)
850
- }
816
+ /** Merge nested `if`s that have the same `else` branch into a single `if`.
817
+ * This optimization targets calls to label defs for case failure jumps to next case.
818
+ *
819
+ * Plan for
820
+ * ```
821
+ * val x1: Int = ...
822
+ * val x2: Int = ...
823
+ * if (x1 == y1) {
824
+ * if (x2 == y2) someCode
825
+ * else label$1()
826
+ * } else label$1()
827
+ * ```
828
+ * is emitted as
829
+ * ```
830
+ * val x1: Int = ...
831
+ * val x2: Int = ...
832
+ * if (x1 == y1 && x2 == y2) someCode
833
+ * else label$1()
834
+ * ```
835
+ */
836
+ def emitWithMashedConditions (plans : List [TestPlan ]): Tree = {
837
+ val plan = plans.head
838
+ plan.onSuccess match {
839
+ case plan2 : TestPlan =>
840
+ emitWithMashedConditions(plan2 :: plans)
841
+ case _ =>
842
+ def emitCondWithPos (plan : TestPlan ) = emitCondition(plan).withPos(plan.pos)
843
+ val conditions =
844
+ plans.foldRight[Tree ](EmptyTree ) { (otherPlan, acc) =>
845
+ if (acc.isEmpty) emitCondWithPos(otherPlan)
846
+ else acc.select(nme.ZAND ).appliedTo(emitCondWithPos(otherPlan))
847
+ }
848
+ If (conditions, emit(plan.onSuccess), unitLiteral)
851
849
}
852
- emitWithMashedConditions(plan :: Nil )
853
850
}
851
+ emitWithMashedConditions(plan :: Nil )
854
852
case LetPlan (sym, body) =>
855
853
seq(ValDef (sym, initializer(sym).ensureConforms(sym.info)) :: Nil , emit(body))
856
854
case LabeledPlan (label, expr) =>
857
855
Labeled (label, emit(expr))
858
856
case ReturnPlan (label) =>
859
857
Return (Literal (Constant (())), ref(label))
860
- case SeqPlan (head, tail) =>
861
- seq(emit(head) :: Nil , emit(tail))
858
+ case plan : SeqPlan =>
859
+ def default = seq(emit(plan.head) :: Nil , emit(plan.tail))
860
+ plan.head match {
861
+ case testPlan : TestPlan =>
862
+ val scrutinee = testPlan.scrutinee
863
+ val switchCases = collectSwitchCases(scrutinee, plan)
864
+ if (switchCases.lengthCompare(MinSwitchCases ) >= 0 ) // at least 3 cases + default
865
+ Match (scrutinee, emitSwitchCases(switchCases))
866
+ else
867
+ default
868
+ case _ =>
869
+ default
870
+ }
862
871
case ResultPlan (tree) =>
863
872
Return (tree, ref(resultLabel))
864
873
}
@@ -954,7 +963,7 @@ object PatternMatcher {
954
963
// System.err.println(s"After $title: ${show(plan)}")
955
964
}
956
965
val result = emit(plan)
957
- // checkSwitch(tree, result)
966
+ checkSwitch(tree, result)
958
967
Labeled (resultLabel, result)
959
968
}
960
969
}
0 commit comments