aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala2
-rw-r--r--src/dotty/tools/dotc/transform/PatternMatcher.scala18
-rw-r--r--test/test/DottyBytecodeTest.scala2
-rw-r--r--test/test/DottyBytecodeTests.scala52
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))
+ }
+ }
}