@@ -394,6 +394,25 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
394
394
override def toString = " B" + ((body, matchPt))
395
395
}
396
396
397
+ /**
398
+ * In scalac for such block
399
+ * x match {
400
+ * case d => <body>
401
+ * }
402
+ *
403
+ * d inside <body> was to be substitued by x.
404
+ *
405
+ * In dotty, SubstOnlyTreeMakers instead generate normal ValDef,
406
+ * and does not create a new substitution.
407
+ *
408
+ * This was done for several reasons:
409
+ * 1) it is a lot easyer to Y-check,
410
+ * as d type could be used in <body>.
411
+ * 2) it would simplify debugging of the generated code as
412
+ * this works also for nested patterns, and previously they used unreadable names
413
+ * 3) It showed better(~30%), performance,
414
+ * Rebuilding tree and propagating types was taking substantial time.
415
+ */
397
416
case class SubstOnlyTreeMaker (prevBinder : Symbol , nextBinder : Symbol ) extends TreeMaker {
398
417
val pos = Positions .NoPosition
399
418
@@ -851,29 +870,25 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
851
870
def removeSubstOnly (makers : List [TreeMaker ]) = makers filterNot (_.isInstanceOf [SubstOnlyTreeMaker ])
852
871
853
872
// a foldLeft to accumulate the localSubstitution left-to-right
854
- // it drops SubstOnly tree makers, since their only goal in life is to propagate substitutions to the next tree maker, which is fullfilled by propagateSubstitution
873
+ // unlike in scalace it does not drop SubstOnly tree makers,
874
+ // as there could types having them as prefix
855
875
def propagateSubstitution (treeMakers : List [TreeMaker ], initial : Substitution ): List [TreeMaker ] = {
856
876
var accumSubst : Substitution = initial
857
877
treeMakers foreach { maker =>
858
878
maker incorporateOuterSubstitution accumSubst
859
879
accumSubst = maker.substitution
860
880
}
861
- removeSubstOnly( treeMakers)
881
+ treeMakers
862
882
}
863
883
864
884
// calls propagateSubstitution on the treemakers
865
885
def combineCases (scrut : Tree , scrutSym : Symbol , casesRaw : List [List [TreeMaker ]], pt : Type , owner : Symbol , matchFailGenOverride : Option [Symbol => Tree ]): Tree = {
866
- // drops SubstOnlyTreeMakers, since their effect is now contained in the TreeMakers that follow them
867
- val casesNoSubstOnly = casesRaw map (propagateSubstitution(_, EmptySubstitution ))
868
- combineCasesNoSubstOnly(scrut, scrutSym, casesNoSubstOnly, pt, owner, matchFailGenOverride)
869
- }
886
+ // unlike in scalac SubstOnlyTreeMakers are maintained.
887
+ val casesSubstitutionPropagated = casesRaw map (propagateSubstitution(_, EmptySubstitution ))
870
888
871
- // pt is the fully defined type of the cases (either pt or the lub of the types of the cases)
872
- def combineCasesNoSubstOnly (scrut : Tree , scrutSym : Symbol , casesNoSubstOnly : List [List [TreeMaker ]], pt : Type , owner : Symbol , matchFailGenOverride : Option [Symbol => Tree ]): Tree =
873
- /* fixerUpper(owner, scrut.pos)*/ {
874
- def matchFailGen = matchFailGenOverride orElse Some ((arg : Symbol ) => Throw (New (defn.MatchErrorType , List (ref(arg)))))
889
+ def matchFailGen = matchFailGenOverride orElse Some ((arg : Symbol ) => Throw (New (defn.MatchErrorType , List (ref(arg)))))
875
890
876
- ctx.debuglog(" combining cases: " + (casesNoSubstOnly .map(_.mkString(" >> " )).mkString(" {" , " \n " , " }" )))
891
+ ctx.debuglog(" combining cases: " + (casesSubstitutionPropagated .map(_.mkString(" >> " )).mkString(" {" , " \n " , " }" )))
877
892
878
893
val (suppression, requireSwitch): (Suppression , Boolean ) =
879
894
/* if (settings.XnoPatmatAnalysis)*/ (Suppression .NoSuppression , false )
@@ -892,26 +907,26 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
892
907
(Suppression.NoSuppression, false)
893
908
}*/
894
909
895
- emitSwitch(scrut, scrutSym, casesNoSubstOnly , pt, matchFailGenOverride, suppression.exhaustive).getOrElse{
910
+ emitSwitch(scrut, scrutSym, casesSubstitutionPropagated , pt, matchFailGenOverride, suppression.exhaustive).getOrElse{
896
911
if (requireSwitch) ctx.warning(" could not emit switch for @switch annotated match" , scrut.pos)
897
912
898
- if (casesNoSubstOnly nonEmpty) {
913
+ if (casesSubstitutionPropagated nonEmpty) {
899
914
// before optimizing, check casesNoSubstOnly for presence of a default case,
900
915
// since DCE will eliminate trivial cases like `case _ =>`, even if they're the last one
901
916
// exhaustivity and reachability must be checked before optimization as well
902
917
// TODO: improve notion of trivial/irrefutable -- a trivial type test before the body still makes for a default case
903
918
// ("trivial" depends on whether we're emitting a straight match or an exception, or more generally, any supertype of scrutSym.tpe is a no-op)
904
919
// irrefutability checking should use the approximation framework also used for CSE, unreachability and exhaustivity checking
905
920
val synthCatchAll : Option [Symbol => Tree ] =
906
- if (casesNoSubstOnly .nonEmpty && {
907
- val nonTrivLast = casesNoSubstOnly .last
921
+ if (casesSubstitutionPropagated .nonEmpty && {
922
+ val nonTrivLast = casesSubstitutionPropagated .last
908
923
nonTrivLast.nonEmpty && nonTrivLast.head.isInstanceOf [BodyTreeMaker ]
909
924
}) None
910
925
else matchFailGen
911
926
912
- analyzeCases(scrutSym, casesNoSubstOnly , pt, suppression)
927
+ analyzeCases(scrutSym, casesSubstitutionPropagated , pt, suppression)
913
928
914
- val (cases, toHoist) = optimizeCases(scrutSym, casesNoSubstOnly , pt)
929
+ val (cases, toHoist) = optimizeCases(scrutSym, casesSubstitutionPropagated , pt)
915
930
916
931
val matchRes = codegen.matcher(scrut, scrutSym, pt)(cases.map(x => combineExtractors(x) _), synthCatchAll)
917
932
0 commit comments