aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-05-17 17:39:55 +0200
committerFelix Mulder <felix.mulder@gmail.com>2016-05-17 17:39:55 +0200
commitd5147288df4cc05ac4d761bd0e451f724c474ae1 (patch)
treeb2135b22adb44929fe8f4499665c0099432b9c0b
parent3aa22cc24f601cb70dcff7247af95ad9fa403de5 (diff)
downloaddotty-d5147288df4cc05ac4d761bd0e451f724c474ae1.tar.gz
dotty-d5147288df4cc05ac4d761bd0e451f724c474ae1.tar.bz2
dotty-d5147288df4cc05ac4d761bd0e451f724c474ae1.zip
Fix #1258: correct behavior for annotated values
Annotated values are encapsulated in a `ConcreteAnnotation`, as such, the statement `tpe isRef defn.IntClass` would yield false despite the annotated reference being an Int. The tpe is now unwrapped if it has an annotation. If the transformation fails despite having the annotation the compiler will warn.
-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))
+ }
+ }
}