Skip to content

Commit 40910d8

Browse files
committed
More docs and some cleanups
1 parent fb03273 commit 40910d8

File tree

1 file changed

+24
-14
lines changed

1 file changed

+24
-14
lines changed

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

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,24 @@ object PatternMatcher {
4747

4848
final val selfCheck = true // debug option, if on we check that no case gets generated twice
4949

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+
*/
5168
class Translator(resultType: Type, trans: TreeTransform)(implicit ctx: Context, info: TransformerInfo) {
5269

5370
// ------- Bindings for variables and labels ---------------------
@@ -356,17 +373,17 @@ object PatternMatcher {
356373
*
357374
* The rewrite is useful to group cases that can form a switch together.
358375
*/
359-
private def hoistCases(plan: TestPlan): Plan = plan.onFailure match {
376+
private def hoistLabelled(plan: TestPlan): Plan = plan.onFailure match {
360377
case LetPlan(sym, body) if sym.is(Label) =>
361378
plan.onFailure = body
362-
LetPlan(sym, hoistCases(plan))
379+
LetPlan(sym, hoistLabelled(plan))
363380
case _ =>
364381
plan
365382
}
366383

367384
/** Inline let-bound trees and labelled blocks that are referenced only once.
368385
* 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`.
370387
*/
371388
private def optimize(plan: Plan): Plan = {
372389
val refCount = referenceCount(plan)
@@ -387,7 +404,7 @@ object PatternMatcher {
387404
plan.scrutinee = treeMap.transform(plan.scrutinee)
388405
plan.onSuccess = transform(plan.onSuccess)
389406
plan.onFailure = transform(plan.onFailure)
390-
hoistCases(plan)
407+
hoistLabelled(plan)
391408
case plan @ LetPlan(sym, body) =>
392409
val body1 = transform(body)
393410
if (toDrop(sym)) body1
@@ -412,15 +429,8 @@ object PatternMatcher {
412429

413430
// ----- Generating trees from plans ---------------
414431

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-
422432
/** The condition a test plan rewrites to */
423-
private def condition(plan: TestPlan): Tree = {
433+
private def emitCondition(plan: TestPlan): Tree = {
424434
val scrutinee = plan.scrutinee
425435
plan.test match {
426436
case NonEmptyTest =>
@@ -526,7 +536,7 @@ object PatternMatcher {
526536
if (switchCases.lengthCompare(4) >= 0) // at least 3 cases + default
527537
Match(plan.scrutinee, emitSwitchCases(switchCases))
528538
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))
530540
case plan @ LetPlan(sym, body) =>
531541
val symDef =
532542
if (sym.is(Label)) DefDef(sym, emit(labelled(sym)))

0 commit comments

Comments
 (0)