summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorAleksandar Prokopec <axel22@gmail.com>2012-07-10 20:54:23 +0200
committerAleksandar Prokopec <axel22@gmail.com>2012-07-18 17:11:59 +0200
commit892ee3df93a10ffe24fb11b37ad7c3a9cb93d5de (patch)
treebad301c983fb868fbaf696fddd2afbc4c11a82a0 /src/reflect
parent79161ec9e2c8511f3b6d22c0e2f5b96da9565144 (diff)
downloadscala-892ee3df93a10ffe24fb11b37ad7c3a9cb93d5de.tar.gz
scala-892ee3df93a10ffe24fb11b37ad7c3a9cb93d5de.tar.bz2
scala-892ee3df93a10ffe24fb11b37ad7c3a9cb93d5de.zip
Implement @static annotation on singleton object fields.
This commit introduces the `@static` annotation on fields of static singleton objects. A static singleton object is a top-level singleton object or an object nested within a static singleton object. The field annotated with `@static` is generated as a true static field in the companion class of the object. The initialization of the field is done in the static initializer of the companion class, instead of the object itself. Here's an example. This: object Foo { @static val FIELD = 123 } class Foo generates : object Foo { def FIELD(): Int = Foo.FIELD } class Foo { <static> val FIELD = 123 } The accessor in `object Foo` is changed to return the static field in `class Foo` (the companion class is generated if it is not already present, and the same is done for getters if `FIELD` is a `var`). Furthermore, all the callsites to accessor `Foo.FIELD` are rewritten to access the static field directly. It is illegal to annotate a field in the singleton object as `@static` if there is already a member of the same name in `class Foo`. This allows better Java interoperability with frameworks which rely on static fields being present in the class. The `AtomicReferenceFieldUpdater`s are one such example. Instead of having a Java base class holding the `volatile` mutable field `f` and a static field containing a reference to the `AtomicReferenceFieldUpdater` that mutates `f` atomically, and extending this Java base class from Scala, we can now simply do: object Foo { @static val arfu = AtomicReferenceUpdater.newUpdater( classOf[Foo], classOf[String], "f" ) } class Foo { @volatile var f = null import Foo._ def CAS(ov: String, nv: String) = arfu.compareAndSet(this, null, "") } In summary, this commit introduces the following: - adds the `@static` annotation - for objects without a companion class and `@static` members, creates a companion class (this is done in `CleanUp`) - checks for conflicting names and if `@static` is used on static singleton object member - creates the `static` field in the companion class for `@static` members - moves the field initialization from the companion object to the static initializer of the class (the initialization of `@static` members is bypassed in the `Constructors` phase, and added to static ctors in `CleanUp`) - all callsites to the accessors of `@static` are rewritten to access the static fields directly (this is done in `GenICode`) - getters and setters to `@static` fields access the static field directly, and the field in the singleton object is not emitted (this is done in `GenICode`) - changes in `GenJVM`, `GenASM` - now computing local var indices in static initializers as well - this was an oversight before, now is necessary Future work: allow the `@static` annotation on methods as well - this will be added in a future commit. Review by @odersky, @dragos, @paulp, @heathermiller.
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala1
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala1
3 files changed, 3 insertions, 0 deletions
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index cd243b9df0..f5172eb9aa 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -899,6 +899,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val SwitchClass = requiredClass[scala.annotation.switch]
lazy val TailrecClass = requiredClass[scala.annotation.tailrec]
lazy val VarargsClass = requiredClass[scala.annotation.varargs]
+ lazy val StaticClass = requiredClass[scala.annotation.static]
lazy val uncheckedStableClass = requiredClass[scala.annotation.unchecked.uncheckedStable]
lazy val uncheckedVarianceClass = requiredClass[scala.annotation.unchecked.uncheckedVariance]
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 165e04863c..d41670591c 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -246,6 +246,7 @@ trait StdNames {
final val BeanPropertyAnnot: NameType = "BeanProperty"
final val BooleanBeanPropertyAnnot: NameType = "BooleanBeanProperty"
final val bridgeAnnot: NameType = "bridge"
+ final val staticAnnot: NameType = "static"
// Classfile Attributes
final val AnnotationDefaultATTR: NameType = "AnnotationDefault"
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index fab5c5a2e7..82e4f98028 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -938,6 +938,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
|| hasAnnotation(SerializableAttr) // last part can be removed, @serializable annotation is deprecated
)
def hasBridgeAnnotation = hasAnnotation(BridgeClass)
+ def hasStaticAnnotation = hasAnnotation(StaticClass)
def isDeprecated = hasAnnotation(DeprecatedAttr)
def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0)
def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1)