summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohannes Rudolph <johannes.rudolph@gmail.com>2016-03-08 23:02:23 +0100
committerLukas Rytz <lukas.rytz@gmail.com>2016-10-28 16:56:57 +0200
commit81d2c6185e6c10defcf1f6a25f69e8b2ed025d86 (patch)
treed1a69af725a9bd7944e3edd159bebf89ab4d7954 /src
parentb9a16c4a812a0bde8bd23fb90c0ec5d9439e0e14 (diff)
downloadscala-81d2c6185e6c10defcf1f6a25f69e8b2ed025d86.tar.gz
scala-81d2c6185e6c10defcf1f6a25f69e8b2ed025d86.tar.bz2
scala-81d2c6185e6c10defcf1f6a25f69e8b2ed025d86.zip
SI-3236 constant types for literal final static java fields
Since we don't parse Java expressions, fields of Java classes coming from source files never have constant types. This prevents using static java fields in annotation arguments in mixed compilation This PR assigns constant types to final static java fields if the initializer is a simple literal.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/javac/JavaParsers.scala58
-rw-r--r--src/compiler/scala/tools/nsc/javac/JavaScanners.scala2
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala2
3 files changed, 60 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
index eb25eb6e06..bc1c19237a 100644
--- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
@@ -567,10 +567,64 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
def varDecl(pos: Position, mods: Modifiers, tpt: Tree, name: TermName): ValDef = {
val tpt1 = optArrayBrackets(tpt)
- if (in.token == EQUALS && !mods.isParameter) skipTo(COMMA, SEMI)
+
+ /** Tries to detect final static literals syntactically and returns a constant type replacement */
+ def optConstantTpe(): Tree = {
+ in.nextToken()
+
+ def constantTpe(lit: Any): Tree =
+ try TypeTree(ConstantType(Constant(lit)))
+ finally in.nextToken()
+
+ def byType(value: Long): Tree =
+ tpt.tpe match {
+ case ByteTpe => constantTpe(value.toByte)
+ case CharTpe => constantTpe(value.toChar)
+ case ShortTpe => constantTpe(value.toShort)
+ case IntTpe => constantTpe(value.toInt)
+ case LongTpe => constantTpe(value.toLong)
+ case _ => tpt1
+ }
+
+ if (mods.hasFlag(Flags.STATIC) && mods.isFinal) {
+ def lit(negate: Boolean): Tree =
+ if (in.lookaheadToken == SEMI)
+ in.token match {
+ case TRUE if tpt.tpe == BooleanTpe => constantTpe(!negate)
+ case FALSE if tpt.tpe == BooleanTpe => constantTpe(negate)
+ case CHARLIT => byType(in.name.charAt(0))
+ case INTLIT => byType(in.intVal(negate))
+ case LONGLIT if tpt.tpe == LongTpe => constantTpe(in.intVal(negate))
+ case FLOATLIT if tpt.tpe == FloatTpe => constantTpe(in.floatVal(negate).toFloat)
+ case DOUBLELIT if tpt.tpe == DoubleTpe => constantTpe(in.floatVal(negate))
+ case STRINGLIT =>
+ tpt match {
+ case Ident(TypeName("String")) => constantTpe(in.name.toString)
+ case _ => tpt1
+ }
+ case _ => tpt1
+ }
+ else tpt1
+
+ in.token match {
+ case MINUS | BANG =>
+ in.nextToken()
+ lit(negate = true)
+ case other => lit(negate = false)
+ }
+ } else tpt1
+ }
+
+ val tpt2: Tree =
+ if (in.token == EQUALS && !mods.isParameter) {
+ val res = optConstantTpe()
+ skipTo(COMMA, SEMI)
+ res
+ } else tpt1
+
val mods1 = if (mods.isFinal) mods &~ Flags.FINAL else mods | Flags.MUTABLE
atPos(pos) {
- ValDef(mods1, name, tpt1, blankExpr)
+ ValDef(mods1, name, tpt2, blankExpr)
}
}
diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
index ac86dfd665..94c9d07939 100644
--- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
@@ -89,6 +89,7 @@ trait JavaScanners extends ast.parser.ScannersCommon {
javanme.ELSEkw -> ELSE,
javanme.ENUMkw -> ENUM,
javanme.EXTENDSkw -> EXTENDS,
+ javanme.FALSEkw -> FALSE,
javanme.FINALkw -> FINAL,
javanme.FINALLYkw -> FINALLY,
javanme.FLOATkw -> FLOAT,
@@ -118,6 +119,7 @@ trait JavaScanners extends ast.parser.ScannersCommon {
javanme.THROWkw -> THROW,
javanme.THROWSkw -> THROWS,
javanme.TRANSIENTkw -> TRANSIENT,
+ javanme.TRUEkw -> TRUE,
javanme.TRYkw -> TRY,
javanme.VOIDkw -> VOID,
javanme.VOLATILEkw -> VOLATILE,
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index a0688e129c..5e2bbf9598 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -1103,6 +1103,7 @@ trait StdNames {
final val ELSEkw: TermName = kw("else")
final val ENUMkw: TermName = kw("enum")
final val EXTENDSkw: TermName = kw("extends")
+ final val FALSEkw: TermName = kw("false")
final val FINALkw: TermName = kw("final")
final val FINALLYkw: TermName = kw("finally")
final val FLOATkw: TermName = kw("float")
@@ -1132,6 +1133,7 @@ trait StdNames {
final val THROWkw: TermName = kw("throw")
final val THROWSkw: TermName = kw("throws")
final val TRANSIENTkw: TermName = kw("transient")
+ final val TRUEkw: TermName = kw("true")
final val TRYkw: TermName = kw("try")
final val VOIDkw: TermName = kw("void")
final val VOLATILEkw: TermName = kw("volatile")