Skip to content

Commit

Permalink
Merge pull request #5056 from dotty-staging/opt-patmat-labeled
Browse files Browse the repository at this point in the history
Fix #5054: Remove the dead code generated by the Labeled-based pattern matcher
  • Loading branch information
allanrenucci authored Sep 3, 2018
2 parents 63b2610 + 6e08649 commit e2eadf9
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 4 deletions.
24 changes: 22 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,12 @@ object PatternMatcher {
apply(initializer(plan.sym))
plan
}
override def apply(plan: SeqPlan): Plan = {
apply(plan.head)
if (canFallThrough(plan.head))
apply(plan.tail)
plan
}
}
refCounter(plan)
refCounter.count
Expand Down Expand Up @@ -564,8 +570,10 @@ object PatternMatcher {
new MergeTests()(plan)
}

/** Inline let-bound trees that are referenced only once.
* Drop all variables that are not referenced anymore after this.
/** Inline let-bound trees that are referenced only once and eliminate dead code.
*
* - Drop all variables that are not referenced anymore after inlining.
* - Drop the `tail` of `SeqPlan`s whose `head` cannot fall through.
*/
private def inlineVars(plan: Plan): Plan = {
val refCount = varRefCount(plan)
Expand Down Expand Up @@ -597,6 +605,18 @@ object PatternMatcher {
plan
}
}
override def apply(plan: SeqPlan): Plan = {
val newHead = apply(plan.head)
if (!canFallThrough(newHead)) {
// If the head cannot fall through, the tail is dead code
newHead
}
else {
plan.head = newHead
plan.tail = apply(plan.tail)
plan
}
}
}
Inliner(plan)
}
Expand Down
67 changes: 66 additions & 1 deletion compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class TestBCode extends DottyBytecodeTest {
/** This test verifies that simple matches with `@switch` annotations are
* indeed transformed to a switch
*/
@Test def basicTransfromAnnotated = {
@Test def basicSwitch = {
val source = """
|object Foo {
| import scala.annotation.switch
Expand All @@ -69,6 +69,71 @@ class TestBCode extends DottyBytecodeTest {
}
}

@Test def switchWithAlternatives = {
val source =
"""
|object Foo {
| import scala.annotation.switch
| def foo(i: Int) = (i: @switch) match {
| case 2 => println(2)
| case 1 | 3 | 5 => println(1)
| case 0 => println(0)
| }
|}
""".stripMargin

checkBCode(source) { dir =>
val moduleIn = dir.lookupName("Foo$.class", directory = false)
val moduleNode = loadClassNode(moduleIn.input)
val methodNode = getMethod(moduleNode, "foo")
assert(verifySwitch(methodNode))
}
}

@Test def switchWithGuards = {
val source =
"""
|object Foo {
| import scala.annotation.switch
| def foo(i: Int, b: Boolean) = (i: @switch) match {
| case 2 => println(3)
| case 1 if b => println(2)
| case 1 => println(1)
| case 0 => println(0)
| }
|}
""".stripMargin

checkBCode(source) { dir =>
val moduleIn = dir.lookupName("Foo$.class", directory = false)
val moduleNode = loadClassNode(moduleIn.input)
val methodNode = getMethod(moduleNode, "foo")
assert(verifySwitch(methodNode))
}
}

@Test def matchWithDefaultNoThrowMatchError = {
val source =
"""class Test {
| def test(s: String) = s match {
| case "Hello" => 1
| case _ => 2
| }
|}
""".stripMargin

checkBCode(source) { dir =>
val clsIn = dir.lookupName("Test.class", directory = false)
val clsNode = loadClassNode(clsIn.input)
val method = getMethod(clsNode, "test")
val throwMatchError = instructionsFromMethod(method).exists {
case Op(Opcodes.ATHROW) => true
case _ => false
}
assertFalse(throwMatchError)
}
}

@Test def failTransform = {
val source = """
|object Foo {
Expand Down
2 changes: 1 addition & 1 deletion scala-backend

0 comments on commit e2eadf9

Please sign in to comment.