@@ -47,7 +47,24 @@ object PatternMatcher {
47
47
48
48
final val selfCheck = true // debug option, if on we check that no case gets generated twice
49
49
50
- /** The pattern matching translator. */
50
+ /** The pattern matching translator.
51
+ * Its general structure is a pipeline:
52
+ *
53
+ * Match tree ---matchPlan---> Plan ---optimize---> Plan ---emit---> Tree
54
+ *
55
+ * The pipeline consists of three steps:
56
+ *
57
+ * - build a plan, using methods `matchPlan`, `caseDefPlan`, `patternPlan`.
58
+ * - optimize the plan, using methods `optimize`, `hoistLabelled`, `referenceCount`.
59
+ * - emit the translated tree, using methods `emit`, `collectSwitchCases`,
60
+ * `emitSwitchCases`, and `emitCondition`.
61
+ *
62
+ * A plan represents the underlying decision graph. It consists
63
+ * of tests, let and label bindings, calls to labels and code blocks.
64
+ * It's represented by its own data type. Plans are optimized by
65
+ * inlining, hoisting, and dead code elimination. We should also
66
+ * do common test elimination but right now this is missing.
67
+ */
51
68
class Translator (resultType : Type , trans : TreeTransform )(implicit ctx : Context , info : TransformerInfo ) {
52
69
53
70
// ------- Bindings for variables and labels ---------------------
@@ -356,17 +373,17 @@ object PatternMatcher {
356
373
*
357
374
* The rewrite is useful to group cases that can form a switch together.
358
375
*/
359
- private def hoistCases (plan : TestPlan ): Plan = plan.onFailure match {
376
+ private def hoistLabelled (plan : TestPlan ): Plan = plan.onFailure match {
360
377
case LetPlan (sym, body) if sym.is(Label ) =>
361
378
plan.onFailure = body
362
- LetPlan (sym, hoistCases (plan))
379
+ LetPlan (sym, hoistLabelled (plan))
363
380
case _ =>
364
381
plan
365
382
}
366
383
367
384
/** Inline let-bound trees and labelled blocks that are referenced only once.
368
385
* Drop all variables and labels that are not referenced anymore after this.
369
- * Also: hoist cases out of tests using `hoistCases `.
386
+ * Also: hoist cases out of tests using `hoistLabelled `.
370
387
*/
371
388
private def optimize (plan : Plan ): Plan = {
372
389
val refCount = referenceCount(plan)
@@ -387,7 +404,7 @@ object PatternMatcher {
387
404
plan.scrutinee = treeMap.transform(plan.scrutinee)
388
405
plan.onSuccess = transform(plan.onSuccess)
389
406
plan.onFailure = transform(plan.onFailure)
390
- hoistCases (plan)
407
+ hoistLabelled (plan)
391
408
case plan @ LetPlan (sym, body) =>
392
409
val body1 = transform(body)
393
410
if (toDrop(sym)) body1
@@ -412,15 +429,8 @@ object PatternMatcher {
412
429
413
430
// ----- Generating trees from plans ---------------
414
431
415
- /** The position to be used for the tree generated from a plan */
416
- private def position (plan : TestPlan ) = plan.test match {
417
- case TypeTest (tpt) => tpt.pos
418
- case EqualTest (tree) => tree.pos
419
- case _ => plan.scrutinee.pos
420
- }
421
-
422
432
/** The condition a test plan rewrites to */
423
- private def condition (plan : TestPlan ): Tree = {
433
+ private def emitCondition (plan : TestPlan ): Tree = {
424
434
val scrutinee = plan.scrutinee
425
435
plan.test match {
426
436
case NonEmptyTest =>
@@ -526,7 +536,7 @@ object PatternMatcher {
526
536
if (switchCases.lengthCompare(4 ) >= 0 ) // at least 3 cases + default
527
537
Match (plan.scrutinee, emitSwitchCases(switchCases))
528
538
else
529
- If (condition (plan).withPos(position( plan) ), emit(plan.onSuccess), emit(plan.onFailure))
539
+ If (emitCondition (plan).withPos(plan.pos ), emit(plan.onSuccess), emit(plan.onFailure))
530
540
case plan @ LetPlan (sym, body) =>
531
541
val symDef =
532
542
if (sym.is(Label )) DefDef (sym, emit(labelled(sym)))
0 commit comments