diff options
-rw-r--r-- | lib/fjbg.jar.desired.sha1 | 2 | ||||
-rw-r--r-- | src/compiler/scala/reflect/internal/Symbols.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/GenICode.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala | 57 | ||||
-rw-r--r-- | src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java | 10 | ||||
-rwxr-xr-x | src/library/scala/reflect/api/Symbols.scala | 2 | ||||
-rw-r--r-- | test/files/run/t5423.check | 1 | ||||
-rw-r--r-- | test/files/run/t5423.scala | 12 | ||||
-rw-r--r-- | test/files/run/virtpatmat_switch.check | 7 | ||||
-rw-r--r-- | test/files/run/virtpatmat_switch.flags | 1 | ||||
-rw-r--r-- | test/files/run/virtpatmat_switch.scala | 32 | ||||
-rw-r--r-- | test/pending/run/t5427a.check | 1 | ||||
-rw-r--r-- | test/pending/run/t5427a.scala | 10 | ||||
-rw-r--r-- | test/pending/run/t5427b.check | 1 | ||||
-rw-r--r-- | test/pending/run/t5427b.scala | 11 | ||||
-rw-r--r-- | test/pending/run/t5427c.check | 1 | ||||
-rw-r--r-- | test/pending/run/t5427c.scala | 13 | ||||
-rw-r--r-- | test/pending/run/t5427d.check | 1 | ||||
-rw-r--r-- | test/pending/run/t5427d.scala | 11 |
19 files changed, 177 insertions, 15 deletions
diff --git a/lib/fjbg.jar.desired.sha1 b/lib/fjbg.jar.desired.sha1 index 1b1068b0d3..d24a5d01fc 100644 --- a/lib/fjbg.jar.desired.sha1 +++ b/lib/fjbg.jar.desired.sha1 @@ -1 +1 @@ -9aa9c99b8032e454f1f85d27de31a88b3dec1045 ?fjbg.jar +c3f9b576c91cb9761932ad936ccc4a71f33d2ef2 ?fjbg.jar diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 94d764067f..e777491300 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -1272,6 +1272,16 @@ trait Symbols extends api.Symbols { self: SymbolTable => * the annotations attached to member a definition (class, method, type, field). */ def annotations: List[AnnotationInfo] = _annotations + + /** This getter is necessary for reflection, see https://issues.scala-lang.org/browse/SI-5423 + * We could auto-inject completion into `annotations' and `setAnnotations', but I'm not sure about that + * @odersky writes: I fear we can't do the forcing for all compiler symbols as that could introduce cycles + */ + def getAnnotations: List[AnnotationInfo] = { + initialize + _annotations + } + def setAnnotations(annots: List[AnnotationInfo]): this.type = { _annotations = annots this diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 3d650ef753..3baff7da9e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1072,6 +1072,15 @@ abstract class GenICode extends SubComponent { targets = tmpCtx.bb :: targets case Ident(nme.WILDCARD) => default = tmpCtx.bb + case Alternative(alts) => + alts foreach { + case Literal(value) => + tags = value.intValue :: tags + targets = tmpCtx.bb :: targets + case _ => + abort("Invalid case in alternative in switch-like pattern match: " + + tree + " at: " + tree.pos) + } case _ => abort("Invalid case statement in switch-like pattern match: " + tree + " at: " + (tree.pos)) diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index 44579400ff..b1e02cb062 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -1128,23 +1128,35 @@ defined class Foo */ // } // } + private val switchableTpes = Set(ByteClass.tpe, ShortClass.tpe, IntClass.tpe, CharClass.tpe) + def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] = if (!optimizingCodeGen) None else { def sequence[T](xs: List[Option[T]]): Option[List[T]] = if (xs exists (_.isEmpty)) None else Some(xs.flatten) + def isSwitchableTpe(tpe: Type): Boolean = + switchableTpes contains tpe + def switchableConstToInt(x: Tree): Tree = { + val Literal(const) = x + const.tag match { + case IntTag => x + case ByteTag | ShortTag | CharTag => Literal(Constant(const.intValue)) + } + } + val caseDefs = cases map { makers => removeSubstOnly(makers) match { // default case (don't move this to unfold, as it may only occur on the top level, not as an alternative -- well, except in degenerate matches) case (btm@BodyTreeMaker(body, _)) :: Nil => Some(CaseDef(Ident(nme.WILDCARD), EmptyTree, btm.substitution(body))) // constant - case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil => import CODE._ - Some(CaseDef(const, EmptyTree, btm.substitution(body))) + case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil => + Some(CaseDef(switchableConstToInt(const), EmptyTree, btm.substitution(body))) // alternatives case AlternativesTreeMaker(_, altss, _) :: (btm@BodyTreeMaker(body, _)) :: Nil => // assert(currLabel.isEmpty && nextLabel.isEmpty) val caseConstants = altss map { case EqualityTestTreeMaker(_, const@SwitchablePattern(), _) :: Nil => - Some(const) + Some(switchableConstToInt(const)) case _ => None } @@ -1158,16 +1170,35 @@ defined class Foo */ } } - sequence(caseDefs) map { caseDefs => - import CODE._ - val matcher = BLOCK( - VAL(scrutSym) === scrut, // TODO: type test for switchable type if patterns allow switch but the scrutinee doesn't - Match(REF(scrutSym), caseDefs) // match on scrutSym, not scrut to avoid duplicating scrut - ) - - // matcher filter (tree => tree.tpe == null) foreach println - // treeBrowser browse matcher - matcher // set type to avoid recursion in typedMatch + if (!isSwitchableTpe(scrut.tpe)) + None + else { + sequence(caseDefs) map { caseDefs => + import CODE._ + val caseDefsWithDefault = { + def isDefault(x: CaseDef): Boolean = x match { + case CaseDef(Ident(nme.WILDCARD), EmptyTree, _) => true + case _ => false + } + val hasDefault = caseDefs exists isDefault + if (hasDefault) caseDefs else { + val default = atPos(scrut.pos) { DEFAULT ==> MATCHERROR(REF(scrutSym)) } + caseDefs :+ default + } + } + val matcher = BLOCK( + if (scrut.tpe != IntClass.tpe) { + scrutSym setInfo IntClass.tpe + VAL(scrutSym) === (scrut DOT nme.toInt) + } else { + VAL(scrutSym) === scrut + }, + Match(REF(scrutSym), caseDefsWithDefault) // match on scrutSym, not scrut to avoid duplicating scrut + ) + // matcher filter (tree => tree.tpe == null) foreach println + // treeBrowser browse matcher + matcher // set type to avoid recursion in typedMatch + } } } diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java b/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java index 8b0338ed29..d4c5417260 100644 --- a/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java +++ b/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java @@ -596,6 +596,16 @@ public class JExtendedCode extends JCode { double minDensity) { assert keys.length == branches.length; + //The special case for empty keys. It makes sense to allow + //empty keys and generate LOOKUPSWITCH with defaultBranch + //only. This is exactly what javac does for switch statement + //that has only a default case. + if (keys.length == 0) { + emitLOOKUPSWITCH(keys, branches, defaultBranch); + return; + } + //the rest of the code assumes that keys.length > 0 + // sorting the tables // FIXME use quicksort for (int i = 1; i < keys.length; i++) { diff --git a/src/library/scala/reflect/api/Symbols.scala b/src/library/scala/reflect/api/Symbols.scala index 01c1a0f2ae..17d9b06324 100755 --- a/src/library/scala/reflect/api/Symbols.scala +++ b/src/library/scala/reflect/api/Symbols.scala @@ -79,7 +79,7 @@ trait Symbols { self: Universe => /** A list of annotations attached to this Symbol. */ - def annotations: List[self.AnnotationInfo] + def getAnnotations: List[self.AnnotationInfo] /** For a class: the module or case class factory with the same name in the same package. * For all others: NoSymbol diff --git a/test/files/run/t5423.check b/test/files/run/t5423.check new file mode 100644 index 0000000000..ae3d3fb82b --- /dev/null +++ b/test/files/run/t5423.check @@ -0,0 +1 @@ +List(table)
\ No newline at end of file diff --git a/test/files/run/t5423.scala b/test/files/run/t5423.scala new file mode 100644 index 0000000000..2139773ff1 --- /dev/null +++ b/test/files/run/t5423.scala @@ -0,0 +1,12 @@ +import java.lang.Class +import scala.reflect.mirror._ +import scala.reflect.runtime.Mirror.ToolBox +import scala.reflect.Code + +final class table extends StaticAnnotation +@table class A + +object Test extends App{ + val s = classToSymbol(classOf[A]) + println(s.getAnnotations) +} diff --git a/test/files/run/virtpatmat_switch.check b/test/files/run/virtpatmat_switch.check new file mode 100644 index 0000000000..6ded95c010 --- /dev/null +++ b/test/files/run/virtpatmat_switch.check @@ -0,0 +1,7 @@ +zero +one +many +got a +got b +got some letter +scala.MatchError: 5 (of class java.lang.Integer)
\ No newline at end of file diff --git a/test/files/run/virtpatmat_switch.flags b/test/files/run/virtpatmat_switch.flags new file mode 100644 index 0000000000..9769db9257 --- /dev/null +++ b/test/files/run/virtpatmat_switch.flags @@ -0,0 +1 @@ + -Yvirtpatmat -Xexperimental diff --git a/test/files/run/virtpatmat_switch.scala b/test/files/run/virtpatmat_switch.scala new file mode 100644 index 0000000000..2e2c31e8e5 --- /dev/null +++ b/test/files/run/virtpatmat_switch.scala @@ -0,0 +1,32 @@ +object Test extends App { + def intSwitch(x: Int) = x match { + case 0 => "zero" + case 1 => "one" + case _ => "many" + } + + println(intSwitch(0)) + println(intSwitch(1)) + println(intSwitch(10)) + + def charSwitch(x: Char) = x match { + case 'a' => "got a" + case 'b' => "got b" + case _ => "got some letter" + } + + println(charSwitch('a')) + println(charSwitch('b')) + println(charSwitch('z')) + + def implicitDefault(x: Int) = x match { + case 0 => 0 + } + + try { + implicitDefault(5) + } catch { + case e: MatchError => println(e) + } + +} diff --git a/test/pending/run/t5427a.check b/test/pending/run/t5427a.check new file mode 100644 index 0000000000..d8263ee986 --- /dev/null +++ b/test/pending/run/t5427a.check @@ -0,0 +1 @@ +2
\ No newline at end of file diff --git a/test/pending/run/t5427a.scala b/test/pending/run/t5427a.scala new file mode 100644 index 0000000000..27b28da0ac --- /dev/null +++ b/test/pending/run/t5427a.scala @@ -0,0 +1,10 @@ +import scala.reflect.mirror._ + +object Foo { val bar = 2 } + +object Test extends App { + val tpe = getType(Foo) + val bar = tpe.nonPrivateMember(newTermName("bar")) + val value = getValue(Foo, bar) + println(value) +}
\ No newline at end of file diff --git a/test/pending/run/t5427b.check b/test/pending/run/t5427b.check new file mode 100644 index 0000000000..d8263ee986 --- /dev/null +++ b/test/pending/run/t5427b.check @@ -0,0 +1 @@ +2
\ No newline at end of file diff --git a/test/pending/run/t5427b.scala b/test/pending/run/t5427b.scala new file mode 100644 index 0000000000..7a92b6ebbe --- /dev/null +++ b/test/pending/run/t5427b.scala @@ -0,0 +1,11 @@ +import scala.reflect.mirror._ + +class Foo { val bar = 2 } + +object Test extends App { + val foo = new Foo + val tpe = getType(foo) + val bar = tpe.nonPrivateMember(newTermName("bar")) + val value = getValue(foo, bar) + println(value) +}
\ No newline at end of file diff --git a/test/pending/run/t5427c.check b/test/pending/run/t5427c.check new file mode 100644 index 0000000000..32c91abbd6 --- /dev/null +++ b/test/pending/run/t5427c.check @@ -0,0 +1 @@ +no public member
\ No newline at end of file diff --git a/test/pending/run/t5427c.scala b/test/pending/run/t5427c.scala new file mode 100644 index 0000000000..ab41d8b8cd --- /dev/null +++ b/test/pending/run/t5427c.scala @@ -0,0 +1,13 @@ +import scala.reflect.mirror._ + +class Foo(bar: Int) + +object Test extends App { + val foo = new Foo(2) + val tpe = getType(foo) + val bar = tpe.nonPrivateMember(newTermName("bar")) + bar match { + case NoSymbol => println("no public member") + case _ => println("i'm screwed") + } +}
\ No newline at end of file diff --git a/test/pending/run/t5427d.check b/test/pending/run/t5427d.check new file mode 100644 index 0000000000..d8263ee986 --- /dev/null +++ b/test/pending/run/t5427d.check @@ -0,0 +1 @@ +2
\ No newline at end of file diff --git a/test/pending/run/t5427d.scala b/test/pending/run/t5427d.scala new file mode 100644 index 0000000000..fd4c62e876 --- /dev/null +++ b/test/pending/run/t5427d.scala @@ -0,0 +1,11 @@ +import scala.reflect.mirror._ + +class Foo(val bar: Int) + +object Test extends App { + val foo = new Foo(2) + val tpe = getType(foo) + val bar = tpe.nonPrivateMember(newTermName("bar")) + val value = getValue(foo, bar) + println(value) +}
\ No newline at end of file |