Skip to content

Commit e2eadf9

Browse files
authored
Merge pull request #5056 from dotty-staging/opt-patmat-labeled
Fix #5054: Remove the dead code generated by the Labeled-based pattern matcher
2 parents 63b2610 + 6e08649 commit e2eadf9

File tree

3 files changed

+89
-4
lines changed

3 files changed

+89
-4
lines changed

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,12 @@ object PatternMatcher {
457457
apply(initializer(plan.sym))
458458
plan
459459
}
460+
override def apply(plan: SeqPlan): Plan = {
461+
apply(plan.head)
462+
if (canFallThrough(plan.head))
463+
apply(plan.tail)
464+
plan
465+
}
460466
}
461467
refCounter(plan)
462468
refCounter.count
@@ -564,8 +570,10 @@ object PatternMatcher {
564570
new MergeTests()(plan)
565571
}
566572

567-
/** Inline let-bound trees that are referenced only once.
568-
* Drop all variables that are not referenced anymore after this.
573+
/** Inline let-bound trees that are referenced only once and eliminate dead code.
574+
*
575+
* - Drop all variables that are not referenced anymore after inlining.
576+
* - Drop the `tail` of `SeqPlan`s whose `head` cannot fall through.
569577
*/
570578
private def inlineVars(plan: Plan): Plan = {
571579
val refCount = varRefCount(plan)
@@ -597,6 +605,18 @@ object PatternMatcher {
597605
plan
598606
}
599607
}
608+
override def apply(plan: SeqPlan): Plan = {
609+
val newHead = apply(plan.head)
610+
if (!canFallThrough(newHead)) {
611+
// If the head cannot fall through, the tail is dead code
612+
newHead
613+
}
614+
else {
615+
plan.head = newHead
616+
plan.tail = apply(plan.tail)
617+
plan
618+
}
619+
}
600620
}
601621
Inliner(plan)
602622
}

compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class TestBCode extends DottyBytecodeTest {
5050
/** This test verifies that simple matches with `@switch` annotations are
5151
* indeed transformed to a switch
5252
*/
53-
@Test def basicTransfromAnnotated = {
53+
@Test def basicSwitch = {
5454
val source = """
5555
|object Foo {
5656
| import scala.annotation.switch
@@ -69,6 +69,71 @@ class TestBCode extends DottyBytecodeTest {
6969
}
7070
}
7171

72+
@Test def switchWithAlternatives = {
73+
val source =
74+
"""
75+
|object Foo {
76+
| import scala.annotation.switch
77+
| def foo(i: Int) = (i: @switch) match {
78+
| case 2 => println(2)
79+
| case 1 | 3 | 5 => println(1)
80+
| case 0 => println(0)
81+
| }
82+
|}
83+
""".stripMargin
84+
85+
checkBCode(source) { dir =>
86+
val moduleIn = dir.lookupName("Foo$.class", directory = false)
87+
val moduleNode = loadClassNode(moduleIn.input)
88+
val methodNode = getMethod(moduleNode, "foo")
89+
assert(verifySwitch(methodNode))
90+
}
91+
}
92+
93+
@Test def switchWithGuards = {
94+
val source =
95+
"""
96+
|object Foo {
97+
| import scala.annotation.switch
98+
| def foo(i: Int, b: Boolean) = (i: @switch) match {
99+
| case 2 => println(3)
100+
| case 1 if b => println(2)
101+
| case 1 => println(1)
102+
| case 0 => println(0)
103+
| }
104+
|}
105+
""".stripMargin
106+
107+
checkBCode(source) { dir =>
108+
val moduleIn = dir.lookupName("Foo$.class", directory = false)
109+
val moduleNode = loadClassNode(moduleIn.input)
110+
val methodNode = getMethod(moduleNode, "foo")
111+
assert(verifySwitch(methodNode))
112+
}
113+
}
114+
115+
@Test def matchWithDefaultNoThrowMatchError = {
116+
val source =
117+
"""class Test {
118+
| def test(s: String) = s match {
119+
| case "Hello" => 1
120+
| case _ => 2
121+
| }
122+
|}
123+
""".stripMargin
124+
125+
checkBCode(source) { dir =>
126+
val clsIn = dir.lookupName("Test.class", directory = false)
127+
val clsNode = loadClassNode(clsIn.input)
128+
val method = getMethod(clsNode, "test")
129+
val throwMatchError = instructionsFromMethod(method).exists {
130+
case Op(Opcodes.ATHROW) => true
131+
case _ => false
132+
}
133+
assertFalse(throwMatchError)
134+
}
135+
}
136+
72137
@Test def failTransform = {
73138
val source = """
74139
|object Foo {

0 commit comments

Comments
 (0)