Skip to content

Commit 6ff4671

Browse files
committed
wip new plans
1 parent b3e2a91 commit 6ff4671

File tree

1 file changed

+74
-58
lines changed

1 file changed

+74
-58
lines changed

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 74 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -96,18 +96,18 @@ object PatternMatcher {
9696
LetPlan(vble, body(vble))
9797
}
9898

99-
/** The plan `let l = labelled in body(l)` where `l` is a fresh label */
100-
private def labeledAbstract(next: Plan)(expr: (=> Plan) => Plan): Plan = {
99+
/** The plan `l: { expr(l) }` where `l` is a fresh label */
100+
private def labeledAbstract(expr: (=> Plan) => Plan): Plan = {
101101
val label = ctx.newSymbol(ctx.owner, PatMatCaseName.fresh(), Synthetic | Label,
102102
defn.UnitType)
103-
LabeledPlan(label, expr(ReturnPlan(label)), next)
103+
LabeledPlan(label, expr(ReturnPlan(label)))
104104
}
105105

106-
/** The plan `let l = labelled in body(l)` where `l` is a fresh label */
107-
private def labeledAbstract2(next: Plan)(expr: TermSymbol => Plan): Plan = {
106+
/** The plan `l: { expr(l) }` where `l` is a fresh label */
107+
private def labeledAbstract2(expr: TermSymbol => Plan): Plan = {
108108
val label = ctx.newSymbol(ctx.owner, PatMatCaseName.fresh(), Synthetic | Label,
109109
defn.UnitType)
110-
LabeledPlan(label, expr(label), next)
110+
LabeledPlan(label, expr(label))
111111
}
112112

113113
/** Test whether a type refers to a pattern-generated variable */
@@ -138,7 +138,7 @@ object PatternMatcher {
138138
sealed abstract class Plan { val id = nxId; nxId += 1 }
139139

140140
case class TestPlan(test: Test, var scrutinee: Tree, pos: Position,
141-
var onSuccess: Plan, var onFailure: Plan) extends Plan {
141+
var onSuccess: Plan) extends Plan {
142142
override def equals(that: Any) = that match {
143143
case that: TestPlan => this.scrutinee === that.scrutinee && this.test == that.test
144144
case _ => false
@@ -147,13 +147,14 @@ object PatternMatcher {
147147
}
148148

149149
case class LetPlan(sym: TermSymbol, var body: Plan) extends Plan
150-
case class LabeledPlan(sym: TermSymbol, var expr: Plan, var next: Plan) extends Plan
150+
case class LabeledPlan(sym: TermSymbol, var expr: Plan) extends Plan
151151
case class ReturnPlan(var label: TermSymbol) extends Plan
152+
case class SeqPlan(var head: Plan, var tail: Plan) extends Plan
152153
case class ResultPlan(var tree: Tree) extends Plan
153154

154155
object TestPlan {
155-
def apply(test: Test, sym: Symbol, pos: Position, ons: Plan, onf: Plan): TestPlan =
156-
TestPlan(test, ref(sym), pos, ons, onf)
156+
def apply(test: Test, sym: Symbol, pos: Position, ons: Plan): TestPlan =
157+
TestPlan(test, ref(sym), pos, ons)
157158
}
158159

159160
/** The different kinds of tests */
@@ -218,7 +219,7 @@ object PatternMatcher {
218219
}
219220

220221
/** Plan for matching `scrutinee` symbol against `tree` pattern */
221-
private def patternPlan(scrutinee: Symbol, tree: Tree, onSuccess: Plan, onFailure: Plan): Plan = {
222+
private def patternPlan(scrutinee: Symbol, tree: Tree, onSuccess: Plan): Plan = {
222223

223224
/** Plan for matching `selectors` against argument patterns `args` */
224225
def matchArgsPlan(selectors: List[Tree], args: List[Tree], onSuccess: Plan): Plan = {
@@ -247,7 +248,7 @@ object PatternMatcher {
247248
args match {
248249
case arg :: args1 =>
249250
val sym :: syms1 = syms
250-
patternPlan(sym, arg, matchArgsPatternPlan(args1, syms1), onFailure)
251+
patternPlan(sym, arg, matchArgsPatternPlan(args1, syms1))
251252
case Nil =>
252253
assert(syms.isEmpty)
253254
onSuccess
@@ -262,7 +263,7 @@ object PatternMatcher {
262263
val selectors = args.indices.toList.map(idx =>
263264
ref(seqSym).select(nme.apply).appliedTo(Literal(Constant(idx))))
264265
TestPlan(LengthTest(args.length, exact), seqSym, seqSym.pos,
265-
matchArgsPlan(selectors, args, onSuccess), onFailure)
266+
matchArgsPlan(selectors, args, onSuccess))
266267
}
267268

268269
/** Plan for matching the sequence in `getResult` against sequence elements
@@ -272,13 +273,13 @@ object PatternMatcher {
272273
case Some(VarArgPattern(arg)) =>
273274
val matchRemaining =
274275
if (args.length == 1)
275-
patternPlan(getResult, arg, onSuccess, onFailure)
276+
patternPlan(getResult, arg, onSuccess)
276277
else {
277278
val dropped = ref(getResult)
278279
.select(defn.Seq_drop.matchingMember(getResult.info))
279280
.appliedTo(Literal(Constant(args.length - 1)))
280281
letAbstract(dropped) { droppedResult =>
281-
patternPlan(droppedResult, arg, onSuccess, onFailure)
282+
patternPlan(droppedResult, arg, onSuccess)
282283
}
283284
}
284285
matchElemsPlan(getResult, args.init, exact = false, matchRemaining)
@@ -297,7 +298,7 @@ object PatternMatcher {
297298
if (isSyntheticScala2Unapply(unapp.symbol) && caseAccessors.length == args.length)
298299
matchArgsPlan(caseAccessors.map(ref(scrutinee).select(_)), args, onSuccess)
299300
else if (unapp.tpe.widenSingleton.isRef(defn.BooleanClass))
300-
TestPlan(GuardTest, unapp, unapp.pos, onSuccess, onFailure)
301+
TestPlan(GuardTest, unapp, unapp.pos, onSuccess)
301302
else {
302303
letAbstract(unapp) { unappResult =>
303304
val isUnapplySeq = unapp.symbol.name == nme.unapplySeq
@@ -320,7 +321,7 @@ object PatternMatcher {
320321
matchArgsPlan(selectors, args, onSuccess)
321322
}
322323
}
323-
TestPlan(NonEmptyTest, unappResult, unapp.pos, argsPlan, onFailure)
324+
TestPlan(NonEmptyTest, unappResult, unapp.pos, argsPlan)
324325
}
325326
}
326327
}
@@ -332,54 +333,58 @@ object PatternMatcher {
332333
TestPlan(TypeTest(tpt), scrutinee, tree.pos,
333334
letAbstract(ref(scrutinee).asInstance(tpt.tpe)) { casted =>
334335
nonNull += casted
335-
patternPlan(casted, pat, onSuccess, onFailure)
336-
},
337-
onFailure)
336+
patternPlan(casted, pat, onSuccess)
337+
})
338338
case UnApply(extractor, implicits, args) =>
339339
val mt @ MethodType(_) = extractor.tpe.widen
340340
var unapp = extractor.appliedTo(ref(scrutinee).ensureConforms(mt.paramInfos.head))
341341
if (implicits.nonEmpty) unapp = unapp.appliedToArgs(implicits)
342342
val unappPlan = unapplyPlan(unapp, args)
343343
if (scrutinee.info.isNotNull || nonNull(scrutinee)) unappPlan
344-
else TestPlan(NonNullTest, scrutinee, tree.pos, unappPlan, onFailure)
344+
else TestPlan(NonNullTest, scrutinee, tree.pos, unappPlan)
345345
case Bind(name, body) =>
346-
if (name == nme.WILDCARD) patternPlan(scrutinee, body, onSuccess, onFailure)
346+
if (name == nme.WILDCARD) patternPlan(scrutinee, body, onSuccess)
347347
else {
348348
// The type of `name` may refer to val in `body`, therefore should come after `body`
349349
val bound = tree.symbol.asTerm
350350
initializer(bound) = ref(scrutinee)
351-
patternPlan(scrutinee, body, LetPlan(bound, onSuccess), onFailure)
351+
patternPlan(scrutinee, body, LetPlan(bound, onSuccess))
352352
}
353353
case Alternative(alts) =>
354-
labeledAbstract(onSuccess) { ons =>
355-
(alts :\ onFailure) { (alt, onf) =>
356-
labeledAbstract(onf) { onf1 =>
357-
patternPlan(scrutinee, alt, ons, onf1)
358-
}
359-
}
354+
labeledAbstract { onf =>
355+
SeqPlan(
356+
labeledAbstract { ons =>
357+
alts.foldRight(onf) { (alt, next) =>
358+
SeqPlan(patternPlan(scrutinee, alt, ons), next)
359+
}
360+
},
361+
onSuccess
362+
)
360363
}
361364
case WildcardPattern() =>
362365
onSuccess
363366
case SeqLiteral(pats, _) =>
364367
matchElemsPlan(scrutinee, pats, exact = true, onSuccess)
365368
case _ =>
366-
TestPlan(EqualTest(tree), scrutinee, tree.pos, onSuccess, onFailure)
369+
TestPlan(EqualTest(tree), scrutinee, tree.pos, onSuccess)
367370
}
368371
}
369372

370-
private def caseDefPlan(scrutinee: Symbol, cdef: CaseDef, onFailure: Plan): Plan =
371-
labeledAbstract(onFailure) { onf =>
372-
var onSuccess: Plan = ResultPlan(cdef.body)
373-
if (!cdef.guard.isEmpty)
374-
onSuccess = TestPlan(GuardTest, cdef.guard, cdef.guard.pos, onSuccess, onf)
375-
patternPlan(scrutinee, cdef.pat, onSuccess, onf)
376-
}
373+
private def caseDefPlan(scrutinee: Symbol, cdef: CaseDef): Plan = {
374+
var onSuccess: Plan = ResultPlan(cdef.body)
375+
if (!cdef.guard.isEmpty)
376+
onSuccess = TestPlan(GuardTest, cdef.guard, cdef.guard.pos, onSuccess)
377+
patternPlan(scrutinee, cdef.pat, onSuccess)
378+
}
377379

378-
private def matchPlan(tree: Match): Plan =
380+
private def matchPlan(tree: Match): Plan = {
379381
letAbstract(tree.selector) { scrutinee =>
380382
val matchError: Plan = ResultPlan(Throw(New(defn.MatchErrorType, ref(scrutinee) :: Nil)))
381-
(tree.cases :\ matchError)(caseDefPlan(scrutinee, _, _))
383+
tree.cases.foldRight(matchError) { (cdef, next) =>
384+
SeqPlan(caseDefPlan(scrutinee, cdef), next)
385+
}
382386
}
387+
}
383388

384389
// ----- Optimizing plans ---------------
385390

@@ -392,7 +397,6 @@ object PatternMatcher {
392397
def apply(plan: TestPlan): Plan = {
393398
plan.scrutinee = apply(plan.scrutinee)
394399
plan.onSuccess = apply(plan.onSuccess)
395-
plan.onFailure = apply(plan.onFailure)
396400
plan
397401
}
398402
def apply(plan: LetPlan): Plan = {
@@ -402,15 +406,20 @@ object PatternMatcher {
402406
}
403407
def apply(plan: LabeledPlan): Plan = {
404408
plan.expr = apply(plan.expr)
405-
plan.next = apply(plan.next)
406409
plan
407410
}
408411
def apply(plan: ReturnPlan): Plan = plan
412+
def apply(plan: SeqPlan): Plan = {
413+
plan.head = apply(plan.head)
414+
plan.tail = apply(plan.tail)
415+
plan
416+
}
409417
def apply(plan: Plan): Plan = plan match {
410418
case plan: TestPlan => apply(plan)
411419
case plan: LetPlan => apply(plan)
412420
case plan: LabeledPlan => apply(plan)
413421
case plan: ReturnPlan => apply(plan)
422+
case plan: SeqPlan => apply(plan)
414423
case plan: ResultPlan => plan
415424
}
416425
}
@@ -426,7 +435,6 @@ object PatternMatcher {
426435
object refCounter extends RefCounter {
427436
override def apply(plan: LabeledPlan): Plan = {
428437
apply(plan.expr)
429-
apply(plan.next)
430438
plan
431439
}
432440
override def apply(plan: ReturnPlan): Plan = {
@@ -500,6 +508,7 @@ object PatternMatcher {
500508
* We use some tricks to identify a let pointing to an unapply and the
501509
* NonEmptyTest that follows it as a single `UnappTest` test.
502510
*/
511+
/*
503512
def mergeTests(plan: Plan): Plan = {
504513
def isUnapply(sym: Symbol) = sym.name == nme.unapply || sym.name == nme.unapplySeq
505514
@@ -570,6 +579,7 @@ object PatternMatcher {
570579
}
571580
new MergeTests()(plan)
572581
}
582+
*/
573583

574584
/** Eliminate tests that are redundant (known to be true or false).
575585
* Two parts:
@@ -894,6 +904,7 @@ object PatternMatcher {
894904
* a switch, including a last default case, by starting with this
895905
* plan and following onSuccess plans.
896906
*/
907+
/*
897908
private def collectSwitchCases(plan: TestPlan): List[Plan] = {
898909
def isSwitchableType(tpe: Type): Boolean =
899910
(tpe isRef defn.IntClass) ||
@@ -919,14 +930,17 @@ object PatternMatcher {
919930
if (isSwitchableType(scrutinee.tpe.widen)) recur(plan)
920931
else Nil
921932
}
933+
*/
922934

923935
/** Emit cases of a switch */
936+
/*
924937
private def emitSwitchCases(cases: List[Plan]): List[CaseDef] = (cases: @unchecked) match {
925938
case (default: Plan) :: Nil =>
926939
CaseDef(Underscore(defn.IntType), EmptyTree, emit(default)) :: Nil
927940
case TestPlan(EqualTest(tree), _, _, ons, _) :: cases1 =>
928941
CaseDef(tree, EmptyTree, emit(ons)) :: emitSwitchCases(cases1)
929942
}
943+
*/
930944

931945
/** If selfCheck is `true`, used to check whether a tree gets generated twice */
932946
private val emitted = mutable.Set[Int]()
@@ -939,10 +953,10 @@ object PatternMatcher {
939953
}
940954
plan match {
941955
case plan: TestPlan =>
942-
val switchCases = collectSwitchCases(plan)
956+
/*val switchCases = collectSwitchCases(plan)
943957
if (switchCases.lengthCompare(MinSwitchCases) >= 0) // at least 3 cases + default
944958
Match(plan.scrutinee, emitSwitchCases(switchCases))
945-
else {
959+
else*/ {
946960
/** Merge nested `if`s that have the same `else` branch into a single `if`.
947961
* This optimization targets calls to label defs for case failure jumps to next case.
948962
*
@@ -966,7 +980,7 @@ object PatternMatcher {
966980
def emitWithMashedConditions(plans: List[TestPlan]): Tree = {
967981
val plan = plans.head
968982
plan.onSuccess match {
969-
case plan2: TestPlan if plan.onFailure == plan2.onFailure =>
983+
case plan2: TestPlan =>
970984
emitWithMashedConditions(plan2 :: plans)
971985
case _ =>
972986
def emitCondWithPos(plan: TestPlan) = emitCondition(plan).withPos(plan.pos)
@@ -975,19 +989,19 @@ object PatternMatcher {
975989
if (acc.isEmpty) emitCondWithPos(otherPlan)
976990
else acc.select(nme.ZAND).appliedTo(emitCondWithPos(otherPlan))
977991
}
978-
If(conditions, emit(plan.onSuccess), emit(plan.onFailure))
992+
If(conditions, emit(plan.onSuccess), unitLiteral)
979993
}
980-
981994
}
982995
emitWithMashedConditions(plan :: Nil)
983996
}
984997
case LetPlan(sym, body) =>
985998
seq(ValDef(sym, initializer(sym).ensureConforms(sym.info)) :: Nil, emit(body))
986-
case LabeledPlan(label, expr, next) =>
987-
val labeledBlock = Labeled(label, emit(expr))
988-
seq(labeledBlock :: Nil, emit(next))
999+
case LabeledPlan(label, expr) =>
1000+
Labeled(label, emit(expr))
9891001
case ReturnPlan(label) =>
9901002
Return(Literal(Constant(())), ref(label))
1003+
case SeqPlan(head, tail) =>
1004+
seq(emit(head) :: Nil, emit(tail))
9911005
case ResultPlan(tree) =>
9921006
Return(tree, ref(resultLabel))
9931007
}
@@ -1009,21 +1023,23 @@ object PatternMatcher {
10091023
seen += plan.id
10101024
sb append s"\n${plan.id}: "
10111025
plan match {
1012-
case TestPlan(test, scrutinee, _, ons, onf) =>
1013-
sb.append(i"$scrutinee ? ${showTest(test)}(${ons.id}, ${onf.id})")
1026+
case TestPlan(test, scrutinee, _, ons) =>
1027+
sb.append(i"$scrutinee ? ${showTest(test)}(${ons.id})")
10141028
showPlan(ons)
1015-
showPlan(onf)
10161029
case LetPlan(sym, body) =>
10171030
sb.append(i"Let($sym = ${initializer(sym)}}, ${body.id})")
10181031
sb.append(s", refcount = ${vrefCount(sym)}")
10191032
showPlan(body)
1020-
case LabeledPlan(label, expr, next) =>
1021-
sb.append(i"Labeled($label: { ${expr.id} }; ${next.id})")
1033+
case LabeledPlan(label, expr) =>
1034+
sb.append(i"Labeled($label: { ${expr.id} })")
10221035
sb.append(s", refcount = ${lrefCount(label)}")
10231036
showPlan(expr)
1024-
showPlan(next)
10251037
case ReturnPlan(label) =>
10261038
sb.append(s"Return($label)")
1039+
case SeqPlan(head, tail) =>
1040+
sb.append(s"${head.id}; ${tail.id}")
1041+
showPlan(head)
1042+
showPlan(tail)
10271043
case ResultPlan(tree) =>
10281044
sb.append(tree.show)
10291045
}
@@ -1075,12 +1091,12 @@ object PatternMatcher {
10751091
def translateMatch(tree: Match): Tree = {
10761092
var plan = matchPlan(tree)
10771093
//patmatch.println(i"Plan for $tree: ${show(plan)}")
1078-
System.err.println(i"Plan for $tree: ${show(plan)}")
1094+
//System.err.println(i"Plan for $tree: ${show(plan)}")
10791095
if (!ctx.settings.YnoPatmatOpt.value)
10801096
for ((title, optimization) <- optimizations) {
10811097
plan = optimization(plan)
10821098
//patmatch.println(s"After $title: ${show(plan)}")
1083-
System.err.println(s"After $title: ${show(plan)}")
1099+
//System.err.println(s"After $title: ${show(plan)}")
10841100
}
10851101
val result = emit(plan)
10861102
//checkSwitch(tree, result)

0 commit comments

Comments
 (0)