diff options
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/PatternMatcher.scala | 18 | ||||
-rw-r--r-- | test/test/DottyBytecodeTest.scala | 2 | ||||
-rw-r--r-- | test/test/DottyBytecodeTests.scala | 52 |
4 files changed, 50 insertions, 24 deletions
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 7f59cbed0..e96636282 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -479,6 +479,8 @@ class Definitions { def TASTYLongSignatureAnnot(implicit ctx: Context) = TASTYLongSignatureAnnotType.symbol.asClass lazy val TailrecAnnotType = ctx.requiredClassRef("scala.annotation.tailrec") def TailrecAnnot(implicit ctx: Context) = TailrecAnnotType.symbol.asClass + lazy val SwitchAnnotType = ctx.requiredClassRef("scala.annotation.switch") + def SwitchAnnot(implicit ctx: Context) = SwitchAnnotType.symbol.asClass lazy val ThrowsAnnotType = ctx.requiredClassRef("scala.throws") def ThrowsAnnot(implicit ctx: Context) = ThrowsAnnotType.symbol.asClass lazy val TransientAnnotType = ctx.requiredClassRef("scala.transient") diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala index 740fd5460..f8f32131b 100644 --- a/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -307,10 +307,15 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans // TODO Deal with guards? def isSwitchableType(tpe: Type): Boolean = { - (tpe isRef defn.IntClass) || - (tpe isRef defn.ByteClass) || - (tpe isRef defn.ShortClass) || - (tpe isRef defn.CharClass) + val actualTpe = tpe match { + case t @ AnnotatedType(inner, _) => inner + case x => x + } + + (actualTpe isRef defn.IntClass) || + (actualTpe isRef defn.ByteClass) || + (actualTpe isRef defn.ShortClass) || + (actualTpe isRef defn.CharClass) } object IntEqualityTestTreeMaker { @@ -423,7 +428,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans Match(intScrut, newCases :+ defaultCase) } - if (isSwitchableType(scrut.tpe.widenDealias) && cases.forall(isSwitchCase)) { + val dealiased = scrut.tpe.widenDealias + if (isSwitchableType(dealiased) && cases.forall(isSwitchCase)) { val valuesToCases = cases.map(extractSwitchCase) val values = valuesToCases.map(_._1) if (values.tails.exists { tail => tail.nonEmpty && tail.tail.exists(doOverlap(_, tail.head)) }) { @@ -433,6 +439,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans Some(makeSwitch(valuesToCases)) } } else { + if (dealiased hasAnnotation defn.SwitchAnnot) + ctx.warning("failed to emit switch for `@switch` annotated match") None } } diff --git a/test/test/DottyBytecodeTest.scala b/test/test/DottyBytecodeTest.scala index 3814b03bd..1acb85cbf 100644 --- a/test/test/DottyBytecodeTest.scala +++ b/test/test/DottyBytecodeTest.scala @@ -107,7 +107,7 @@ trait DottyBytecodeTest extends DottyTest { if (debug || !succ && !shouldFail || succ && shouldFail) instructions.foreach(Console.err.println) - succ + succ && !shouldFail || shouldFail && !succ } def sameBytecode(methA: MethodNode, methB: MethodNode) = { diff --git a/test/test/DottyBytecodeTests.scala b/test/test/DottyBytecodeTests.scala index 6b1562741..5b79772c4 100644 --- a/test/test/DottyBytecodeTests.scala +++ b/test/test/DottyBytecodeTests.scala @@ -46,24 +46,40 @@ class TestBCode extends DottyBytecodeTest { /** This test verifies that simple matches with `@switch` annotations are * indeed transformed to a switch - * - * FIXME: once issue#1258 is resolved, this should be enabled! */ - //@Test def basicTransfromAnnotated = { - // val source = """ - // |object Foo { - // | import scala.annotation.switch - // | def foo(i: Int) = (i: @switch) match { - // | case 2 => println(2) - // | case 1 => println(1) - // | } - // |}""".stripMargin + @Test def basicTransfromAnnotated = { + val source = """ + |object Foo { + | import scala.annotation.switch + | def foo(i: Int) = (i: @switch) match { + | case 2 => println(2) + | case 1 => println(1) + | } + |}""".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)) - // } - //} + 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 failTransform = { + val source = """ + |object Foo { + | import scala.annotation.switch + | def foo(i: Any) = (i: @switch) match { + | case x: String => println("string!") + | case x :: xs => println("list!") + | } + |}""".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, shouldFail = true)) + } + } } |