Skip to content

Commit 80aff40

Browse files
authored
Merge pull request scala#8796 from LorenzoCC/issue/11709
Updated docs for `Constant` post removal of `LiteralArgument`
2 parents 006ed7d + f9902d2 commit 80aff40

File tree

1 file changed

+48
-127
lines changed

1 file changed

+48
-127
lines changed

src/reflect/scala/reflect/api/Constants.scala

Lines changed: 48 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,25 @@ package api
1919
*
2020
* According to the section 6.24 "Constant Expressions" of the Scala language specification,
2121
* certain expressions (dubbed ''constant expressions'') can be evaluated by the Scala compiler at compile-time.
22+
* Examples include "true", "0" and "classOf[List]".
2223
*
23-
* [[scala.reflect.api.Constants#Constant]] instances represent certain kinds of these expressions
24-
* (with values stored in the `value` field and its strongly-typed views named `booleanValue`, `intValue` etc.), namely:
25-
* 1. Literals of primitive value classes (bytes, shorts, ints, longs, floats, doubles, chars, booleans and voids).
26-
* 1. String literals.
27-
* 1. References to classes (typically constructed with [[scala.Predef#classOf]]).
28-
* 1. References to enumeration values.
24+
* `Constant` instances can be matched against and can be constructed directly, as if they were case classes:
25+
* {{{
26+
* assert(Constant(true).value == true)
27+
* Constant(true) match {
28+
* case Constant(s: String) => println("A string: " + s)
29+
* case Constant(b: Boolean) => println("A boolean value: " + b)
30+
* case Constant(x) => println("Something else: " + x)
31+
* }
32+
* }}}
2933
*
30-
* Such constants are used to represent literals in abstract syntax trees (the [[scala.reflect.api.Trees#Literal]] node)
31-
* and literal arguments for Java class file annotations (the [[scala.reflect.api.Annotations#LiteralArgument]] class).
34+
* `Constant` instances can wrap the following kinds of expressions:
35+
* 1. Literals of primitive value classes ([[scala.Byte `Byte`]], [[scala.Short `Short`]], [[scala.Int `Int`]], [[scala.Long `Long`]], [[scala.Float `Float`]], [[scala.Double `Double`]], [[scala.Char `Char`]], [[scala.Boolean `Boolean`]] and [[scala.Unit `Unit`]]) - represented directly as the corresponding type
36+
* 1. String literals - represented as instances of `String`.
37+
* 1. References to classes, typically constructed with [[scala.Predef#classOf]] - represented as [[scala.reflect.api.Types#Type types]].
38+
* 1. References to enumeration values - represented as [[scala.reflect.api.Symbols#Symbol symbols]].
39+
*
40+
* Instances are used to represent literals in abstract syntax trees, inside [[scala.reflect.api.Trees#Literal]] nodes.
3241
*
3342
* === Example ===
3443
*
@@ -43,10 +52,12 @@ package api
4352
* Enumeration value references are represented as instances of [[scala.reflect.api.Symbols#Symbol]], which on JVM point to methods
4453
* that return underlying enum values. To inspect an underlying enumeration or to get runtime value of a reference to an enum,
4554
* one should use a [[scala.reflect.api.Mirrors#RuntimeMirror]] (the simplest way to get such a mirror is again [[scala.reflect.runtime.package#currentMirror]]).
46-
55+
*
4756
* {{{
57+
* // File "JavaSimpleEnumeration.java"
4858
* enum JavaSimpleEnumeration { FOO, BAR }
4959
*
60+
* // File "JavaSimpleAnnotation.java"
5061
* import java.lang.annotation.*;
5162
* @Retention(RetentionPolicy.RUNTIME)
5263
* @Target({ElementType.TYPE})
@@ -55,40 +66,41 @@ package api
5566
* JavaSimpleEnumeration enumRef();
5667
* }
5768
*
69+
* // File "JavaAnnottee.java"
5870
* @JavaSimpleAnnotation(
5971
* classRef = JavaAnnottee.class,
6072
* enumRef = JavaSimpleEnumeration.BAR
6173
* )
6274
* public class JavaAnnottee {}
6375
* }}}
6476
* {{{
65-
* import scala.reflect.runtime.universe._
66-
* import scala.reflect.runtime.{currentMirror => cm}
67-
*
68-
* object Test extends App {
69-
* val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs
70-
* def jarg(name: String) = jann(TermName(name)).asInstanceOf[LiteralArgument].value
71-
*
72-
* val classRef = jarg("classRef").typeValue
73-
* println(showRaw(classRef)) // TypeRef(ThisType(<empty>), JavaAnnottee, List())
74-
* println(cm.runtimeClass(classRef)) // class JavaAnnottee
75-
*
76-
* val enumRef = jarg("enumRef").symbolValue
77-
* println(enumRef) // value BAR
78-
*
79-
* val siblings = enumRef.owner.info.decls
80-
* val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic)
81-
* println(enumValues) // Scope{
82-
* // final val FOO: JavaSimpleEnumeration;
83-
* // final val BAR: JavaSimpleEnumeration
84-
* // }
85-
*
86-
* // doesn't work because of https://github.com/scala/bug/issues/6459
87-
* // val enumValue = mirror.reflectField(enumRef.asTerm).get
88-
* val enumClass = cm.runtimeClass(enumRef.owner.asClass)
89-
* val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null)
90-
* println(enumValue) // BAR
91-
* }
77+
* val javaArgs = typeOf[JavaAnnottee].typeSymbol.annotations(0).tree.children.tail
78+
*
79+
* def jArg[A](lhs: String): Option[A] = javaArgs
80+
* .map { case NamedArg(lhs, Literal(const)) => (lhs.toString, const) }
81+
* .find(_._1 == lhs)
82+
* .map(_._2.value.asInstanceOf[A])
83+
*
84+
* // class reference, cast to Type
85+
* val classRef = jArg[Type]("classRef").get
86+
* println(showRaw(classRef)) // TypeRef(ThisType(<empty>), JavaAnnottee, List())
87+
* println(cm.runtimeClass(classRef)) // class JavaAnnottee
88+
* // enum value reference, cast to Symbol
89+
* val enumRef = jArg[Symbol]("enumRef").get
90+
* println(enumRef) // value BAR
91+
*
92+
* val siblings = enumRef.owner.info.decls
93+
* val enumValues = siblings.filter(_.isJavaEnum)
94+
* println(enumValues) // Scope{
95+
* // final val FOO: JavaSimpleEnumeration;
96+
* // final val BAR: JavaSimpleEnumeration
97+
* // }
98+
*
99+
* // doesn't work because of https://github.com/scala/bug/issues/6459
100+
* // val enumValue = mirror.reflectField(enumRef.asTerm).get
101+
* val enumClass = cm.runtimeClass(enumRef.owner.asClass)
102+
* val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null)
103+
* println(enumValue) // BAR
92104
* }}}
93105
*
94106
* @contentDiagram hideNodes "*Api"
@@ -97,97 +109,6 @@ package api
97109
trait Constants {
98110
self: Universe =>
99111

100-
/**
101-
* This "virtual" case class represents the reflection interface for literal expressions which can not be further
102-
* broken down or evaluated, such as "true", "0", "classOf[List]". Such values become parts of the Scala abstract
103-
* syntax tree representing the program. The constants
104-
* correspond to section 6.24 "Constant Expressions" of the
105-
* [[http://www.scala-lang.org/files/archive/spec/2.13/ Scala Language Specification]].
106-
*
107-
* Such constants are used to represent literals in abstract syntax trees (the [[scala.reflect.api.Trees#Literal]] node)
108-
* and literal arguments for Java class file annotations (the [[scala.reflect.api.Annotations#LiteralArgument]] class).
109-
*
110-
* Constants can be matched against and can be constructed directly, as if they were case classes:
111-
* {{{
112-
* assert(Constant(true).value == true)
113-
* Constant(true) match {
114-
* case Constant(s: String) => println("A string: " + s)
115-
* case Constant(b: Boolean) => println("A boolean value: " + b)
116-
* case Constant(x) => println("Something else: " + x)
117-
* }
118-
* }}}
119-
*
120-
* `Constant` instances can wrap certain kinds of these expressions:
121-
* 1. Literals of primitive value classes ([[scala.Byte `Byte`]], [[scala.Short `Short`]], [[scala.Int `Int`]], [[scala.Long `Long`]], [[scala.Float `Float`]], [[scala.Double `Double`]], [[scala.Char `Char`]], [[scala.Boolean `Boolean`]] and [[scala.Unit `Unit`]]) - represented directly as the corresponding type
122-
* 1. String literals - represented as instances of the `String`.
123-
* 1. References to classes, typically constructed with [[scala.Predef#classOf]] - represented as [[scala.reflect.api.Types#Type types]].
124-
* 1. References to enumeration values - represented as [[scala.reflect.api.Symbols#Symbol symbols]].
125-
*
126-
* Class references are represented as instances of [[scala.reflect.api.Types#Type]]
127-
* (because when the Scala compiler processes a class reference, the underlying runtime class might not yet have
128-
* been compiled). To convert such a reference to a runtime class, one should use the [[scala.reflect.api.Mirrors#RuntimeMirror#runtimeClass `runtimeClass`]] method of a
129-
* mirror such as [[scala.reflect.api.Mirrors#RuntimeMirror `RuntimeMirror`]] (the simplest way to get such a mirror is using
130-
* [[scala.reflect.runtime#currentMirror `scala.reflect.runtime.currentMirror`]]).
131-
*
132-
* Enumeration value references are represented as instances of [[scala.reflect.api.Symbols#Symbol]], which on JVM point to methods
133-
* that return underlying enum values. To inspect an underlying enumeration or to get runtime value of a reference to an enum,
134-
* one should use a [[scala.reflect.api.Mirrors#RuntimeMirror]] (the simplest way to get such a mirror is again [[scala.reflect.runtime.package#currentMirror]]).
135-
*
136-
* Usage example:
137-
* {{{
138-
* enum JavaSimpleEnumeration { FOO, BAR }
139-
*
140-
* import java.lang.annotation.*;
141-
* @Retention(RetentionPolicy.RUNTIME)
142-
* @Target({ElementType.TYPE})
143-
* public @interface JavaSimpleAnnotation {
144-
* Class<?> classRef();
145-
* JavaSimpleEnumeration enumRef();
146-
* }
147-
*
148-
* @JavaSimpleAnnotation(
149-
* classRef = JavaAnnottee.class,
150-
* enumRef = JavaSimpleEnumeration.BAR
151-
* )
152-
* public class JavaAnnottee {}
153-
* }}}
154-
* {{{
155-
* import scala.reflect.runtime.universe._
156-
* import scala.reflect.runtime.{currentMirror => cm}
157-
*
158-
* object Test extends App {
159-
* val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs
160-
* def jarg(name: String) = jann(TermName(name)) match {
161-
* // Constant is always wrapped into a Literal or LiteralArgument tree node
162-
* case LiteralArgument(ct: Constant) => value
163-
* }
164-
*
165-
* val classRef = jarg("classRef").value.asInstanceOf[Type]
166-
* // ideally one should match instead of casting
167-
* println(showRaw(classRef)) // TypeRef(ThisType(<empty>), JavaAnnottee, List())
168-
* println(cm.runtimeClass(classRef)) // class JavaAnnottee
169-
*
170-
* val enumRef = jarg("enumRef").value.asInstanceOf[Symbol]
171-
* // ideally one should match instead of casting
172-
* println(enumRef) // value BAR
173-
*
174-
* val siblings = enumRef.owner.info.decls
175-
* val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic)
176-
* println(enumValues) // Scope{
177-
* // final val FOO: JavaSimpleEnumeration;
178-
* // final val BAR: JavaSimpleEnumeration
179-
* // }
180-
*
181-
* // doesn't work because of https://github.com/scala/bug/issues/6459
182-
* // val enumValue = mirror.reflectField(enumRef.asTerm).get
183-
* val enumClass = cm.runtimeClass(enumRef.owner.asClass)
184-
* val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null)
185-
* println(enumValue) // BAR
186-
* }
187-
* }}}
188-
* @template
189-
* @group Constants
190-
*/
191112
type Constant >: Null <: AnyRef with ConstantApi
192113

193114
/** The constructor/extractor for `Constant` instances.

0 commit comments

Comments
 (0)