summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-10-04 07:37:41 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-10-11 19:53:52 +0200
commit6eb48f9602c3a21c85a38651c2e0b887e06b8d18 (patch)
tree641403b5a61dcc12d3419c0028a786ffc21cafff /src
parent553ee0118dbc052bed8c4580376b48cd9cb5d0f9 (diff)
downloadscala-6eb48f9602c3a21c85a38651c2e0b887e06b8d18.tar.gz
scala-6eb48f9602c3a21c85a38651c2e0b887e06b8d18.tar.bz2
scala-6eb48f9602c3a21c85a38651c2e0b887e06b8d18.zip
docs for reflection and macros
Diffstat (limited to 'src')
-rw-r--r--src/reflect/scala/reflect/api/Annotations.scala133
-rw-r--r--src/reflect/scala/reflect/api/Constants.scala84
-rw-r--r--src/reflect/scala/reflect/api/Exprs.scala55
-rw-r--r--src/reflect/scala/reflect/api/FlagSets.scala36
-rw-r--r--src/reflect/scala/reflect/api/Importers.scala84
-rw-r--r--src/reflect/scala/reflect/api/JavaMirrors.scala21
-rw-r--r--src/reflect/scala/reflect/api/JavaUniverse.scala7
-rw-r--r--src/reflect/scala/reflect/api/Mirror.scala9
-rw-r--r--src/reflect/scala/reflect/api/Mirrors.scala44
-rw-r--r--src/reflect/scala/reflect/api/Names.scala69
-rw-r--r--src/reflect/scala/reflect/api/Position.scala65
-rw-r--r--src/reflect/scala/reflect/api/Positions.scala10
-rw-r--r--src/reflect/scala/reflect/api/Printers.scala126
-rw-r--r--src/reflect/scala/reflect/api/Scopes.scala20
-rw-r--r--src/reflect/scala/reflect/api/StandardDefinitions.scala234
-rw-r--r--src/reflect/scala/reflect/api/StandardNames.scala55
-rw-r--r--src/reflect/scala/reflect/api/Symbols.scala243
-rw-r--r--src/reflect/scala/reflect/api/TagInterop.scala20
-rw-r--r--src/reflect/scala/reflect/api/Trees.scala850
-rw-r--r--src/reflect/scala/reflect/api/TypeTags.scala46
-rw-r--r--src/reflect/scala/reflect/api/Types.scala212
-rw-r--r--src/reflect/scala/reflect/api/Universe.scala70
-rw-r--r--src/reflect/scala/reflect/api/package.scala271
-rw-r--r--src/reflect/scala/reflect/internal/util/Position.scala44
-rw-r--r--src/reflect/scala/reflect/macros/Aliases.scala76
-rw-r--r--src/reflect/scala/reflect/macros/Context.scala65
-rw-r--r--src/reflect/scala/reflect/macros/Enclosures.scala5
-rw-r--r--src/reflect/scala/reflect/macros/Evals.scala47
-rw-r--r--src/reflect/scala/reflect/macros/ExprUtils.scala16
-rw-r--r--src/reflect/scala/reflect/macros/FrontEnds.scala28
-rw-r--r--src/reflect/scala/reflect/macros/Infrastructure.scala3
-rw-r--r--src/reflect/scala/reflect/macros/Names.scala11
-rw-r--r--src/reflect/scala/reflect/macros/Parsers.scala10
-rw-r--r--src/reflect/scala/reflect/macros/Reifiers.scala3
-rw-r--r--src/reflect/scala/reflect/macros/TreeBuilder.scala17
-rw-r--r--src/reflect/scala/reflect/macros/Typers.scala3
-rw-r--r--src/reflect/scala/reflect/macros/Universe.scala71
-rw-r--r--src/reflect/scala/reflect/macros/package.scala257
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverse.scala5
-rw-r--r--src/reflect/scala/reflect/runtime/package.scala11
40 files changed, 3051 insertions, 385 deletions
diff --git a/src/reflect/scala/reflect/api/Annotations.scala b/src/reflect/scala/reflect/api/Annotations.scala
index 37882a9f3c..92dda2c75f 100644
--- a/src/reflect/scala/reflect/api/Annotations.scala
+++ b/src/reflect/scala/reflect/api/Annotations.scala
@@ -3,17 +3,91 @@ package api
import scala.collection.immutable.ListMap
-/**
- * Defines the type hierarchy for annotations.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines annotations and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
+ *
+ * Scala reflection supports:
+ * 1. Annotations on definitions or types produced by the Scala compiler, i.e. subtypes of both
+ * [[scala.annotation.StaticAnnotation]] and [[scala.annotation.ClassfileAnnotation]] attached to program definitions or types
+ * (note: subclassing just [[scala.annotation.Annotation]] is not enough to have the corresponding
+ * metadata persisted for runtime reflection).
+ * 1. Annotations on definitions produced by the Java compiler, i.e. subtypes of [[java.lang.annotation.Annotation]]
+ * attached to program definitions. When read by Scala reflection, the [[scala.annotation.ClassfileAnnotation]] trait
+ * is automatically added as a subclass to every Java annotation.
+ *
+ * First of all [[scala.reflect.api.Annotations#Annotation]] provides `tpe`, which describes the type of the annotation.
+ * Depending on the superclasses of `tpe`, there are two flavors of annotations.
+ *
+ * When annotations that subclass of [[scala.annotation.StaticAnnotation]] (dubbed ''Scala annotations'') are compiled by the Scala compiler,
+ * the information about them is ''pickled'', i.e. stored in special attributes in class files. To the contrast,
+ * annotations subclassing [[scala.annotation.ClassfileAnnotation]] (called ''Java annotations'') are written to class files as Java annotations.
+ * This distinction is manifested in the contract of [[scala.reflect.api.Annotations#Annotation]], which exposes
+ * both `scalaArgs` and `javaArgs`.
+ *
+ * For Scala annotations, arguments are stored in `scalaArgs` and `javaArgs` is empty. Arguments in
+ * `scalaArgs` are represented as typed trees. Note that these trees are not transformed by any phases
+ * following the type-checker.
+ *
+ * For Java annotations, `scalaArgs` is empty and arguments are stored in `javaArgs`.
+ * In this case, unlike in Java, Scala reflection only provides a key-value store of type [[scala.collection.immutable.ListMap]] from [[scala.reflect.api.Names#Name]] to
+ * [[scala.reflect.api.Annotations#JavaArgument]] that describes the annotations. Instances of `JavaArgument`
+ * represent different kinds of Java annotation arguments: literals (primitive and string constants), arrays and nested annotations.
+ * One shoud match against [[scala.reflect.api.Annotations#LiteralArgument]], [[scala.reflect.api.Annotations#ArrayArgument]] and [[scala.reflect.api.Annotations#NestedArgument]]
+ * to analyze them. We acknowledge that this process can be made more convenient and created [[https://issues.scala-lang.org/browse/SI-6423 an issue]] in the issue tracker
+ * to discuss possible improvements and track progress.
+ *
+ * === Example ===
+ *
+ * Entry points to the annotation API are [[scala.reflect.api.Symbols#Symbol.annotations]] (for definition annotations)
+ * and [[scala.reflect.api.Types#AnnotatedType]] (for type annotations).
+ *
+ * To get annotations attached to a definition, first load the corresponding symbol (either explicitly using a [[scala.reflect.api.Mirror]]
+ * such as [[scala.reflect.runtime.package#currentMirror]]
+ * or implicitly using [[scala.reflect.api.TypeTags#typeOf]] and then either acquiring its `typeSymbol` or navigating its `members`).
+ * After the symbol is loaded, call its `annotations` method.
+ *
+ * When inspecting a symbol for annotations, one should make sure that the inspected symbol is indeed the target of the annotation being looked for.
+ * Since single Scala definitions might produce multiple underlying definitions in bytecode, sometimes the notion of annotation's target is convoluted.
+ * For example, by default an annotation placed on a `val` will be attached to the private underlying field rather than to the getter
+ * (therefore to get such an annotation, one needs to do not `getter.annotations`, but `getter.asTerm.accessed.annotations`).
+ * This can get nasty with abstract vals, which don't have underlying fields and therefore ignore their annotations unless special measures are taken.
+ * See [[scala.annotation.meta.package]] for more information.
+ *
+ * To get annotations attached to a type, simply pattern match that type against [[scala.reflect.api.Types#AnnotatedType]].
+
+ * {{{
+ * import scala.reflect.runtime.universe._
+ *
+ * class S(x: Int, y: Int) extends scala.annotation.StaticAnnotation
+ * class J(x: Int, y: Int) extends scala.annotation.ClassfileAnnotation
+ *
+ * object Test extends App {
+ * val x = 2
+ *
+ * // Scala annotations are the most flexible with respect to
+ * // the richness of metadata they can store.
+ * // Arguments of such annotations are stored as abstract syntax trees,
+ * // so they can represent and persist arbitrary Scala expressions.
+ * @S(x, 2) class C
+ * val c = typeOf[C].typeSymbol
+ * println(c.annotations) // List(S(Test.this.x, 2))
+ * val tree = c.annotations(0).scalaArgs(0)
+ * println(showRaw(tree)) // Select(..., newTermName("x"))
+ * println(tree.symbol.owner) // object Test
+ * println(showRaw(c.annotations(0).scalaArgs(1))) // Literal(Constant(2))
+ *
+ * // Java annotations are limited to predefined kinds of arguments:
+ * // literals (primitives and strings), arrays and nested annotations.
+ * @J(x = 2, y = 2) class D
+ * val d = typeOf[D].typeSymbol
+ * println(d.annotations) // List(J(x = 2, y = 2))
+ * println(d.annotations(0).javaArgs) // Map(x -> 2, y -> 2)
+ * }
+ * }}}
*/
trait Annotations { self: Universe =>
- /** Typed information about an annotation. It can be attached to either a symbol or an annotated type.
- *
- * Annotations are either ''Scala annotations'', which conform to [[scala.annotation.StaticAnnotation]]
- * or ''Java annotations'', which conform to [[scala.annotation.ClassfileAnnotation]].
- * Trait `ClassfileAnnotation` is automatically added to every Java annotation by the scalac classfile parser.
- */
+ /** Information about an annotation. */
type Annotation >: Null <: AnyRef with AnnotationApi
/** A tag that preserves the identity of the `Annotation` abstract type from erasure.
@@ -21,34 +95,41 @@ trait Annotations { self: Universe =>
*/
implicit val AnnotationTag: ClassTag[Annotation]
- /** The constructor/deconstructor for `Annotation` instances. */
+ /** The constructor/deconstructor for `Annotation` instances. */
val Annotation: AnnotationExtractor
- /** An extractor class to create and pattern match with syntax `Annotation(atp, scalaArgs, javaArgs)`.
- * Here, `atp` is the annotation type, `scalaArgs` the arguments, and `javaArgs` the annotation's key-value
- * pairs.
- *
- * Annotations are pickled, i.e. written to scala symtab attribute in the classfile.
- * Annotations are written to the classfile as Java annotations if `atp` conforms to `ClassfileAnnotation`.
- *
- * For Scala annotations, arguments are stored in `scalaArgs` and `javaArgs` is empty. Arguments in
- * `scalaArgs` are represented as typed trees. Note that these trees are not transformed by any phases
- * following the type-checker. For Java annotations, `scalaArgs` is empty and arguments are stored in
- * `javaArgs`.
+ /** An extractor class to create and pattern match with syntax `Annotation(tpe, scalaArgs, javaArgs)`.
+ * Here, `tpe` is the annotation type, `scalaArgs` the payload of Scala annotations, and `javaArgs` the payload of Java annotations.
*/
abstract class AnnotationExtractor {
def apply(tpe: Type, scalaArgs: List[Tree], javaArgs: ListMap[Name, JavaArgument]): Annotation
def unapply(ann: Annotation): Option[(Type, List[Tree], ListMap[Name, JavaArgument])]
}
+ /** The API of `Annotation` instances.
+ * The main source of information about annotations is the [[scala.reflect.api.Annotations]] page.
+ */
trait AnnotationApi {
+ /** The type of the annotation. */
def tpe: Type
+
+ /** Payload of the Scala annotation: a list of abstract syntax trees that represent the argument.
+ * Empty for Java annotations.
+ */
def scalaArgs: List[Tree]
+
+ /** Payload of the Java annotation: a list of name-value pairs.
+ * Empty for Scala annotations.
+ */
def javaArgs: ListMap[Name, JavaArgument]
}
/** A Java annotation argument */
type JavaArgument >: Null <: AnyRef
+
+ /** A tag that preserves the identity of the `JavaArgument` abstract type from erasure.
+ * Can be used for pattern matching, instance tests, serialization and likes.
+ */
implicit val JavaArgumentTag: ClassTag[JavaArgument]
/** A literal argument to a Java annotation as `"Use X instead"` in `@Deprecated("Use X instead")`*/
@@ -70,7 +151,11 @@ trait Annotations { self: Universe =>
def unapply(arg: LiteralArgument): Option[Constant]
}
+ /** The API of `LiteralArgument` instances.
+ * The main source of information about annotations is the [[scala.reflect.api.Annotations]] page.
+ */
trait LiteralArgumentApi {
+ /** The underlying compile-time constant value. */
def value: Constant
}
@@ -94,7 +179,11 @@ trait Annotations { self: Universe =>
def unapply(arg: ArrayArgument): Option[Array[JavaArgument]]
}
+ /** API of `ArrayArgument` instances.
+ * The main source of information about annotations is the [[scala.reflect.api.Annotations]] page.
+ */
trait ArrayArgumentApi {
+ /** The underlying array of Java annotation arguments. */
def args: Array[JavaArgument]
}
@@ -118,7 +207,11 @@ trait Annotations { self: Universe =>
def unapply(arg: NestedArgument): Option[Annotation]
}
+ /** API of `NestedArgument` instances.
+ * The main source of information about annotations is the [[scala.reflect.api.Annotations]] page.
+ */
trait NestedArgumentApi {
+ /** The underlying nested annotation. */
def annotation: Annotation
}
} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/api/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala
index 2f201d033d..1f303877de 100644
--- a/src/reflect/scala/reflect/api/Constants.scala
+++ b/src/reflect/scala/reflect/api/Constants.scala
@@ -6,10 +6,82 @@
package scala.reflect
package api
-/**
- * Defines the type hierachy for compile-time constants.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines compile-time constants and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
*
- * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here.
+ * According to the section 6.24 "Constant Expressions" of the Scala language specification,
+ * certain expressions (dubbed ''constant expressions'') can be evaluated by the Scala compiler at compile-time.
+ *
+ * [[scala.reflect.api.Constants#Constant]] instances represent certain kinds of these expressions
+ * (with values stored in the `value` field and its strongly-typed views named `booleanValue`, `intValue` etc.), namely:
+ * 1. Literals of primitive value classes (bytes, shorts, ints, longs, floats, doubles, chars, booleans and voids).
+ * 1. String literals.
+ * 1. References to classes (typically constructed with [[scala.Predef#classOf]]).
+ * 1. References to enumeration values.
+ *
+ * Such constants are used to represent literals in abstract syntax trees (the [[scala.reflect.api.Trees#Literal]] node)
+ * and literal arguments for Java class file annotations (the [[scala.reflect.api.Annotations#LiteralArgument]] class).
+ *
+ * === Example ===
+ *
+ * The `value` field deserves some explanation. Primitive and string values are represented as themselves, whereas
+ * references to classes and enums are a bit roundabout.
+ *
+ * Class references are represented as instances of [[scala.reflect.api.Types#Type]]
+ * (because when the Scala compiler processes a class reference, the underlying runtime class might not yet have been compiled).
+ * To convert such a reference to a runtime class, one should use the `runtimeClass` method of a mirror such as [[scala.reflect.api.Mirrors#RuntimeMirror]]
+ * (the simplest way to get such a mirror is using [[scala.reflect.runtime.package#currentMirror]]).
+ *
+ * Enumeration value references are represented as instances of [[scala.reflect.api.Symbols#Symbol]], which on JVM point to methods
+ * that return underlying enum values. To inspect an underlying enumeration or to get runtime value of a reference to an enum,
+ * one should use a [[scala.reflect.api.Mirrors#RuntimeMirror]] (the simplest way to get such a mirror is again [[scala.reflect.runtime.package#currentMirror]]).
+
+ * {{{
+ * enum JavaSimpleEnumeration { FOO, BAR }
+ *
+ * import java.lang.annotation.*;
+ * @Retention(RetentionPolicy.RUNTIME)
+ * @Target({ElementType.TYPE})
+ * public @interface JavaSimpleAnnotation {
+ * Class<?> classRef();
+ * JavaSimpleEnumeration enumRef();
+ * }
+ *
+ * @JavaSimpleAnnotation(
+ * classRef = JavaAnnottee.class,
+ * enumRef = JavaSimpleEnumeration.BAR
+ * )
+ * public class JavaAnnottee {}
+ * }}}
+ * {{{
+ * import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.{currentMirror => cm}
+ *
+ * object Test extends App {
+ * val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs
+ * def jarg(name: String) = jann(newTermName(name)).asInstanceOf[LiteralArgument].value
+ *
+ * val classRef = jarg("classRef").typeValue
+ * println(showRaw(classRef)) // TypeRef(ThisType(<empty>), JavaAnnottee, List())
+ * println(cm.runtimeClass(classRef)) // class JavaAnnottee
+ *
+ * val enumRef = jarg("enumRef").symbolValue
+ * println(enumRef) // value BAR
+ *
+ * val siblings = enumRef.owner.typeSignature.declarations
+ * val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic)
+ * println(enumValues) // Scope{
+ * // final val FOO: JavaSimpleEnumeration;
+ * // final val BAR: JavaSimpleEnumeration
+ * // }
+ *
+ * // doesn't work because of https://issues.scala-lang.org/browse/SI-6459
+ * // val enumValue = mirror.reflectField(enumRef.asTerm).get
+ * val enumClass = cm.runtimeClass(enumRef.owner.asClass)
+ * val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null)
+ * println(enumValue) // BAR
+ * }
+ * }}}
*/
trait Constants {
self: Universe =>
@@ -34,8 +106,14 @@ trait Constants {
def unapply(arg: Constant): Option[Any]
}
+ /** The API of `Constant` instances.
+ * The main source of information about constants is the [[scala.reflect.api.Constants]] page.
+ */
abstract class ConstantApi {
+ /** Payload of the constant. */
val value: Any
+
+ /** Scala type that describes the constant. */
def tpe: Type
}
}
diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala
index b86f36420d..eb4c49c808 100644
--- a/src/reflect/scala/reflect/api/Exprs.scala
+++ b/src/reflect/scala/reflect/api/Exprs.scala
@@ -8,9 +8,38 @@ package api
import scala.reflect.runtime.{universe => ru}
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines strongly-typed tree wrappers and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
+ *
+ * Expr wraps an abstract syntax tree ([[scala.reflect.api.Trees#Tree]]) and tags it with its type ([[scala.reflect.api.Types#Type]]).
+ *
+ * Usually exprs are created via [[scala.reflect.api.Universe#reify]], in which case a compiler
+ * produces a [[scala.reflect.api.TreeCreator]] for the provided expression and also
+ * creates a complementary [[scala.reflect.api.TypeTags#WeakTypeTag]] that corresponds to the type of that expression.
+ *
+ * Thanks to using TreeCreators, exprs are essentially tree factories, capable of instantiating
+ * themselves in any universe and mirror. This is achieved by the `in` method, which performs
+ * migration of a given expression to another mirror. Migration means that all symbolic references
+ * to classes/objects/packages in the expression are re-resolved within the new mirror
+ * (typically using that mirror's classloader). Default universe of an expr is typically
+ * [[scala.reflect.runtime.package#universe]], default mirror is typically [[scala.reflect.runtime.package#currentMirror]].
+ *
+ * Exprs can also be created manually, but then the burden of providing a TreeCreator lies on the programmer.
+ * However, on the one hand, manual creation is very rarely needed when working with runtime reflection,
+ * while, on the other hand, compile-time reflection via macros provides an easier way to instantiate exprs,
+ * described in [[scala.reflect.macros.Aliases]].
+ *
+ * === Known issues ===
+ *
+ * Exprs are marked as serializable, but this functionality is not yet implemented.
+ * An issue tracker entry: [[https://issues.scala-lang.org/browse/SI-5919 https://issues.scala-lang.org/browse/SI-5919]]
+ * has been created to track the implementation of this feature.
+ */
trait Exprs { self: Universe =>
- /** Expr wraps an expression tree and tags it with its type. */
+ /** Expr wraps an abstract syntax tree and tags it with its type.
+ * The main source of information about exprs is the [[scala.reflect.api.Exprs]] page.
+ */
trait Expr[+T] extends Equals with Serializable {
/**
* Underlying mirror of this expr.
@@ -19,23 +48,24 @@ trait Exprs { self: Universe =>
/**
* Migrates the expression into another mirror, jumping into a different universe if necessary.
- *
- * This means that all symbolic references to classes/objects/packages in the expression
- * will be re-resolved within the new mirror (typically using that mirror's classloader).
*/
def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # Expr[T]
/**
- * The Scala syntax tree representing the wrapped expression.
+ * The Scala abstract syntax tree representing the wrapped expression.
*/
def tree: Tree
/**
- * Representation of the type of the wrapped expression tree as found via type tags.
+ * Type of the wrapped expression tree as provided during creation.
+ *
+ * When exprs are created by the compiler, `staticType` represents
+ * a statically known type of the tree as calculated at that point by the compiler.
*/
def staticType: Type
+
/**
- * Representation of the type of the wrapped expression tree as found in the tree.
+ * Type of the wrapped expression tree as found in the underlying tree.
*/
def actualType: Type
@@ -65,6 +95,7 @@ trait Exprs { self: Universe =>
* because expr of type Expr[T] itself does not have a method foo.
*/
def splice: T
+
/**
* A dummy value to denote cross-stage path-dependent type dependencies.
*
@@ -81,10 +112,16 @@ trait Exprs { self: Universe =>
*/
val value: T
- /** case class accessories */
+ /** TODO how do I doc this? */
override def canEqual(x: Any) = x.isInstanceOf[Expr[_]]
+
+ /** TODO how do I doc this? */
override def equals(x: Any) = x.isInstanceOf[Expr[_]] && this.mirror == x.asInstanceOf[Expr[_]].mirror && this.tree == x.asInstanceOf[Expr[_]].tree
+
+ /** TODO how do I doc this? */
override def hashCode = mirror.hashCode * 31 + tree.hashCode
+
+ /** TODO how do I doc this? */
override def toString = "Expr["+staticType+"]("+tree+")"
}
@@ -93,6 +130,8 @@ trait Exprs { self: Universe =>
*
* Can be useful, when having a tree and wanting to splice it in reify call,
* in which case the tree first needs to be wrapped in an expr.
+
+ * The main source of information about exprs is the [[scala.reflect.api.Exprs]] page.
*/
object Expr {
def apply[T: WeakTypeTag](mirror: scala.reflect.api.Mirror[self.type], treec: TreeCreator): Expr[T] = new ExprImpl[T](mirror.asInstanceOf[Mirror], treec)
diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala
index 3eda54b28a..bb570bebbe 100644
--- a/src/reflect/scala/reflect/api/FlagSets.scala
+++ b/src/reflect/scala/reflect/api/FlagSets.scala
@@ -3,6 +3,33 @@ package api
import scala.language.implicitConversions
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines flag sets and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
+ *
+ * Flags are used to provide modifiers for abstract syntax trees that represent definitions
+ * via the `flags` field of [[scala.reflect.api.Trees#Modifiers]]. Trees that accept modifiers are:
+ * [[scala.reflect.api.Trees#ClassDef]] (classes and traits), [[scala.reflect.api.Trees#ModuleDef]] (objects),
+ * [[scala.reflect.api.Trees#ValDef]] (vals, vars, parameters and self-type annotations),
+ * [[scala.reflect.api.Trees#DefDef]] (methods and constructors) and
+ * [[scala.reflect.api.Trees#TypeDef]] (type aliases, abstract type members and type parameters).
+ *
+ * For example, to create a class named `C` one would write `ClassDef(Modifiers(NoFlags), newTypeName("C"), Nil, ...)`.
+ * Here the flag set is empty, representing a vanilla class definition. To make `C` private, one would write
+ * `ClassDef(Modifiers(PRIVATE), newTypeName("C"), Nil, ...)`. Flags can also be combined with the vertical bar operator (`|`).
+ * For example, a private final class is written as followed: `ClassDef(Modifiers(PRIVATE | FINAL), newTypeName("C"), Nil, ...)`.
+ *
+ * The list of all available flags is defined in [[scala.reflect.api.FlagSets#FlagValues]], available via the [[scala.reflect.api.FlagSets#Flag]]
+ * (typically one writes a blanket import for that, e.g. `import scala.reflect.runtime.universe.Flag._`).
+ *
+ * Definition trees are compiled down to symbols, so flags on modifiers of such trees are transformed into flags on the resulting symbols.
+ * Unlike trees, symbols don't expose flags, but rather provide `isXXX` test methods (e.g. `isFinal` can be used to test finality). These test methods
+ * might require an upcast with `asTerm`, `asType` or `asClass` as some flags only make sense for certain flavors of symbols.
+ *
+ * === Known issues ===
+ *
+ * This API is considered to be a candidate for redesign. It is quite probable that in future releases of the reflection API
+ * flag sets will be replaced with something else.
+ */
trait FlagSets { self: Universe =>
/** An abstract type representing sets of flags (like private, final, etc.) that apply to definition trees and symbols */
@@ -13,12 +40,18 @@ trait FlagSets { self: Universe =>
*/
implicit val FlagSetTag: ClassTag[FlagSet]
+ /** The API of `FlagSet` instances.
+ * The main source of information about flag sets is the [[scala.reflect.api.FlagSets]] page.
+ */
trait FlagOps extends Any {
+ /** Produces a flag set that's a union of this flag set and the provided flag set. */
def | (right: FlagSet): FlagSet
}
+ /** The API of `FlagSet` instances. */
implicit def addFlagOps(left: FlagSet): FlagOps
+ /** A module that contains all possible values that can constitute flag sets. */
val Flag: FlagValues
// Q: I have a pretty flag. Can I put it here?
@@ -26,6 +59,9 @@ trait FlagSets { self: Universe =>
// If you want to put a flag here so that it can be tested against,
// introduce an `isXXX` method in one of the `api.Symbols` classes instead.
+ /** All possible values that can constitute flag sets.
+ * The main source of information about flag sets is the [[scala.reflect.api.FlagSets]] page.
+ */
trait FlagValues {
/** Flag indicating that tree represents a trait */
diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala
index fbc29a514e..f745c37b1d 100644
--- a/src/reflect/scala/reflect/api/Importers.scala
+++ b/src/reflect/scala/reflect/api/Importers.scala
@@ -1,21 +1,105 @@
package scala.reflect
package api
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines importers and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
+ *
+ * As described in [[scala.reflect.api.package]], reflection artifacts are contained in universes.
+ * Typically all processing happens within a single universe (e.g. a compile-time macro universe
+ * or a runtime reflection universe), but sometimes there is a need to migrate artifacts from
+ * one universe to another (e.g. runtime compilation works by importing runtime reflection trees
+ * into a runtime compiler universe, compiling the importees and exporting the result back).
+ *
+ * Reflection artifacts are firmly grounded in their universes, it is impossible
+ * to just move them around. Instead importers locate or recreate corresponding artifacts
+ * in the target universe. For example, to import `foo.bar.Baz` from the source universe to the target universe,
+ * an importer will first check whether the entire owner chain exists in the target universe.
+ * If it does, then nothing else will be done. Otherwise, the importer will recreate the entire owner chain
+ * and will import the corresponding type signaturers into the target universe.
+ *
+ * Since importers match symbol tables of the source and the target universes using plain string names,
+ * it is programmer's responsibility to make sure that imports don't distort semantics (e.g. that
+ * `foo.bar.Baz` in the source universe means the same that `foo.bar.Baz` does in the target universe).
+ *
+ * === Known issues ===
+ *
+ * Importers didn't undergo as much testing as most of the reflection API did,
+ * so they might be flaky from time to time. Please report issues if you encounter them.
+ *
+ * Importers are currently not mirror-aware, they always use `rootMirror`
+ * of the target universe to resolve symbols. This might cause troubles in cases when the target universe
+ * need a non-standard way of symbol resolution (e.g. a classloader that's different from the default one).
+ * We have created [[https://issues.scala-lang.org/browse/SI-6241 https://issues.scala-lang.org/browse/SI-6241]],
+ * an issue in the issue tracker, to track the implementation of this feature.
+ *
+ * === Example ===
+ *
+ * Here's how one might implement a macro that performs compile-time evaluation of its argument
+ * by using a runtime compiler to compile and evaluate a tree that belongs to a compile-time compiler:
+ *
+ * {{{
+ * def staticEval[T](x: T) = macro staticEval[T]
+ *
+ * def staticEval[T](c: scala.reflect.macros.Context)(x: c.Expr[T]) = {
+ * // creates a runtime reflection universe to host runtime compilation
+ * import scala.reflect.runtime.{universe => ru}
+ * val mirror = ru.runtimeMirror(c.libraryClassLoader)
+ * import scala.tools.reflect.ToolBox
+ * val toolBox = mirror.mkToolBox()
+ *
+ * // runtime reflection universe and compile-time macro universe are different
+ * // therefore an importer is needed to bridge them
+ * // currently mkImporter requires a cast to correctly assign the path-dependent types
+ * val importer0 = ru.mkImporter(c.universe)
+ * val importer = importer0.asInstanceOf[ru.Importer { val from: c.universe.type }]
+ *
+ * // the created importer is used to turn a compiler tree into a runtime compiler tree
+ * // both compilers use the same classpath, so semantics remains intact
+ * val imported = importer.importTree(tree)
+ *
+ * // after the tree is imported, it can be evaluated as usual
+ * val tree = toolBox.resetAllAttrs(imported.duplicate)
+ * val valueOfX = toolBox.eval(imported).asInstanceOf[T]
+ * ...
+ * }
+ * }}}
+ */
trait Importers { self: Universe =>
+ /** Creates an importer that moves reflection artifacts between universes. */
def mkImporter(from0: Universe): Importer { val from: from0.type }
+ /** The API of importers.
+ * The main source of information about importers is the [[scala.reflect.api.Importers]] page.
+ */
trait Importer {
+ /** The source universe of reflection artifacts that will be processed.
+ * The target universe is universe that created this importer with `mkImporter`.
+ */
val from: Universe
+ /** An importer that works in reverse direction, namely:
+ * imports reflection artifacts from the current universe to the universe specified in `from`.
+ */
val reverse: from.Importer { val from: self.type }
+ /** In the current universe, locates or creates a symbol that corresponds to the provided symbol in the source universe.
+ * If necessary imports the owner chain, companions, type signature, annotations and attachments.
+ */
def importSymbol(sym: from.Symbol): Symbol
+ /** In the current universe, locates or creates a type that corresponds to the provided type in the source universe.
+ * If necessary imports the underlying symbols, annotations, scopes and trees.
+ */
def importType(tpe: from.Type): Type
+ /** In the current universe, creates a tree that corresponds to the provided tree in the source universe.
+ * If necessary imports the underlying symbols, types and attachments.
+ */
def importTree(tree: from.Tree): Tree
+ /** In the current universe, creates a position that corresponds to the provided position in the source universe.
+ */
def importPosition(pos: from.Position): Position
}
} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/api/JavaMirrors.scala b/src/reflect/scala/reflect/api/JavaMirrors.scala
index cb0fa0f650..e1219b2dde 100644
--- a/src/reflect/scala/reflect/api/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/api/JavaMirrors.scala
@@ -1,16 +1,37 @@
package scala.reflect
package api
+/** A refinement of [[scala.reflect.api.Mirror]] for runtime reflection using JVM classloaders.
+ *
+ * With this upgrade, mirrors become capable of converting Scala reflection artifacts (symbols and types)
+ * into Java reflection artifacts (classes) and vice versa. Consequently refined mirrors
+ * become capable of performing reflective invocations (getting/settings field values, calling methods, etc).
+ *
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait JavaMirrors { self: JavaUniverse =>
+ /** In runtime reflection universes, runtime representation of a class is [[java.lang.Class]]. */
type RuntimeClass = java.lang.Class[_]
+ /** In runtime reflection universes, mirrors are JavaMirrors. */
override type Mirror >: Null <: JavaMirror
+ /** A refinement of [[scala.reflect.api.Mirror]] for runtime reflection using JVM classloaders.
+ *
+ * With this upgrade, mirrors become capable of converting Scala reflection artifacts (symbols and types)
+ * into Java reflection artifacts (classes) and vice versa. Consequently refined mirrors
+ * become capable of performing reflective invocations (getting/settings field values, calling methods, etc).
+ *
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait JavaMirror extends scala.reflect.api.Mirror[self.type] with RuntimeMirror {
val classLoader: ClassLoader
override def toString = s"JavaMirror with ${runtime.ReflectionUtils.show(classLoader)}"
}
+ /** Creates a runtime reflection mirror from a JVM classloader.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
def runtimeMirror(cl: ClassLoader): Mirror
}
diff --git a/src/reflect/scala/reflect/api/JavaUniverse.scala b/src/reflect/scala/reflect/api/JavaUniverse.scala
index 1a8a02776b..b96a6cf4f8 100644
--- a/src/reflect/scala/reflect/api/JavaUniverse.scala
+++ b/src/reflect/scala/reflect/api/JavaUniverse.scala
@@ -1,6 +1,13 @@
package scala.reflect
package api
+/** A refinement of [[scala.reflect.api.Universe]] for runtime reflection using JVM classloaders.
+ *
+ * The refinement consists of an upgrade to the mirror API, which gets extended from [[scala.reflect.api.Mirror]]
+ * to [[scala.reflect.api.JavaMirrors#JavaMirror]].
+ *
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait JavaUniverse extends Universe with JavaMirrors { self =>
override def typeTagToManifest[T: ClassTag](mirror0: Any, tag: Universe # TypeTag[T]): Manifest[T] = {
diff --git a/src/reflect/scala/reflect/api/Mirror.scala b/src/reflect/scala/reflect/api/Mirror.scala
index 2de0d7120e..281953926f 100644
--- a/src/reflect/scala/reflect/api/Mirror.scala
+++ b/src/reflect/scala/reflect/api/Mirror.scala
@@ -3,16 +3,15 @@ package api
/**
* The base interface for all mirrors.
+ * See [[scala.reflect.api.package the overview page]] for a description of mirrors and infomation on getting started with Scala reflection API.
*
- * @tparam U the type of the universe this mirror belongs to.
- *
- * This is defined outside the reflection universe cake pattern implementation
- * so that it can be referenced from outside. For example TypeCreator and TreeCreator
+ * Note. Mirror is defined outside [[scala.reflect.api.Universe the Scala reflection cake]],
+ * so that it can be referenced from outside. For example [[scala.reflect.api.TypeCreator]] and [[scala.reflect.api.TreeCreator]]
* reference Mirror and also need to be defined outside the cake as they are
* used by type tags, which can be migrated between different universes and consequently
* cannot be bound to a fixed one.
*
- * @see [[Mirrors]]
+ * @tparam U the type of the universe this mirror belongs to.
*/
abstract class Mirror[U <: Universe with Singleton] {
/** The universe this mirror belongs to. */
diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala
index bfd60dfba0..789dc42f2a 100644
--- a/src/reflect/scala/reflect/api/Mirrors.scala
+++ b/src/reflect/scala/reflect/api/Mirrors.scala
@@ -1,13 +1,8 @@
package scala.reflect
package api
-/**
- * Defines a type hierarchy for mirrors.
- *
- * Every universe has one or more mirrors. A mirror defines a hierarchy of symbols starting with the root package `_root_`
- * and provides methods to locate and define classes and singleton objects in that hierarchy.
- *
- * On the JVM, there is a one to one correspondance between class loaders and mirrors.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines mirrors and operations on them.
+ * See [[scala.reflect.api.package the overview page]] for a description of mirrors and infomation on getting started with Scala reflection API.
*/
trait Mirrors { self: Universe =>
@@ -23,19 +18,22 @@ trait Mirrors { self: Universe =>
*/
val rootMirror: Mirror
+ /** Abstracts the runtime representation of a class on the underlying platform. */
type RuntimeClass >: Null
// todo. an improvement might be having mirrors reproduce the structure of the reflection domain
// e.g. a ClassMirror could also have a list of fields, methods, constructors and so on
// read up more on the proposed design in "Reflecting Scala" by Y. Coppel
- /** A mirror that reflects a runtime value */
+ /** A mirror that reflects a runtime value.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait InstanceMirror {
/** The instance value reflected by this mirror */
def instance: Any
- /** The symbol corresponding to the run-time class of the reflected instance */
+ /** The symbol corresponding to the runtime class of the reflected instance */
def symbol: ClassSymbol
/** Reflects against a field symbol and returns a mirror
@@ -103,7 +101,9 @@ trait Mirrors { self: Universe =>
def reflectModule(mod: ModuleSymbol): ModuleMirror
}
- /** A mirror that reflects a field */
+ /** A mirror that reflects a field.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait FieldMirror {
/** The object containing the field */
@@ -145,7 +145,9 @@ trait Mirrors { self: Universe =>
def set(value: Any): Unit
}
- /** A mirror that reflects a method handle */
+ /** A mirror that reflects a method.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait MethodMirror {
/** The receiver object of the method */
@@ -163,7 +165,9 @@ trait Mirrors { self: Universe =>
def apply(args: Any*): Any
}
- /** A mirror that reflects the instance or static parts of a runtime class */
+ /** A mirror that reflects the instance or static parts of a runtime class.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait TemplateMirror {
/** True if the mirror represents the static part
@@ -179,7 +183,9 @@ trait Mirrors { self: Universe =>
def symbol: Symbol
}
- /** A mirror that reflects a Scala object definition or the static parts of a runtime class */
+ /** A mirror that reflects a Scala object definition or the static parts of a runtime class.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait ModuleMirror extends TemplateMirror {
/** The Scala module symbol corresponding to the reflected object */
@@ -192,7 +198,9 @@ trait Mirrors { self: Universe =>
def instance: Any
}
- /** A mirror that reflects the instance parts of a runtime class */
+ /** A mirror that reflects the instance parts of a runtime class.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait ClassMirror extends TemplateMirror {
/** The Scala class symbol corresponding to the reflected class */
@@ -211,7 +219,9 @@ trait Mirrors { self: Universe =>
def reflectConstructor(constructor: MethodSymbol): MethodMirror
}
- /** A mirror that reflects instances and static classes */
+ /** A mirror that reflects instances and static classes.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait ReflectiveMirror extends scala.reflect.api.Mirror[Mirrors.this.type] {
/** A reflective mirror for the given object.
@@ -246,7 +256,9 @@ trait Mirrors { self: Universe =>
def reflectModule(mod: ModuleSymbol): ModuleMirror
}
- /** The API of a mirror for a reflective universe */
+ /** The API of a mirror for a reflective universe.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
+ */
trait RuntimeMirror extends ReflectiveMirror { self =>
/** Maps a Scala type to the corresponding Java class object */
diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala
index 6cb226c32f..c1de49a475 100644
--- a/src/reflect/scala/reflect/api/Names.scala
+++ b/src/reflect/scala/reflect/api/Names.scala
@@ -1,41 +1,70 @@
package scala.reflect
package api
-/** A trait that manages names.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines names and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
*
- * @see TermName
- * @see TypeName
+ * Scala has separate namespaces for term names and type names. For example it is possible to have
+ * a class named `C` and an object named `C` declared in the same lexical scope.
+ *
+ * Therefore the Scala reflection API models names using strongly-typed objects rather than strings:
+ * [[scala.reflect.api.Names#TermName]] and [[scala.reflect.api.Names#TypeName]].
+ *
+ * A Name wraps a string as the name for either a type ([[TypeName]]) of a term ([[TermName]]).
+ * Two names are equal, if the wrapped string are equal and they are either both `TypeName` or both `TermName`.
+ * The same string can co-exist as a `TypeName` and a `TermName`, but they would not be equal.
+ * Names are interned. That is, for two names `name1` and `name2`, `name1 == name2` implies `name1 eq name2`.
+ * Name instances also can perform mangling and unmangling of symbolic names.
+ *
+ * === Examples ===
+ *
+ * To search for the `map` method declared in the `List` class, one uses
+ * `typeOf[List[_]].member(newTermName("map"))` to explicitly specify that a term is looked up.
+ *
+ * An alternative notation makes use of implicit conversions from `String` to `TermName` and `TypeName`:
+ * `typeOf[List[_]].member("map": TermName)`. Note that there's no implicit conversion from `String` to `Name`,
+ * because it would be unclear whether such a conversion should produce a term name or a type name.
+ *
+ * Finally some names that bear special meaning for the compiler are defined in [[scala.reflect.api.StandardNames]].
+ * For example, `WILDCARD` represents `_` and `CONSTRUCTOR` represents the standard JVM name for constructors, `<init>`.
+ * Prefer using such constants instead of spelling the names out explicitly.
*/
trait Names {
- // Intentionally no implicit from String => Name.
+ /** An implicit conversion from String to TermName.
+ * Enables an alternative notation `"map": TermName` as opposed to `newTermName("map")`.
+ */
implicit def stringToTermName(s: String): TermName = newTermName(s)
- implicit def stringToTypeName(s: String): TypeName = newTypeName(s)
- /**
- * The abstract type of names
- *
- * A Name wraps a string as the name for either a type ([[TypeName]]) of a term ([[TermName]]).
- * Two names are equal, if the wrapped string are equal and they are either both `TypeName` or both `TermName`.
- * The same string can co-exist as a `TypeName` and a `TermName`, but they would not be equal.
- * Names are interned. That is, for two names `name11 and `name2`,
- * `name1 == name2` implies `name1 eq name2`.
- *
- * One of the reasons for the existence of names rather than plain strings is being more explicit about what is a name and if it represents a type or a term.
+ /** An implicit conversion from String to TypeName.
+ * Enables an alternative notation `"List": TypeName` as opposed to `newTypeName("List")`.
*/
+ implicit def stringToTypeName(s: String): TypeName = newTypeName(s)
+
+ /** The abstract type of names. */
type Name >: Null <: NameApi
+
+ /** A tag that preserves the identity of the `Name` abstract type from erasure.
+ * Can be used for pattern matching, instance tests, serialization and likes.
+ */
implicit val NameTag: ClassTag[Name]
- /** The abstract type of names representing terms */
+ /** The abstract type of names representing terms. */
type TypeName >: Null <: Name
+
+ /** A tag that preserves the identity of the `TypeName` abstract type from erasure.
+ * Can be used for pattern matching, instance tests, serialization and likes.
+ */
implicit val TypeNameTag: ClassTag[TypeName]
- /** The abstract type of names representing types */
+ /** The abstract type of names representing types. */
type TermName >: Null <: Name
- implicit val TermNameTag: ClassTag[TermName]
- /** The API of names that's supported on reflect mirror via an
- * implicit conversion in reflect.ops
+ /** A tag that preserves the identity of the `TermName` abstract type from erasure.
+ * Can be used for pattern matching, instance tests, serialization and likes.
*/
+ implicit val TermNameTag: ClassTag[TermName]
+
+ /** The API of Name instances. */
abstract class NameApi {
/** Checks wether the name is a a term name */
def isTermName: Boolean
diff --git a/src/reflect/scala/reflect/api/Position.scala b/src/reflect/scala/reflect/api/Position.scala
index d3dc9c884f..9a6c166845 100644
--- a/src/reflect/scala/reflect/api/Position.scala
+++ b/src/reflect/scala/reflect/api/Position.scala
@@ -3,52 +3,59 @@ package api
import scala.reflect.macros.Attachments
-/** The Position class and its subclasses represent positions of ASTs and symbols.
- * Except for NoPosition and FakePos, every position refers to a SourceFile
- * and to an offset in the sourcefile (its `point`). For batch compilation,
- * that's all. For interactive IDE's there are also RangePositions
- * and TransparentPositions. A RangePosition indicates a start and an end
- * in addition to its point. TransparentPositions are a subclass of RangePositions.
+/** Position instances represent positions of ASTs and symbols.
+ *
+ * === Position in runtime reflection ===
+ *
+ * Except for [[scala.reflect.api.Positions#NoPosition], every position refers to a source file (`source`)
+ * and to an offset in the sourcefile (its `point`).
+ *
+ * === Positions in compile-time reflection ===
+ *
+ * For interactive IDE's there are also range positions
+ * and transparent positions. A range position indicates a `start` and an `end`
+ * in addition to its point. Transparent positions subclass range positions.
* Range positions that are not transparent are called opaque.
* Trees with RangePositions need to satisfy the following invariants.
*
- * INV1: A tree with an offset position never contains a child
+ * - INV1: A tree with an offset position never contains a child
* with a range position
- * INV2: If the child of a tree with a range position also has a range position,
+ * - INV2: If the child of a tree with a range position also has a range position,
* then the child's range is contained in the parent's range.
- * INV3: Opaque range positions of children of the same node are non-overlapping
+ * - INV3: Opaque range positions of children of the same node are non-overlapping
* (this means their overlap is at most a single point).
*
* The following tests are useful on positions:
- *
- * pos.isDefined true if position is not a NoPosition nor a FakePosition
- * pos.isRange true if position is a range
- * pos.isOpaqueRange true if position is an opaque range
- *
- * The following accessor methods are provided:
- *
- * pos.source The source file of the position, which must be defined
- * pos.point The offset of the position's point, which must be defined
- * pos.start The start of the position, which must be a range
- * pos.end The end of the position, which must be a range
+ * `pos.isDefined` true if position is not a NoPosition,
+ * `pos.isRange` true if position is a range,
+ * `pos.isOpaqueRange` true if position is an opaque range,
*
* There are also convenience methods, such as
- *
- * pos.startOrPoint
- * pos.endOrPoint
- * pos.pointOrElse(default)
- *
+ * `pos.startOrPoint`,
+ * `pos.endOrPoint`,
+ * `pos.pointOrElse(default)`.
* These are less strict about the kind of position on which they can be applied.
*
* The following conversion methods are often used:
+ * `pos.focus` converts a range position to an offset position, keeping its point;
+ * returns all other positions unchanged,
+ * `pos.makeTransparent` converts an opaque range position into a transparent one.
+ * returns all other positions unchanged.
+ *
+ * === Known issues ===
+ *
+ * As it currently stands, positions cannot be created by a programmer - they only get emitted by the compiler
+ * and can only be reused in compile-time macro universes.
+ *
+ * Also positions are neither pickled (i.e. saved for runtime reflection using standard means of scalac) nor
+ * reified (i.e. saved for runtime reflection using the [[scala.reflect.api.Universe#reify]] macro).
*
- * pos.focus converts a range position to an offset position, keeping its point;
- * returns all other positions unchanged.
- * pos.makeTransparent converts an opaque range position into a transparent one.
- * returns all other positions unchanged.
+ * This API is considered to be a candidate for redesign. It is quite probable that in future releases of the reflection API
+ * positions will undergo a dramatic rehash.
*/
trait Position extends Attachments {
+ /** @inheritdoc */
type Pos >: Null <: Position
/** Java file corresponding to the source file of this position.
diff --git a/src/reflect/scala/reflect/api/Positions.scala b/src/reflect/scala/reflect/api/Positions.scala
index 5c530e7e70..a47dc00f3d 100644
--- a/src/reflect/scala/reflect/api/Positions.scala
+++ b/src/reflect/scala/reflect/api/Positions.scala
@@ -1,15 +1,17 @@
package scala.reflect
package api
-/**
- * Defines the type hierachy for positions.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines positions and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
*
- * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here.
+ * The main documentation entry about positions is located at [[scala.reflect.api.Position]].
*/
trait Positions {
self: Universe =>
- /** .. */
+ /** Defines a universe-specific notion of positions.
+ * The main documentation entry about positions is located at [[scala.reflect.api.Position]].
+ */
type Position >: Null <: scala.reflect.api.Position { type Pos = Position }
/** A tag that preserves the identity of the `Position` abstract type from erasure.
diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala
index 72a9bf8f3d..831c4ae331 100644
--- a/src/reflect/scala/reflect/api/Printers.scala
+++ b/src/reflect/scala/reflect/api/Printers.scala
@@ -3,6 +3,132 @@ package api
import java.io.{ PrintWriter, StringWriter }
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines prettyprinting functionality.
+ *
+ * === Examples (trees) ===
+ *
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> def tree = reify{ final class C { def x = 2 } }.tree
+ * tree: reflect.runtime.universe.Tree
+ *
+ * // show displays prettified representation of reflection artifacts
+ * // which is typically close to Scala code, but sometimes not quite
+ * // (e.g. here the constructor is shown in a desugared way)
+ * scala> show(tree)
+ * res0: String =
+ * {
+ * final class C extends AnyRef {
+ * def <init>() = {
+ * super.<init>();
+ * ()
+ * };
+ * def x = 2
+ * };
+ * ()
+ * }
+ *
+ * // showRaw displays internal structure of a given reflection object
+ * // trees and types (type examples are shown below) are case classes
+ * // so they are shown in a form that's almost copy/pasteable
+ * //
+ * // almost copy/pasteable, but not completely - that's because of symbols
+ * // there's no good way to get a roundtrip-surviving representation of symbols
+ * // in general case, therefore only symbol names are shown (e.g. take a look at AnyRef)
+ * //
+ * // in such a representation, it's impossible to distinguish Idents/Selects
+ * // that have underlying symbols vs ones that don't have symbols, because in both cases
+ * // only names will be printed
+ * //
+ * // to overcome this limitation, use `printIds` and `printKinds` - optional parameters
+ * // of the `showRaw` method (an example is shown below)
+ * scala> showRaw(tree)
+ * res1: String = Block(List(
+ * ClassDef(Modifiers(FINAL), newTypeName("C"), List(), Template(
+ * List(Ident(newTypeName("AnyRef"))),
+ * emptyValDef,
+ * List(
+ * DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(),
+ * Block(List(
+ * Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())),
+ * Literal(Constant(())))),
+ * DefDef(Modifiers(), newTermName("x"), List(), List(), TypeTree(),
+ * Literal(Constant(2))))))),
+ * Literal(Constant(())))
+ *
+ * scala> import scala.tools.reflect.ToolBox // requires scala-compiler.jar
+ * import scala.tools.reflect.ToolBox
+ *
+ * scala> import scala.reflect.runtime.{currentMirror => cm}
+ * import scala.reflect.runtime.{currentMirror=>cm}
+ *
+ * // showRaw can also print types next to the artifacts being inspected
+ * // provide true for a `printTypes` arguments to achieve this effect
+ * scala> showRaw(cm.mkToolBox().typeCheck(tree), printTypes = true)
+ * res2: String = Block[1](List(
+ * ClassDef[2](Modifiers(FINAL), newTypeName("C"), List(), Template[3](
+ * List(Ident[4](newTypeName("AnyRef"))),
+ * emptyValDef,
+ * List(
+ * DefDef[2](Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree[3](),
+ * Block[1](List(
+ * Apply[4](Select[5](Super[6](This[3](newTypeName("C")), tpnme.EMPTY), ...))),
+ * Literal[1](Constant(())))),
+ * DefDef[2](Modifiers(), newTermName("x"), List(), List(), TypeTree[7](),
+ * Literal[8](Constant(2))))))),
+ * Literal[1](Constant(())))
+ * [1] TypeRef(ThisType(scala), scala.Unit, List())
+ * [2] NoType
+ * [3] TypeRef(NoPrefix, newTypeName("C"), List())
+ * [4] TypeRef(ThisType(java.lang), java.lang.Object, List())
+ * [5] MethodType(List(), TypeRef(ThisType(java.lang), java.lang.Object, List()))
+ * [6] SuperType(ThisType(newTypeName("C")), TypeRef(... java.lang.Object ...))
+ * [7] TypeRef(ThisType(scala), scala.Int, List())
+ * [8] ConstantType(Constant(2))
+ * }}}
+ *
+ * === Examples (types) ===
+ *
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> def tpe = typeOf[{ def x: Int; val y: List[Int] }]
+ * tpe: reflect.runtime.universe.Type
+ *
+ * // show has already been discussed above
+ * scala> show(tpe)
+ * res0: String = scala.AnyRef{def x: Int; val y: scala.List[Int]}
+ *
+ * // showRaw has already been discussed above
+ * scala> showRaw(tpe)
+ * res1: String = RefinedType(
+ * List(TypeRef(ThisType(scala), newTypeName("AnyRef"), List())),
+ * Scope(
+ * newTermName("x"),
+ * newTermName("y")))
+ *
+ * // when `printIds` and/or `printKinds` arguments are provided for showRaw
+ * // the prettyprinter reveals underlying symbols and their flavors
+ * //
+ * // courtesy of `printKinds` we can see four different symbols: a package class `scala`,
+ * // a type alias `AnyRef`, a method named `x` and a getter named `y`.
+ * //
+ * // thanks to `printIds` we can see unique identifiers of symbols
+ * // so that it becomes possible to distinguish, say, `scala.collection.immutable.List`
+ * // from `scala.collection.mutable.List` (this also helps in rare cases
+ * // when the same reflection entity is represented by multiple symbols, but let's
+ * // not speak of these horrors here)
+ * scala> showRaw(tpe, printIds = true, printKinds = true)
+ * res2: String = RefinedType(
+ * List(TypeRef(ThisType(scala#2043#PK), newTypeName("AnyRef")#691#TPE, List())),
+ * Scope(
+ * newTermName("x")#2540#METH,
+ * newTermName("y")#2541#GET))
+ * }}}
+ */
trait Printers { self: Universe =>
protected trait TreePrinter {
diff --git a/src/reflect/scala/reflect/api/Scopes.scala b/src/reflect/scala/reflect/api/Scopes.scala
index 770349c5b5..e0142470e5 100644
--- a/src/reflect/scala/reflect/api/Scopes.scala
+++ b/src/reflect/scala/reflect/api/Scopes.scala
@@ -1,16 +1,24 @@
package scala.reflect
package api
-/**
- * Defines the type hierachy for scopes.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines scopes and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
*
- * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here.
+ * A scope object generally maps names to symbols available in some lexical scope.
+ * Scopes can be nested. The base type exposed to the reflection API, however,
+ * only exposes a minimal interface, representing a scope as an iterable of symbols.
+ *
+ * For rare occasions when it is necessary to create a scope manually,
+ * e.g. to populate members of [[scala.reflect.api.Types#RefinedType]],
+ * there is the `newScopeWith` function.
+ *
+ * Additional functionality is exposed in member scopes that are returned by
+ * `members` and `declarations` defined in [[scala.reflect.api.Types#TypeApi]].
+ * Such scopes support the `sorted` method, which sorts members in declaration order.
*/
trait Scopes { self: Universe =>
- /** The base type of all scopes. A scope object generally maps names to symbols available in the current lexical scope.
- * Scopes can be nested. This base type, however, only exposes a minimal interface, representing a scope as an iterable of symbols.
- */
+ /** The base type of all scopes. */
type Scope >: Null <: ScopeApi
/** The API that all scopes support */
diff --git a/src/reflect/scala/reflect/api/StandardDefinitions.scala b/src/reflect/scala/reflect/api/StandardDefinitions.scala
index 7197542370..cca9440302 100644
--- a/src/reflect/scala/reflect/api/StandardDefinitions.scala
+++ b/src/reflect/scala/reflect/api/StandardDefinitions.scala
@@ -5,128 +5,298 @@
package scala.reflect
package api
-/**
- * Defines standard symbols and types.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines standard symbols and types.
+ *
+ * These standard reflection artifacts can be referred to using `definitions` (typically imported with
+ * a blanket import `import definitions._`) and are listed in [[scala.reflect.api.StandardDefinitions#DefinitionsApi]].
*/
trait StandardDefinitions {
self: Universe =>
- /** A value containing all standard defnitions. */
+ /** A value containing all standard definitions. */
val definitions: DefinitionsApi
/** Defines standard symbols (and types via its base trait). */
trait DefinitionsApi extends StandardTypes {
- /** The class symbol of package `scala`. */
+ /** The module class symbol of package `scala`. */
def ScalaPackageClass: ClassSymbol
- /** The module class symbol of package `scala`. */
+ /** The module symbol of package `scala`. */
def ScalaPackage: ModuleSymbol
- // top types
+ /** The class symbol of core class `scala.Any`. */
def AnyClass : ClassSymbol
+
+ /** The class symbol of core class `scala.AnyVal`. */
def AnyValClass: ClassSymbol
+
+ /** The class symbol of core class `java.lang.Object`. */
def ObjectClass: ClassSymbol
+
+ /** The type symbol of core class `scala.AnyRef`. */
def AnyRefClass: TypeSymbol
- // bottom types
+ /** The class symbol of core class `scala.Null`. */
def NullClass : ClassSymbol
+
+ /** The class symbol of core class `scala.Nothing`. */
def NothingClass: ClassSymbol
- // the scala value classes
+ /** The class symbol of primitive class `scala.Unit`. */
def UnitClass : ClassSymbol
+
+ /** The class symbol of primitive class `scala.Byte`. */
def ByteClass : ClassSymbol
+
+ /** The class symbol of primitive class `scala.Short`. */
def ShortClass : ClassSymbol
+
+ /** The class symbol of primitive class `scala.Char`. */
def CharClass : ClassSymbol
+
+ /** The class symbol of primitive class `scala.Int`. */
def IntClass : ClassSymbol
+
+ /** The class symbol of primitive class `scala.Long`. */
def LongClass : ClassSymbol
+
+ /** The class symbol of primitive class `scala.Float`. */
def FloatClass : ClassSymbol
+
+ /** The class symbol of primitive class `scala.Double`. */
def DoubleClass : ClassSymbol
+
+ /** The class symbol of primitive class `scala.Boolean`. */
def BooleanClass: ClassSymbol
- /** The class symbol of class `String`. */
+ /** The class symbol of class `scala.String`. */
def StringClass : ClassSymbol
- /** The class symbol of class `Class`. */
+ /** The class symbol of class `java.lang.Class`. */
def ClassClass : ClassSymbol
- /** The class symbol of class `Array`. */
+ /** The class symbol of class `scala.Array`. */
def ArrayClass : ClassSymbol
- /** The class symbol of class `List`. */
+ /** The class symbol of class `scala.List`. */
def ListClass : ClassSymbol
- /** The module symbol of `scala.Predef`. */
+ /** The module symbol of module `scala.Predef`. */
def PredefModule: ModuleSymbol
+ /** The module class symbol of package `java.lang`. */
def JavaLangPackageClass: ClassSymbol
+
+ /** The module symbol of package `java.lang`. */
def JavaLangPackage: ModuleSymbol
+
+ /** The module symbol of module `scala.Array`. */
def ArrayModule: ModuleSymbol
+
+ /** The method symbol of method `apply` in module `scala.Array`. */
def ArrayModule_overloadedApply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+
+ /** The method symbol of method `apply` in class `scala.Array`. */
def Array_apply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+
+ /** The method symbol of method `clone` in class `scala.Array`. */
def Array_clone: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+
+ /** The method symbol of method `length` in class `scala.Array`. */
def Array_length: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+
+ /** The method symbol of method `update` in class `scala.Array`. */
def Array_update: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+
+ /** A dummy class symbol that is used to indicate by-name parameters.
+ *
+ * {{{
+ * scala> class C { def m(x: => Int) = ??? }
+ * defined class C
+ *
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> val m = typeOf[C].member(newTermName("m")).asMethod
+ * m: reflect.runtime.universe.MethodSymbol = method m
+ *
+ * scala> m.params(0)(0).typeSignature
+ * res1: reflect.runtime.universe.Type = => scala.Int
+ *
+ * scala> showRaw(m.params(0)(0).typeSignature)
+ * res2: String = TypeRef(
+ * ThisType(scala),
+ * scala.<byname>, // <-- ByNameParamClass
+ * List(TypeRef(ThisType(scala), scala.Int, List())))
+ * }}}
+ */
def ByNameParamClass: ClassSymbol
- def FunctionClass : Array[ClassSymbol]
+
+ /** A dummy class symbol that is used to indicate repeated parameters
+ * compiled by the Java compiler.
+ *
+ * {{{
+ * class C {
+ * public void m(Object... x) {}
+ * }
+ * }}}
+ *
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> val m = typeOf[C].member(newTermName("m")).asMethod
+ * m: reflect.runtime.universe.MethodSymbol = method m
+ *
+ * scala> m.params(0)(0).typeSignature
+ * res1: reflect.runtime.universe.Type = <repeated...>[Object]
+ *
+ * scala> showRaw(m.params(0)(0).typeSignature)
+ * res2: String = TypeRef(
+ * ThisType(scala),
+ * scala.<repeated...>, // <-- JavaRepeatedParamClass
+ * List(TypeRef(ThisType(java.lang), Object, List())))
+ * }}}
+ */
def JavaRepeatedParamClass: ClassSymbol
+
+ /** A dummy class symbol that is used to indicate repeated parameters
+ * compiled by the Scala compiler.
+ *
+ * {{{
+ * scala> class C { def m(x: Int*) = ??? }
+ * defined class C
+ *
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> val m = typeOf[C].member(newTermName("m")).asMethod
+ * m: reflect.runtime.universe.MethodSymbol = method m
+ *
+ * scala> m.params(0)(0).typeSignature
+ * res1: reflect.runtime.universe.Type = scala.Int*
+ *
+ * scala> showRaw(m.params(0)(0).typeSignature)
+ * res2: String = TypeRef(
+ * ThisType(scala),
+ * scala.<repeated>, // <-- RepeatedParamClass
+ * List(TypeRef(ThisType(scala), scala.Int, List())))
+ * }}}
+ */
+ def RepeatedParamClass: ClassSymbol
+
+ /** The module symbol of module `scala.List`. */
def ListModule: ModuleSymbol
+
+ /** The method symbol of method `apply` in class `scala.List`. */
def List_apply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+
+ /** The module symbol of module `scala.collection.immutable.Nil`. */
def NilModule: ModuleSymbol
- def NoneModule: ModuleSymbol
+
+ /** The class symbol of class `scala.Option`. */
def OptionClass: ClassSymbol
- def ProductClass : Array[ClassSymbol]
- def RepeatedParamClass: ClassSymbol
+
+ /** The module symbol of module `scala.None`. */
+ def NoneModule: ModuleSymbol
+
+ /** The module symbol of module `scala.Some`. */
def SomeModule: ModuleSymbol
+
+ /** The array of class symbols for classes `scala.ProductX`.
+ * - 0th element is `Unit`
+ * - 1st element is `Product1`
+ * - ...
+ * - 22nd element is `Product22`
+ */
+ def ProductClass : Array[ClassSymbol]
+
+ /** The array of class symbols for classes `scala.FunctionX`.
+ * - 0th element is `Function0`
+ * - 1st element is `Function1`
+ * - ...
+ * - 22nd element is `Function22`
+ */
+ def FunctionClass : Array[ClassSymbol]
+
+ /** The array of class symbols for classes `scala.TupleX`.
+ * - 0th element is `NoSymbol`
+ * - 1st element is `Product1`
+ * - ...
+ * - 22nd element is `Product22`
+ */
def TupleClass: Array[Symbol] // cannot make it Array[ClassSymbol], because TupleClass(0) is supposed to be NoSymbol. weird
+
+ /** Contains Scala primitive value classes:
+ * - Byte
+ * - Short
+ * - Int
+ * - Long
+ * - Float
+ * - Double
+ * - Char
+ * - Boolean
+ * - Unit
+ */
def ScalaPrimitiveValueClasses: List[ClassSymbol]
+
+ /** Contains Scala numeric value classes:
+ * - Byte
+ * - Short
+ * - Int
+ * - Long
+ * - Float
+ * - Double
+ * - Char
+ */
def ScalaNumericValueClasses: List[ClassSymbol]
}
/** Defines standard types. */
trait StandardTypes {
- /** The `Type` of type `Unit`. */
+ /** The type of primitive type `Unit`. */
val UnitTpe: Type
- /** The `Type` of primitive type `Byte`. */
+ /** The type of primitive type `Byte`. */
val ByteTpe: Type
- /** The `Type` of primitive type `Short`. */
+ /** The type of primitive type `Short`. */
val ShortTpe: Type
- /** The `Type` of primitive type `Char`. */
+ /** The type of primitive type `Char`. */
val CharTpe: Type
- /** The `Type` of primitive type `Int`. */
+ /** The type of primitive type `Int`. */
val IntTpe: Type
- /** The `Type` of primitive type `Long`. */
+ /** The type of primitive type `Long`. */
val LongTpe: Type
- /** The `Type` of primitive type `Float`. */
+ /** The type of primitive type `Float`. */
val FloatTpe: Type
- /** The `Type` of primitive type `Double`. */
+ /** The type of primitive type `Double`. */
val DoubleTpe: Type
- /** The `Type` of primitive type `Boolean`. */
+ /** The type of primitive type `Boolean`. */
val BooleanTpe: Type
- /** The `Type` of type `Any`. */
+ /** The type of core type `Any`. */
val AnyTpe: Type
- /** The `Type` of type `AnyVal`. */
+ /** The type of core type `AnyVal`. */
val AnyValTpe: Type
- /** The `Type` of type `AnyRef`. */
+ /** The type of core type `AnyRef`. */
val AnyRefTpe: Type
- /** The `Type` of type `Object`. */
+ /** The type of core type `Object`. */
val ObjectTpe: Type
- /** The `Type` of type `Nothing`. */
+ /** The type of core type `Nothing`. */
val NothingTpe: Type
- /** The `Type` of type `Null`. */
+ /** The type of core type `Null`. */
val NullTpe: Type
}
}
diff --git a/src/reflect/scala/reflect/api/StandardNames.scala b/src/reflect/scala/reflect/api/StandardNames.scala
index 36ba840c84..8029450ca0 100644
--- a/src/reflect/scala/reflect/api/StandardNames.scala
+++ b/src/reflect/scala/reflect/api/StandardNames.scala
@@ -10,33 +10,82 @@ package api
// Is it necessary to perform reflection (like ERROR or LOCAL_SUFFIX_STRING)? If yes, then sure.
// Otherwise you'd better not - reflection API should stay minimalistic.
-// TODO: document better
-/**
- * Names necessary to create Scala trees.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines standard names.
+ *
+ * Standard names are names that are essential to creating trees or to reflecting Scala artifacts.
+ * For example, `CONSTRUCTOR` (aka `<init>` on JVM) is necessary to create and invoke constructors.
+ *
+ * These standard names can be referred to using `nme` for term names (listed in [[scala.reflect.api.StandardNames#TermNamesApi]])
+ * and using `tpnme` for type names (listed in [[scala.reflect.api.StandardNames#TypeNamesApi]])
*/
trait StandardNames {
self: Universe =>
+ /** A value containing all standard term names. */
val nme: TermNamesApi
+
+ /** A value containing all standard type names. */
val tpnme: TypeNamesApi
+ /** Defines standard names, common for term and type names. */
trait NamesApi {
+ /** An abstract type that represents the exact flavor of the name. */
type NameType >: Null <: Name
+
+ /** The term or type name `_`.
+ * Used to construct trees that correspond to underscores in Scala.
+ */
val WILDCARD: NameType
+
+ /** The term or type name corresponding to an empty string.
+ * Represents an empty name, used to denote the fact that no name was specified
+ * for `privateWithin` in [[scala.reflect.api.Trees#Modifiers]], for [[scala.reflect.api.Trees#This]],
+ * for [[scala.reflect.api.Trees#Super]], etc.
+ */
val EMPTY: NameType
+
+ /** The term or type name `<error>`.
+ * Indicates that the enclosing tree or symbol contains a compilation error.
+ */
val ERROR: NameType
+
+ /** The term or type name `package`.
+ * Used to get modules representing package objects.
+ */
val PACKAGE: NameType
}
+ /** Defines standard term names. */
trait TermNamesApi extends NamesApi {
+ /** @inheritdoc */
type NameType = TermName
+
+ /** The term name `<init>`.
+ * Represents the constructor name on the JVM.
+ */
val CONSTRUCTOR: NameType
+
+ /** The term name `_root_`.
+ * Represents the root package.
+ */
val ROOTPKG: NameType
+
+ /** The string " " (a single whitespace).
+ * `LOCAL_SUFFIX_STRING` is appended to the names of local identifiers,
+ * when it's necessary to prevent a naming conflict. For example, underlying fields
+ * of non-private vals and vars are renamed using `LOCAL_SUFFIX_STRING`.
+ */
val LOCAL_SUFFIX_STRING: String
}
+ /** Defines standard type names. */
trait TypeNamesApi extends NamesApi {
+ /** @inheritdoc */
type NameType = TypeName
+
+ /** The type name `_*`.
+ * Used to construct types that specify sequence arguments to repeated parameters.
+ */
val WILDCARD_STAR: NameType
}
}
diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala
index e456428338..371e20cdd4 100644
--- a/src/reflect/scala/reflect/api/Symbols.scala
+++ b/src/reflect/scala/reflect/api/Symbols.scala
@@ -1,10 +1,206 @@
package scala.reflect
package api
-/**
- * Defines the type hierachy for symbols
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines symbols and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
*
- * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here.
+ * === Symbols from a compile-time perspective ===
+ *
+ * [[http://dcsobral.blogspot.ch/2012/08/json-serialization-with-reflection-in.html To quote Daniel Sobral]],
+ * anything you define in Scala has a symbol. If you give something a name,
+ * then it has a symbol associated with it. If you didn't give it a name, but you could have, then it has a symbol.
+ *
+ * Symbols are used by the Scala compiler to establish bindings. When typechecking a Scala program,
+ * the compiler populates [[scala.reflect.api.Trees#RefTrees ref trees]], such as [[scala.reflect.api.Trees#Ident Ident]]
+ * (references to identifiers) and [[scala.reflect.api.Trees#Select Select]] (references to members)
+ * with symbols that represent the declarations being referred to. Populating means setting the `symbol`
+ * field to a non-empty value.
+ *
+ * Here's an example of how trees look after the `typer` phase of the Scala compiler (this phase performs the typechecking).
+ * {{{
+ * >cat Test.scala
+ * def foo[T: TypeTag](x: Any) = x.asInstanceOf[T]
+ *
+ * >scalac -Xprint:typer -uniqid Test.scala
+ * [[syntax trees at end of typer]]// Scala source: Test.scala
+ * def foo#8339
+ * [T#8340 >: Nothing#4658 <: Any#4657]
+ * (x#9529: Any#4657)
+ * (implicit evidence$1#9530: TypeTag#7861[T#8341])
+ * : T#8340 =
+ * x#9529.asInstanceOf#6023[T#8341];
+ * }}}
+ *
+ * Shortly put, we write a small snippet and then compile it with scalac, asking the compiler to dump the trees
+ * after the typer phase, printing unique ids of the symbols assigned to trees (if any).
+ *
+ * The resulting printout shows that identifiers have been linked to corresponding definitions.
+ * For example, on the one hand, the `ValDef("x", ...)`, which represents the parameter of the method `foo`,
+ * defines a method symbol with `id=9529`. On the other hand, the `Ident("x")` in the body of the method
+ * got its `symbol` field set to the same symbol, which establishes the binding.
+ *
+ * In the light of this discussion, it might come as a surprise that the definition of the type parameter `T`
+ * has a symbol with `id=8340`, whereas references to this type parameter all have a symbol with `id=8341`.
+ * This is the only exception from the general principe outlined above. It happens because the Scala compiler
+ * skolemizes type parameters (creates new symbols very similar to the original ones) before entering scopes
+ * that define these parameters. This is an advanced feature of Scala, and the knowledge of it is needed only
+ * when writing complex macros, but symbols in the macro universe [[scala.reflect.macros.Universe]] have the
+ * `deskolemize` method, which goes back from skolems to the originating type parameters.
+ *
+ * === Symbols from a runtime perspective ===
+ *
+ * From the point of view of a runtime reflection framework, symbols are akin to [[java.lang.reflect.Member]] from Java
+ * and [[System.Reflection.MemberInfo]] from .NET. But not only they represent members - they also represent
+ * classes, objects and even packages.
+ *
+ * Also similarly to the base classes in the reflection facilities of JVM and .NET, Scala symbols have subclasses
+ * that describe particular flavors of definitions. [[scala.reflect.api.Symbols#TermSymbol]] models term definitions
+ * (such as lazy and eager vals, vars and parameters of methods). Its subclasses are [[scala.reflect.api.Symbols#MethodSymbol]]
+ * and [[scala.reflect.api.Symbols#ModuleSymbol]] (representing "modules", which in Scala compiler speak mean "objects").
+ * [[scala.reflect.api.Symbols#TypeSymbol]] along with its subclass [[scala.reflect.api.Symbols#ClassSymbol]]
+ * describes type definitions in Scala (type aliases, type members, type parameters, classes and traits).
+ *
+ * Most reflection APIs that return symbols return non-specific [[scala.reflect.api.Symbols#Symbol]], because upon failure
+ * they don't raise exceptions, but rather produce `NoSymbol`, a special singleton, which is a null object for symbols.
+ * Therefore to use such APIs one has to first check whether a callee returned a valid symbol and, if yes, then perform
+ * a cast using one of the `asTerm`, `asMethod`, `asModule`, `asType` or `asClass` methods. This is arguably inconvenient
+ * and might be improved in the future.
+ *
+ * Unlike [[scala.reflect.api.Trees trees]] and [[scala.reflect.api.Types types]], symbols should not be created directly.
+ * Instead one should load the symbols from the global symbol table maintained by the compiler.
+ * To get a symbol that corresponds to a top-level class or object, one can use the `staticClass` and `staticModule`
+ * methods of [[scala.reflect.api.Mirror]]. To get a symbol that corresponds to a certain member, there are `members`
+ * and `declarations` methods of [[scala.reflect.api.Types#Type]], which brings the discussion to the next point: type signatures.
+ *
+ * Each symbol has a type signature, which describes its type and is available via the `typeSignature` method
+ * on [[scala.reflect.api.Symbols#Symbol]]. Classes have signatures of the [[scala.reflect.api.Types#ClassInfoType]] type,
+ * which knows the list of its members and declarations. Modules per se don't have interesting signatures. To access members
+ * of modules, one first has to obtain a module class (using the `moduleClass` method) and then inspect its signature.
+ * Members have type signatures of their own: method signatures feature information about parameters and result types,
+ * type member signatures store upper and lower bounds and so on.
+ *
+ * One thing to know about type signatures is that `typeSignature` method always returns signatures in the most generic
+ * way possible, even if the underlying symbol is obtained from an instantiation of a generic type. For example, signature
+ * of the method `def map[B](f: (A) ⇒ B): List[B]`, which refers to the type parameter `A` of the declaring class `List[A]`,
+ * will always feature `A`, regardless of whether `map` is loaded from the `List[_]` or from `List[Int]`. To get a signature
+ * with type parameters appropriately instantiated, one should use `typeSignatureIn`.
+ *
+ * Symbols are at the heart of the reflection API. Along with the type signatures, which are arguably the most important
+ * use of reflection, they provide comprehensive information about the underlying definitions. This includes various
+ * `isXXX` test methods such as `isPublic` or `isFinal`, `params` and `returnType` methods for method symbols,
+ * `baseClasses` for class symbols and so on. Be prepared - some of these methods don't make sense on the ultimate
+ * base class Symbol, so they are declared in subclasses.
+ *
+ * === Exploring symbols ===
+ *
+ * In this example we'll try to get a hold on a symbol that represents the `map` method of `List`,
+ * and then do something interesting with it.
+ *
+ * First of all, to obtain a symbol, one needs to load its enclosing top-level class or module.
+ * There are two ways of doing that. The first one is getting a symbol by its name using a mirror
+ * (refer to [[scala.reflect.api.package the reflection overview]] for information about mirrors).
+ * Another one is getting a type with [[scaa.reflect.api.Types#typeOf]] and using its `typeSymbol` method.
+ * The second approach is preferable, because it's typesafe, but sometimes it's unavailable.
+ *
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> val cm = runtimeMirror(getClass.getClassLoader)
+ * cm: reflect.runtime.universe.Mirror = JavaMirror with ...
+ *
+ * scala> val list = cm.staticClass("scala.List")
+ * list: reflect.runtime.universe.ClassSymbol = class List
+ *
+ * scala> val list = typeOf[List[_]].typeSymbol
+ * list: reflect.runtime.universe.Symbol = class List
+ * }}}
+ *
+ * Now when the enclosing class is obtained, there's a straight path to getting its member
+ * using `typeSignature` and `member` methods discussed above:
+ *
+ * {{{
+ * scala> val map = list.typeSignature.member("map": TermName).asMethod
+ * map: reflect.runtime.universe.MethodSymbol = method map
+ *
+ * scala> map.typeSignature
+ * res0: reflect.runtime.universe.Type = [B, That](f: A => B)(implicit bf:
+ * scala.collection.generic.CanBuildFrom[Repr,B,That])That
+ *
+ * scala> map.typeSignatureIn(typeOf[List[Int]])
+ * res1: reflect.runtime.universe.Type = [B, That](f: Int => B)(implicit bf:
+ * scala.collection.generic.CanBuildFrom[List[Int],B,That])That
+ *
+ * scala> map.params
+ * res2: List[List[reflect.runtime.universe.Symbol]] = List(List(value f), List(value bf))
+ *
+ * scala> val filter = map.params(0)(0)
+ * filter: reflect.runtime.universe.Symbol = value f
+ *
+ * scala> filter.name
+ * res3: reflect.runtime.universe.Name = f
+ *
+ * scala> filter.typeSignature
+ * res4: reflect.runtime.universe.Type = A => B
+ * }}}
+ *
+ * === Gotcha #1: Overloaded methods ===
+ *
+ * Be careful though, because overloaded methods are represented as instances of TermSymbol
+ * with multiple `alternatives` that have to be resolved manually. For example, a lookup
+ * for a member named `mkString` will produce not a MethodSymbol, but a TermSymbol:
+ *
+ * {{{
+ * scala> list.typeSignature.member("mkString": TermName)
+ * res1: reflect.runtime.universe.Symbol = value mkString
+ *
+ * scala> val mkString = list.typeSignature.member("mkString": TermName).asTerm
+ * mkString: reflect.runtime.universe.TermSymbol = value mkString
+ *
+ * scala> mkString.isMethod
+ * res0: Boolean = false
+ *
+ * scala> mkString.alternatives
+ * res1: List[reflect.runtime.universe.Symbol] = List(method mkString, method mkString, method mkString)
+ *
+ * scala> mkString.alternatives foreach println
+ * method mkString
+ * method mkString
+ * method mkString
+ *
+ * scala> mkString.alternatives foreach (alt => println(alt.typeSignature))
+ * => String
+ * (sep: String)String
+ * (start: String, sep: String, end: String)String
+ * }}}
+ *
+ * Once one has a symbol, that symbol can be used for reflective invocations. For example,
+ * having a TermSymbol corresponding to a field it's possible to get or set a value of that field.
+ * Having a MethodSymbol makes it possible to invoke the corresponding methods. ClassSymbols
+ * can be instantiated. ModuleSymbols can provide corresponding singleton instances. This is described
+ * in detail on [[scala.reflect.api.package the reflection overview page]].
+ *
+ * === Gotcha #2: Module classes ===
+ *
+ * Internally the Scala compiler represents objects with two symbols: a module symbol and a module class symbol.
+ * The former is a term symbol, used everywhere a module is referenced (e.g. in singleton types or in expressions),
+ * while the latter is a type symbol, which carries the type signature (i.e. the member list) of the module.
+ * This implementation detail can be easily seen by compiling a trivial snippet of code. Invoking the Scala
+ * compiler on `object C` will generate C$.class. That's exactly the module class.
+ *
+ * Note that module classes are different from companion classes. Say, for `case class C`, the compiler
+ * will generate three symbols: `type C`, `term C` and (another one) `type C`, where the first type `C`
+ * represents the class `C` (which contains auto-generated `copy`, `productPrefix`, `productArity` etc) and
+ * the second type `C` represents the signature of object `C` (which contains auto-generated factory,
+ * extractor etc). There won't be any name clashes, because the module class isn't added to the symbol table
+ * directly and is only available through `<module>.moduleClass`. For the sake of completeness, it is possible
+ * to go back from a module class to a module via `<module class>.module`.
+ *
+ * Separation between modules and module classes is something that we might eliminate in the future, but for now
+ * this obscure implementation detail has to be taken into account when working with reflection. On the one hand,
+ * it is necessary to go to a module class to get a list of members for an object. On the other hand, it is
+ * necessary to go from a module class back to a module to get a singleton instance of an object. The latter
+ * scenario is described at Stack Overflow: [[http://stackoverflow.com/questions/12128783 How can I get the actual object referred to by Scala 2.10 reflection?]].
*/
trait Symbols { self: Universe =>
@@ -79,7 +275,9 @@ trait Symbols { self: Universe =>
/** A special "missing" symbol */
val NoSymbol: Symbol
- /** The API of symbols */
+ /** The API of symbols.
+ * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
+ */
trait SymbolApi { this: Symbol =>
/** The owner of this symbol. This is the symbol
@@ -357,11 +555,14 @@ trait Symbols { self: Universe =>
/******************* helpers *******************/
- /** ...
+ /** Provides an alternate if symbol is a NoSymbol.
*/
def orElse(alt: => Symbol): Symbol
- /** ...
+ /** Filters the underlying alternatives (or a single-element list
+ * composed of the symbol itself if the symbol is not overloaded).
+ * Returns an overloaded symbol is there are multiple matches.
+ * Returns a NoSymbol if there are no matches.
*/
def filter(cond: Symbol => Boolean): Symbol
@@ -370,12 +571,14 @@ trait Symbols { self: Universe =>
*/
def map(f: Symbol => Symbol): Symbol
- /** ...
+ /** Does the same as `filter`, but crashes if there are multiple matches.
*/
def suchThat(cond: Symbol => Boolean): Symbol
}
- /** The API of term symbols */
+ /** The API of term symbols.
+ * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
+ */
trait TermSymbolApi extends SymbolApi { this: TermSymbol =>
/** Term symbols have their names of type `TermName`.
*/
@@ -456,7 +659,9 @@ trait Symbols { self: Universe =>
def isByNameParam: Boolean
}
- /** The API of type symbols */
+ /** The API of type symbols.
+ * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
+ */
trait TypeSymbolApi extends SymbolApi { this: TypeSymbol =>
/** Type symbols have their names of type `TypeName`.
*/
@@ -521,7 +726,9 @@ trait Symbols { self: Universe =>
def typeParams: List[Symbol]
}
- /** The API of method symbols */
+ /** The API of method symbols.
+ * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
+ */
trait MethodSymbolApi extends TermSymbolApi { this: MethodSymbol =>
final override def isMethod = true
final override def asMethod = this
@@ -556,7 +763,9 @@ trait Symbols { self: Universe =>
def returnType: Type
}
- /** The API of module symbols */
+ /** The API of module symbols.
+ * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
+ */
trait ModuleSymbolApi extends TermSymbolApi { this: ModuleSymbol =>
/** The class implicitly associated with the object definition.
* One can go back from a module class to the associated module symbol
@@ -569,7 +778,9 @@ trait Symbols { self: Universe =>
final override def asModule = this
}
- /** The API of class symbols */
+ /** The API of class symbols.
+ * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
+ */
trait ClassSymbolApi extends TypeSymbolApi { this: ClassSymbol =>
final override def isClass = true
final override def asClass = this
@@ -635,7 +846,9 @@ trait Symbols { self: Universe =>
def typeParams: List[Symbol]
}
- /** The API of free term symbols */
+ /** The API of free term symbols.
+ * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
+ */
trait FreeTermSymbolApi extends TermSymbolApi { this: FreeTermSymbol =>
final override def isFreeTerm = true
final override def asFreeTerm = this
@@ -647,7 +860,9 @@ trait Symbols { self: Universe =>
def value: Any
}
- /** The API of free term symbols */
+ /** The API of free type symbols.
+ * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page.
+ */
trait FreeTypeSymbolApi extends TypeSymbolApi { this: FreeTypeSymbol =>
final override def isFreeType = true
final override def asFreeType = this
diff --git a/src/reflect/scala/reflect/api/TagInterop.scala b/src/reflect/scala/reflect/api/TagInterop.scala
index fc0558d717..916be3c324 100644
--- a/src/reflect/scala/reflect/api/TagInterop.scala
+++ b/src/reflect/scala/reflect/api/TagInterop.scala
@@ -1,25 +1,33 @@
package scala.reflect
package api
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that provides type tag <-> manifest interop.
+ */
trait TagInterop { self: Universe =>
// TODO `mirror` parameters are now of type `Any`, because I can't make these path-dependent types work
// if you're brave enough, replace `Any` with `Mirror`, recompile and run interop_typetags_are_manifests.scala
/**
- * Convert a typetag to a pre `Scala-2.10` manifest.
- * For example
+ * Convert a [[scala.reflect.api.TypeTags#TypeTag]] to a [[scala.reflect.Manifest]].
+ *
+ * Compiler usually generates these conversions automatically, when a type tag for a type `T` is in scope,
+ * and an implicit of type `Manifest[T]` is requested, but this method can also be called manually.
+ * For example:
* {{{
- * typeTagToManifest( scala.reflect.runtime.currentMirror, implicitly[TypeTag[String]] )
+ * typeTagToManifest(scala.reflect.runtime.currentMirror, implicitly[TypeTag[String]])
* }}}
*/
def typeTagToManifest[T: ClassTag](mirror: Any, tag: Universe#TypeTag[T]): Manifest[T] =
throw new UnsupportedOperationException("This universe does not support tag -> manifest conversions. Use a JavaUniverse, e.g. the scala.reflect.runtime.universe.")
/**
- * Convert a pre `Scala-2.10` manifest to a typetag.
- * For example
+ * Convert a [[scala.reflect.Manifest]] to a [[scala.reflect.api.TypeTags#TypeTag]].
+ *
+ * Compiler usually generates these conversions automatically, when a manifest for a type `T` is in scope,
+ * and an implicit of type `TypeTag[T]` is requested, but this method can also be called manually.
+ * For example:
* {{{
- * manifestToTypeTag( scala.reflect.runtime.currentMirror, implicitly[Manifest[String]] )
+ * manifestToTypeTag(scala.reflect.runtime.currentMirror, implicitly[Manifest[String]])
* }}}
*/
def manifestToTypeTag[T](mirror: Any, manifest: Manifest[T]): Universe#TypeTag[T] =
diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala
index 5a87d1a90e..9d574adf69 100644
--- a/src/reflect/scala/reflect/api/Trees.scala
+++ b/src/reflect/scala/reflect/api/Trees.scala
@@ -5,52 +5,226 @@
package scala.reflect
package api
-// Syncnote: Trees are currently not thread-safe.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines trees and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
+ *
+ * Tree is the basis for scala's abstract syntax. The nodes are
+ * implemented as case classes, and the parameters which initialize
+ * a given tree are immutable: however trees have several mutable
+ * fields which are manipulated in the course of typechecking,
+ * including `pos`, `symbol`, and `tpe`.
+ *
+ * Newly instantiated trees have `tpe` set to null (though it
+ * may be set immediately thereafter depending on how it is
+ * constructed.) When a tree is passed to the typechecker
+ * (via toolboxes in runtime reflection or using
+ * [[scala.reflect.macros.Context#typeCheck]] in comple-time reflection)
+ * under normal circumstances the `tpe` must be
+ * `null` or the typechecker will ignore it. Furthermore, the typechecker is not
+ * required to return the same tree it was passed.
+ *
+ * Trees can be easily traversed with e.g. `foreach` on the root node;
+ * for a more nuanced traversal, subclass `Traverser`. Transformations
+ * are done by subclassing `Transformer`.
+ *
+ * Copying Trees should be done with care depending on whether
+ * it needs be done lazily or strictly (see [[scala.reflect.api.Trees#newLazyTreeCopier]] and
+ * [[scala.reflect.api.Trees#newStrictTreeCopier]]) and on whether the contents of the mutable
+ * fields should be copied. The tree copiers will copy the mutable
+ * attributes to the new tree. A shortcut way of copying trees is [[scala.reflect.api.Trees#Tree#duplicate]]
+ * which uses a strict copier.
+ *
+ * Trees can be coarsely divided into four mutually exclusive categories:
+ *
+ * - Subclasses of `TermTree`, representing terms
+ * - Subclasses of `TypTree`, representing types. Note that is `TypTree`, not `TypeTree`.
+ * - Subclasses of `SymTree`, which either define or reference symbols.
+ * - Other trees, which have none of those as superclasses.
+ *
+ * `SymTrees` include important nodes `Ident` (which represent references to identifiers)
+ * and `Select` (which represent member selection). These nodes can be used as both terms and types;
+ * they are distinguishable based on whether their underlying [[scala.reflect.api.Names#Name]]
+ * is a `TermName` or `TypeName`. The correct way to test any Tree for a type or a term are the `isTerm`/`isType`
+ * methods on Tree.
+ *
+ * "Others" are mostly syntactic or short-lived constructs. Take, for example,
+ * `CaseDef`, which wraps individual match cases: such nodes are neither terms nor types,
+ * nor do they carry a symbol.
+ *
+ * === How to get a tree that corresponds to a snippet of Scala code? ===
+ *
+ * With the introduction of compile-time metaprogramming and runtime compilation in Scala 2.10.0,
+ * quite often it becomes necessary to convert Scala code into corresponding trees.
+ *
+ * The simplest was to do that is to use [[scala.reflect.api.Universe#reify]].
+ * The `reify` method takes an valid Scala expression (i.e. it has to be well-formed
+ * with respect to syntax and has to typecheck, which means no unresolved free variables).
+ * and produces a tree that represents the input.
+ *
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * // trying to reify a snippet that doesn't typecheck
+ * // leads to a compilation error
+ * scala> reify(x + 2)
+ * <console>:31: error: not found: value x
+ * reify(x + 2)
+ * ^
+ *
+ * scala> val x = 2
+ * x: Int = 2
+ *
+ * // now when the variable x is in the scope
+ * // we can successfully reify the expression `x + 2`
+ * scala> val expr = reify(x + 2)
+ * expr: reflect.runtime.universe.Expr[Int] = Expr[Int](x.$plus(2))
+ *
+ * // the result of reification is of type Expr
+ * // exprs are thin wrappers over trees
+ * scala> expr.tree
+ * res2: reflect.runtime.universe.Tree = x.$plus(2)
+ *
+ * // we can see that the expression `x + 2`
+ * // is internally represented as an instance of the `Apply` case class
+ * scala> res2.getClass.toString
+ * res3: String = class scala.reflect.internal.Trees$Apply
+ *
+ * // when it comes to inspecting the structure of the trees,
+ * // the default implementation of `toString` doesn't help much
+ * // the solution is discussed in one of the next sections
+ * }}}
+ *
+ * The alternative way of getting an AST of a snippet of Scala code
+ * is having it parsed by a toolbox (see [[scala.reflect.api.package the overview page]]
+ * for more information about toolboxes):
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> import scala.reflect.runtime.{currentMirror => cm}
+ * import scala.reflect.runtime.{currentMirror=>cm}
+ *
+ * scala> import scala.tools.reflect.ToolBox // requires scala-compiler.jar
+ * import scala.tools.reflect.ToolBox
+ *
+ * scala> val tb = cm.mkToolBox()
+ * tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = ...
+ *
+ * scala> tb.parse("x + 2")
+ * res0: tb.u.Tree = x.$plus(2)
+ * }}}
+ *
+ * === How to evaluate a tree? ===
+ *
+ * Once there's a way to get a tree that represents Scala code, the next question
+ * is how to evaluate it. The answer to this question depends on what flavor of reflection is used:
+ * runtime reflection or compile-time reflection (macros).
+ *
+ * Within runtime reflection, evaluation can be carried out using toolboxes.
+ * To create a toolbox one wraps a classloader in a mirror and then uses the mirror
+ * to instantiate a toolbox. Later on the underlying classloader will be used to map
+ * symbolic names (such as `List`) to underlying classes of the platform
+ * (see [[scala.reflect.api.package the overview page]] for more information about universes,
+ * mirrors and toolboxes):
+ *
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> import scala.tools.reflect.ToolBox // requires scala-compiler.jar
+ * import scala.tools.reflect.ToolBox
+ *
+ * scala> val mirror = runtimeMirror(getClass.getClassLoader)
+ * mirror: reflect.runtime.universe.Mirror = JavaMirror with ...
+ *
+ * scala> val tb = mirror.mkToolBox()
+ * tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = ...
+ *
+ * scala> tb.eval(tb.parse("2 + 2"))
+ * res0: Int = 4
+ * }}}
+ *
+ * At compile-time, [[scala.reflect.macros.Context]] provides the [[scala.reflect.macros.Evals#eval]] method,
+ * which doesn't require manual instantiation of mirrors and toolboxes and potentially will have better performance
+ * (at the moment it still creates toolboxes under the cover, but in later releases it might be optimized
+ * to reuse the infrastructure of already running compiler).
+ *
+ * Behind the scenes tree evaluation launches the entire compilation pipeline and creates an in-memory virtual directory
+ * that holds the resulting class files (that's why it requires scala-compiler.jar when used with runtime reflection).
+ * This means that the tree being evaluated should be valid Scala code (e.g. it shouldn't contain type errors).
+ *
+ * Quite often though there is a need to evaluate code in some predefined context. For example, one might want to use a dictionary
+ * that maps names to values as an environment for the code being evaluated. This isn't supported out of the box,
+ * but nevertheless this scenario is possible to implement. See a [[http://stackoverflow.com/questions/12122939 Stack Overflow topic]]
+ * for more details.
+ *
+ * === How to get an internal representation of a tree? ===
+ *
+ * The `toString` method on trees is designed to print a close-to-Scala representation
+ * of the code that a given tree represents. This is usually convenient, but sometimes
+ * one would like to look under the covers and see what exactly are the AST nodes that
+ * constitute a certain tree.
+ *
+ * Scala reflection provides a way to dig deeper through [[scala.reflect.api.Printers]]
+ * and their `showRaw` method. Refer to the page linked above for a series of detailed
+ * examples.
+ *
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> def tree = reify{ final class C { def x = 2 } }.tree
+ * tree: reflect.runtime.universe.Tree
+ *
+ * // show displays prettified representation of reflection artifacts
+ * // which is typically close to Scala code, but sometimes not quite
+ * // (e.g. here the constructor is shown in a desugared way)
+ * scala> show(tree)
+ * res0: String =
+ * {
+ * final class C extends AnyRef {
+ * def <init>() = {
+ * super.<init>();
+ * ()
+ * };
+ * def x = 2
+ * };
+ * ()
+ * }
+ *
+ * // showRaw displays internal structure of a given reflection object
+ * // trees and types (type examples are shown below) are case classes
+ * // so they are shown in a form that's almost copy/pasteable
+ * //
+ * // almost copy/pasteable, but not completely - that's because of symbols
+ * // there's no good way to get a roundtrip-surviving representation of symbols
+ * // in general case, therefore only symbol names are shown (e.g. take a look at AnyRef)
+ * //
+ * // in such a representation, it's impossible to distinguish Idents/Selects
+ * // that have underlying symbols vs ones that don't have symbols, because in both cases
+ * // only names will be printed
+ * //
+ * // to overcome this limitation, use `printIds` and `printKinds` - optional parameters
+ * // of the `showRaw` method (example is shown on the scala.reflect.api.Printers doc page)
+ * scala> showRaw(tree)
+ * res1: String = Block(List(
+ * ClassDef(Modifiers(FINAL), newTypeName("C"), List(), Template(
+ * List(Ident(newTypeName("AnyRef"))),
+ * emptyValDef,
+ * List(
+ * DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(),
+ * Block(List(
+ * Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())),
+ * Literal(Constant(())))),
+ * DefDef(Modifiers(), newTermName("x"), List(), List(), TypeTree(),
+ * Literal(Constant(2))))))),
+ * Literal(Constant(())))
+ * }}}
+ */
trait Trees { self: Universe =>
- /** Tree is the basis for scala's abstract syntax. The nodes are
- * implemented as case classes, and the parameters which initialize
- * a given tree are immutable: however Trees have several mutable
- * fields which are manipulated in the course of typechecking,
- * including pos, symbol, and tpe.
- *
- * Newly instantiated trees have tpe set to null (though it
- * may be set immediately thereafter depending on how it is
- * constructed.) When a tree is passed to the typer, typically via
- * `typer.typed(tree)`, under normal circumstances the tpe must be
- * null or the typer will ignore it. Furthermore, the typer is not
- * required to return the same tree it was passed.
- *
- * Trees can be easily traversed with e.g. foreach on the root node;
- * for a more nuanced traversal, subclass Traverser. Transformations
- * can be considerably trickier: see the numerous subclasses of
- * Transformer found around the compiler.
- *
- * Copying Trees should be done with care depending on whether
- * it needs be done lazily or strictly (see LazyTreeCopier and
- * StrictTreeCopier) and on whether the contents of the mutable
- * fields should be copied. The tree copiers will copy the mutable
- * attributes to the new tree; calling Tree#duplicate will copy
- * symbol and tpe, but all the positions will be focused.
- *
- * Trees can be coarsely divided into four mutually exclusive categories:
- *
- * - TermTrees, representing terms
- * - TypTrees, representing types. Note that is `TypTree`, not `TypeTree`.
- * - SymTrees, which may represent types or terms.
- * - Other Trees, which have none of those as parents.
- *
- * SymTrees include important nodes Ident and Select, which are
- * used as both terms and types; they are distinguishable based on
- * whether the Name is a TermName or TypeName. The correct way
- * to test any Tree for a type or a term are the `isTerm`/`isType`
- * methods on Tree.
- *
- * "Others" are mostly syntactic or short-lived constructs. Examples
- * include CaseDef, which wraps individual match cases: they are
- * neither terms nor types, nor do they carry a symbol. Another
- * example is Parens, which is eliminated during parsing.
- */
+ /** The type of Scala abstract syntax trees. */
type Tree >: Null <: TreeApi
/** A tag that preserves the identity of the `Tree` abstract type from erasure.
@@ -58,14 +232,17 @@ trait Trees { self: Universe =>
*/
implicit val TreeTag: ClassTag[Tree]
- /** The API that all trees support */
+ /** The API that all trees support.
+ * The main source of information about trees is the [[scala.reflect.api.Trees]] page.
+ */
trait TreeApi extends Product { this: Tree =>
- // TODO
- /** ... */
+ /** Does this tree represent a definition? (of a method, of a class, etc) */
def isDef: Boolean
- // TODO
- /** ... */
+ /** Is this tree one of the empty trees?
+ * Empty trees are: the `EmptyTree` null object, `TypeTree` instances that don't carry a type
+ * and the special `emptyValDef` singleton.
+ */
def isEmpty: Boolean
/** The canonical way to test if a Tree represents a term.
@@ -76,26 +253,29 @@ trait Trees { self: Universe =>
*/
def isType: Boolean
- /** ... */
+ /** Position of the tree. */
def pos: Position
- /** ... */
+ /** Type of the tree.
+ *
+ * Upon creation most trees have their `tpe` set to `null`.
+ * Types are typically assigned to trees during typechecking.
+ */
def tpe: Type
- /** Note that symbol is fixed as null at this level. In SymTrees,
- * it is overridden and implemented with a var, initialized to NoSymbol.
+ /** Symbol of the tree.
*
- * Trees which are not SymTrees but which carry symbols do so by
- * overriding `def symbol` to forward it elsewhere. Examples:
+ * For most trees symbol is `null`. In `SymTree`s,
+ * it is overridden and implemented with a var, initialized to `NoSymbol`.
*
- * Super(qual, _) // has qual's symbol
- * Apply(fun, args) // has fun's symbol
- * TypeApply(fun, args) // has fun's symbol
- * AppliedTypeTree(tpt, args) // has tpt's symbol
- * TypeTree(tpe) // has tpe's typeSymbol, if tpe != null
+ * Trees which are not `SymTree`s but which carry symbols do so by
+ * overriding `def symbol` to forward it elsewhere. Examples:
*
- * Attempting to set the symbol of a Tree which does not support
- * it will induce an exception.
+ * - `Super(qual, _)` has `qual`'s symbol,
+ * - `Apply(fun, args)` has `fun`'s symbol,
+ * - `TypeApply(fun, args)` has `fun`'s symbol,
+ * - `AppliedTypeTree(tpt, args)` has `tpt`'s symbol,
+ * - `TypeTree(tpe)` has `tpe`'s `typeSymbol`, if `tpe != null`.
*/
def symbol: Symbol
@@ -217,6 +397,7 @@ trait Trees { self: Universe =>
/** The API that all sym trees support */
trait SymTreeApi extends TreeApi { this: SymTree =>
+ /** @inheritdoc */
def symbol: Symbol
}
@@ -231,6 +412,9 @@ trait Trees { self: Universe =>
/** The API that all name trees support */
trait NameTreeApi extends TreeApi { this: NameTree =>
+ /** The underlying name.
+ * For example, the `<List>` part of `Ident("List": TermName)`.
+ */
def name: Name
}
@@ -247,7 +431,13 @@ trait Trees { self: Universe =>
/** The API that all ref trees support */
trait RefTreeApi extends SymTreeApi with NameTreeApi { this: RefTree =>
- def qualifier: Tree // empty for Idents
+ /** The qualifier of the reference.
+ * For example, the `<scala>` part of `Select("scala": TermName, "List": TermName)`.
+ * `EmptyTree` for `Ident` instances.
+ */
+ def qualifier: Tree
+
+ /** @inheritdoc */
def name: Name
}
@@ -262,6 +452,7 @@ trait Trees { self: Universe =>
/** The API that all def trees support */
trait DefTreeApi extends SymTreeApi with NameTreeApi { this: DefTree =>
+ /** @inheritdoc */
def name: Name
}
@@ -277,6 +468,7 @@ trait Trees { self: Universe =>
/** The API that all member defs support */
trait MemberDefApi extends DefTreeApi { this: MemberDef =>
+ /** Modifiers of the declared member. */
def mods: Modifiers
}
@@ -304,7 +496,10 @@ trait Trees { self: Universe =>
/** The API that all package defs support */
trait PackageDefApi extends MemberDefApi { this: PackageDef =>
+ /** The (possibly, fully-qualified) name of the package. */
val pid: RefTree
+
+ /** Body of the package definition. */
val stats: List[Tree]
}
@@ -319,6 +514,7 @@ trait Trees { self: Universe =>
/** The API that all impl defs support */
trait ImplDefApi extends MemberDefApi { this: ImplDef =>
+ /** The body of the definition. */
val impl: Template
}
@@ -350,9 +546,16 @@ trait Trees { self: Universe =>
/** The API that all class defs support */
trait ClassDefApi extends ImplDefApi { this: ClassDef =>
+ /** @inheritdoc */
val mods: Modifiers
+
+ /** The name of the class. */
val name: TypeName
+
+ /** The type parameters of the class. */
val tparams: List[TypeDef]
+
+ /** @inheritdoc */
val impl: Template
}
@@ -386,8 +589,13 @@ trait Trees { self: Universe =>
/** The API that all module defs support */
trait ModuleDefApi extends ImplDefApi { this: ModuleDef =>
+ /** @inheritdoc */
val mods: Modifiers
+
+ /** The name of the module. */
val name: TermName
+
+ /** @inheritdoc */
val impl: Template
}
@@ -402,8 +610,18 @@ trait Trees { self: Universe =>
/** The API that all val defs and def defs support */
trait ValOrDefDefApi extends MemberDefApi { this: ValOrDefDef =>
+ /** @inheritdoc */
def name: Name // can't be a TermName because macros can be type names.
+
+ /** The type ascribed to the definition.
+ * An empty `TypeTree` if the type hasn't been specified explicitly
+ * and is supposed to be inferred.
+ */
def tpt: Tree
+
+ /** The body of the definition.
+ * The `EmptyTree` is the body is empty (e.g. for abstract members).
+ */
def rhs: Tree
}
@@ -446,9 +664,16 @@ trait Trees { self: Universe =>
/** The API that all val defs support */
trait ValDefApi extends ValOrDefDefApi { this: ValDef =>
+ /** @inheritdoc */
val mods: Modifiers
+
+ /** @inheritdoc */
val name: TermName
+
+ /** @inheritdoc */
val tpt: Tree
+
+ /** @inheritdoc */
val rhs: Tree
}
@@ -480,11 +705,22 @@ trait Trees { self: Universe =>
/** The API that all def defs support */
trait DefDefApi extends ValOrDefDefApi { this: DefDef =>
+ /** @inheritdoc */
val mods: Modifiers
+
+ /** @inheritdoc */
val name: Name
+
+ /** The type parameters of the method. */
val tparams: List[TypeDef]
+
+ /** The parameter lists of the method. */
val vparamss: List[List[ValDef]]
+
+ /** @inheritdoc */
val tpt: Tree
+
+ /** @inheritdoc */
val rhs: Tree
}
@@ -519,9 +755,18 @@ trait Trees { self: Universe =>
/** The API that all type defs support */
trait TypeDefApi extends MemberDefApi { this: TypeDef =>
+ /** @inheritdoc */
val mods: Modifiers
+
+ /** @inheritdoc */
val name: TypeName
+
+ /** The type parameters of this type definition. */
val tparams: List[TypeDef]
+
+ /** The body of the definition.
+ * The `EmptyTree` is the body is empty (e.g. for abstract type members).
+ */
val rhs: Tree
}
@@ -568,8 +813,17 @@ trait Trees { self: Universe =>
/** The API that all label defs support */
trait LabelDefApi extends DefTreeApi with TermTreeApi { this: LabelDef =>
+ /** @inheritdoc */
val name: TermName
+
+ /** Label's parameters - names that can be used in the body of the label.
+ * See the example for [[scala.reflect.api.Trees#LabelDefExtractor]].
+ */
val params: List[Ident]
+
+ /** The body of the label.
+ * See the example for [[scala.reflect.api.Trees#LabelDefExtractor]].
+ */
val rhs: Tree
}
@@ -604,9 +858,22 @@ trait Trees { self: Universe =>
/** The API that all import selectors support */
trait ImportSelectorApi { this: ImportSelector =>
+ /** The imported name. */
val name: Name
+
+ /** Offset of the position of the importing part of the selector in the source file.
+ * Is equal to -1 is the position is unknown.
+ */
val namePos: Int
+
+ /** The name the import is renamed to.
+ * Is equal to `name` if it's not a renaming import.
+ */
val rename: Name
+
+ /** Offset of the position of the renaming part of the selector in the source file.
+ * Is equal to -1 is the position is unknown.
+ */
val renamePos: Int
}
@@ -649,7 +916,14 @@ trait Trees { self: Universe =>
/** The API that all imports support */
trait ImportApi extends SymTreeApi { this: Import =>
+ /** The qualifier of the import.
+ * See the example for [[scala.reflect.api.Trees#ImportExtractor]].
+ */
val expr: Tree
+
+ /** The selectors of the import.
+ * See the example for [[scala.reflect.api.Trees#ImportExtractor]].
+ */
val selectors: List[ImportSelector]
}
@@ -693,8 +967,16 @@ trait Trees { self: Universe =>
/** The API that all templates support */
trait TemplateApi extends SymTreeApi { this: Template =>
+ /** Superclasses of the template. */
val parents: List[Tree]
+
+ /** Self type of the template.
+ * Is equal to `emptyValDef` if the self type is not specified.
+ */
val self: ValDef
+
+ /** Body of the template.
+ */
val body: List[Tree]
}
@@ -723,7 +1005,12 @@ trait Trees { self: Universe =>
/** The API that all blocks support */
trait BlockApi extends TermTreeApi { this: Block =>
+ /** All, but the last, expressions in the block.
+ * Can very well be an empty list.
+ */
val stats: List[Tree]
+
+ /** The last expression in the block. */
val expr: Tree
}
@@ -756,8 +1043,17 @@ trait Trees { self: Universe =>
/** The API that all case defs support */
trait CaseDefApi extends TreeApi { this: CaseDef =>
+ /** The pattern of the pattern matching clause. */
val pat: Tree
+
+ /** The guard of the pattern matching clause.
+ * Is equal to `EmptyTree` if the guard is not specified.
+ */
val guard: Tree
+
+ /** The body of the pattern matching clause.
+ * Is equal to `Literal(Constant())` if the body is not specified.
+ */
val body: Tree
}
@@ -789,6 +1085,7 @@ trait Trees { self: Universe =>
/** The API that all alternatives support */
trait AlternativeApi extends TermTreeApi { this: Alternative =>
+ /** Alternatives of the pattern matching clause. */
val trees: List[Tree]
}
@@ -818,6 +1115,7 @@ trait Trees { self: Universe =>
/** The API that all stars support */
trait StarApi extends TermTreeApi { this: Star =>
+ /** The quantified pattern. */
val elem: Tree
}
@@ -850,7 +1148,15 @@ trait Trees { self: Universe =>
/** The API that all binds support */
trait BindApi extends DefTreeApi { this: Bind =>
+ /** The name that can be used to refer to this fragment of the matched expression.
+ * The `list` part of the `list @ List(x, y)`.
+ */
val name: Name
+
+ /** The pattern that represents this fragment of the matched expression.
+ * The `List(x, y)` part of the `list @ List(x, y)`.
+ * Is equal to `EmptyTree` if the pattern is not specified as in `case x => x`.
+ */
val body: Tree
}
@@ -902,7 +1208,14 @@ trait Trees { self: Universe =>
/** The API that all unapplies support */
trait UnApplyApi extends TermTreeApi { this: UnApply =>
+ /** A dummy node that carries the type of unapplication.
+ * See the example for [[scala.reflect.api.Trees#UnApplyExtractor]].
+ */
val fun: Tree
+
+ /** The arguments of the unapplication.
+ * See the example for [[scala.reflect.api.Trees#UnApplyExtractor]].
+ */
val args: List[Tree]
}
@@ -932,7 +1245,12 @@ trait Trees { self: Universe =>
/** The API that all functions support */
trait FunctionApi extends TermTreeApi with SymTreeApi { this: Function =>
+ /** The list of parameters of the function.
+ */
val vparams: List[ValDef]
+
+ /** The body of the function.
+ */
val body: Tree
}
@@ -959,7 +1277,12 @@ trait Trees { self: Universe =>
/** The API that all assigns support */
trait AssignApi extends TermTreeApi { this: Assign =>
+ /** The left-hand side of the assignment.
+ */
val lhs: Tree
+
+ /** The right-hand side of the assignment.
+ */
val rhs: Tree
}
@@ -994,7 +1317,12 @@ trait Trees { self: Universe =>
/** The API that all assigns support */
trait AssignOrNamedArgApi extends TermTreeApi { this: AssignOrNamedArg =>
+ /** The left-hand side of the expression.
+ */
val lhs: Tree
+
+ /** The right-hand side of the expression.
+ */
val rhs: Tree
}
@@ -1023,8 +1351,17 @@ trait Trees { self: Universe =>
/** The API that all ifs support */
trait IfApi extends TermTreeApi { this: If =>
+ /** The condition of the if.
+ */
val cond: Tree
+
+ /** The main branch of the if.
+ */
val thenp: Tree
+
+ /** The alternative of the if.
+ * Is equal to `Literal(Constant(()))` if not specified.
+ */
val elsep: Tree
}
@@ -1063,7 +1400,10 @@ trait Trees { self: Universe =>
/** The API that all matches support */
trait MatchApi extends TermTreeApi { this: Match =>
+ /** The scrutinee of the pattern match. */
val selector: Tree
+
+ /** The arms of the pattern match. */
val cases: List[CaseDef]
}
@@ -1092,10 +1432,11 @@ trait Trees { self: Universe =>
/** The API that all returns support */
trait ReturnApi extends TermTreeApi { this: Return =>
+ /** The returned expression. */
val expr: Tree
}
- /** [Eugene++] comment me! */
+ /** TODO comment me! */
type Try >: Null <: TermTree with TryApi
/** A tag that preserves the identity of the `Try` abstract type from erasure.
@@ -1120,8 +1461,13 @@ trait Trees { self: Universe =>
/** The API that all tries support */
trait TryApi extends TermTreeApi { this: Try =>
+ /** The protected block. */
val block: Tree
+
+ /** The `catch` pattern-matching clauses of the try. */
val catches: List[CaseDef]
+
+ /** The `finally` part of the try. */
val finalizer: Tree
}
@@ -1148,6 +1494,7 @@ trait Trees { self: Universe =>
/** The API that all tries support */
trait ThrowApi extends TermTreeApi { this: Throw =>
+ /** The thrown expression. */
val expr: Tree
}
@@ -1185,6 +1532,9 @@ trait Trees { self: Universe =>
/** The API that all news support */
trait NewApi extends TermTreeApi { this: New =>
+ /** The tree that represents the type being instantiated.
+ * See the example for [[scala.reflect.api.Trees#NewExtractor]].
+ */
val tpt: Tree
}
@@ -1211,7 +1561,10 @@ trait Trees { self: Universe =>
/** The API that all typeds support */
trait TypedApi extends TermTreeApi { this: Typed =>
+ /** The expression being ascribed with the type. */
val expr: Tree
+
+ /** The type being ascribed to the expression. */
val tpt: Tree
}
@@ -1226,7 +1579,10 @@ trait Trees { self: Universe =>
/** The API that all applies support */
trait GenericApplyApi extends TermTreeApi { this: GenericApply =>
+ /** The target of the application. */
val fun: Tree
+
+ /** The arguments of the application. */
val args: List[Tree]
}
@@ -1326,7 +1682,14 @@ trait Trees { self: Universe =>
/** The API that all supers support */
trait SuperApi extends TermTreeApi { this: Super =>
+ /** The qualifier of the `super` expression.
+ * See the example for [[scala.reflect.api.Trees#SuperExtractor]].
+ */
val qual: Tree
+
+ /** The selector of the `super` expression.
+ * See the example for [[scala.reflect.api.Trees#SuperExtractor]].
+ */
val mix: TypeName
}
@@ -1348,8 +1711,6 @@ trait Trees { self: Universe =>
*
* The symbol of a This is the class to which the this refers.
* For instance in C.this, it would be C.
- *
- * If `mix` is empty, then ???
*/
abstract class ThisExtractor {
def apply(qual: TypeName): This
@@ -1358,6 +1719,9 @@ trait Trees { self: Universe =>
/** The API that all thises support */
trait ThisApi extends TermTreeApi with SymTreeApi { this: This =>
+ /** The qualifier of the `this` expression.
+ * For an unqualified `this` refers to the enclosing class.
+ */
val qual: TypeName
}
@@ -1384,7 +1748,10 @@ trait Trees { self: Universe =>
/** The API that all selects support */
trait SelectApi extends RefTreeApi { this: Select =>
+ /** @inheritdoc */
val qualifier: Tree
+
+ /** @inheritdoc */
val name: Name
}
@@ -1414,6 +1781,7 @@ trait Trees { self: Universe =>
/** The API that all idents support */
trait IdentApi extends RefTreeApi { this: Ident =>
+ /** @inheritdoc */
val name: Name
}
@@ -1460,6 +1828,7 @@ trait Trees { self: Universe =>
/** The API that all references support */
trait ReferenceToBoxedApi extends TermTreeApi { this: ReferenceToBoxed =>
+ /** The underlying reference. */
val ident: Tree
}
@@ -1486,6 +1855,7 @@ trait Trees { self: Universe =>
/** The API that all literals support */
trait LiteralApi extends TermTreeApi { this: Literal =>
+ /** The compile-time constant underlying the literal. */
val value: Constant
}
@@ -1517,7 +1887,10 @@ trait Trees { self: Universe =>
/** The API that all annotateds support */
trait AnnotatedApi extends TreeApi { this: Annotated =>
+ /** The annotation. */
val annot: Tree
+
+ /** The annotee. */
val arg: Tree
}
@@ -1544,6 +1917,7 @@ trait Trees { self: Universe =>
/** The API that all singleton type trees support */
trait SingletonTypeTreeApi extends TypTreeApi { this: SingletonTypeTree =>
+ /** The underlying reference. */
val ref: Tree
}
@@ -1573,7 +1947,10 @@ trait Trees { self: Universe =>
/** The API that all selects from type trees support */
trait SelectFromTypeTreeApi extends TypTreeApi with RefTreeApi { this: SelectFromTypeTree =>
+ /** @inheritdoc */
val qualifier: Tree
+
+ /** @inheritdoc */
val name: TypeName
}
@@ -1600,6 +1977,7 @@ trait Trees { self: Universe =>
/** The API that all compound type trees support */
trait CompoundTypeTreeApi extends TypTreeApi { this: CompoundTypeTree =>
+ /** The template of the compound type - represents the parents, the optional self-type and the optional definitions. */
val templ: Template
}
@@ -1626,7 +2004,10 @@ trait Trees { self: Universe =>
/** The API that all applied type trees support */
trait AppliedTypeTreeApi extends TypTreeApi { this: AppliedTypeTree =>
+ /** The target of the application. */
val tpt: Tree
+
+ /** The arguments of the application. */
val args: List[Tree]
}
@@ -1653,11 +2034,18 @@ trait Trees { self: Universe =>
/** The API that all type bound trees support */
trait TypeBoundsTreeApi extends TypTreeApi { this: TypeBoundsTree =>
+ /** The lower bound.
+ * Is equal to `Ident(<scala.Nothing>)` if not specified explicitly.
+ */
val lo: Tree
+
+ /** The upper bound.
+ * Is equal to `Ident(<scala.Any>)` if not specified explicitly.
+ */
val hi: Tree
}
- /** Document me! */
+ /** TODO Document me! */
type ExistentialTypeTree >: Null <: TypTree with ExistentialTypeTreeApi
/** A tag that preserves the identity of the `ExistentialTypeTree` abstract type from erasure.
@@ -1680,7 +2068,10 @@ trait Trees { self: Universe =>
/** The API that all existential type trees support */
trait ExistentialTypeTreeApi extends TypTreeApi { this: ExistentialTypeTree =>
+ /** The underlying type of the existential type. */
val tpt: Tree
+
+ /** The clauses of the definition of the existential type. */
val whereClauses: List[Tree]
}
@@ -1710,6 +2101,9 @@ trait Trees { self: Universe =>
/** The API that all type trees support */
trait TypeTreeApi extends TypTreeApi { this: TypeTree =>
+ /** The precursor of this tree.
+ * Is equal to `EmptyTree` if this type tree doesn't have precursors.
+ */
def original: Tree
}
@@ -1722,50 +2116,73 @@ trait Trees { self: Universe =>
// ---------------------- factories ----------------------------------------------
- /** @param sym the class symbol
- * @param impl the implementation template
+ /** A factory method for `ClassDef` nodes.
*/
def ClassDef(sym: Symbol, impl: Template): ClassDef
- /**
- * @param sym the class symbol
- * @param impl the implementation template
+ /** A factory method for `ModuleDef` nodes.
*/
def ModuleDef(sym: Symbol, impl: Template): ModuleDef
+ /** A factory method for `ValDef` nodes.
+ */
def ValDef(sym: Symbol, rhs: Tree): ValDef
+ /** A factory method for `ValDef` nodes.
+ */
def ValDef(sym: Symbol): ValDef
+ /** A factory method for `ValDef` nodes.
+ */
def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef
+ /** A factory method for `ValDef` nodes.
+ */
def DefDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef
+ /** A factory method for `ValDef` nodes.
+ */
def DefDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef
+ /** A factory method for `ValDef` nodes.
+ */
def DefDef(sym: Symbol, rhs: Tree): DefDef
+ /** A factory method for `ValDef` nodes.
+ */
def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef
- /** A TypeDef node which defines given `sym` with given tight hand side `rhs`. */
+ /** A factory method for `TypeDef` nodes.
+ */
def TypeDef(sym: Symbol, rhs: Tree): TypeDef
- /** A TypeDef node which defines abstract type or type parameter for given `sym` */
+ /** A factory method for `TypeDef` nodes.
+ */
def TypeDef(sym: Symbol): TypeDef
+ /** A factory method for `LabelDef` nodes.
+ */
def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef
- /** Block factory that flattens directly nested blocks.
+ /** A factory method for `Block` nodes.
+ * Flattens directly nested blocks.
*/
def Block(stats: Tree*): Block
- /** casedef shorthand */
+ /** A factory method for `CaseDef` nodes.
+ */
def CaseDef(pat: Tree, body: Tree): CaseDef
+ /** A factory method for `Bind` nodes.
+ */
def Bind(sym: Symbol, body: Tree): Bind
+ /** A factory method for `Try` nodes.
+ */
def Try(body: Tree, cases: (Tree, Tree)*): Try
+ /** A factory method for `Throw` nodes.
+ */
def Throw(tpe: Type, args: Tree*): Throw
/** Factory method for object creation `new tpt(args_1)...(args_n)`
@@ -1777,96 +2194,295 @@ trait Trees { self: Universe =>
*/
def New(tpe: Type, args: Tree*): Tree
+ /** 0-1 argument list new, based on a symbol.
+ */
def New(sym: Symbol, args: Tree*): Tree
+ /** A factory method for `Apply` nodes.
+ */
def Apply(sym: Symbol, args: Tree*): Tree
+ /** 0-1 argument list new, based on a type tree.
+ */
def ApplyConstructor(tpt: Tree, args: List[Tree]): Tree
+ /** A factory method for `Super` nodes.
+ */
def Super(sym: Symbol, mix: TypeName): Tree
+ /** A factory method for `This` nodes.
+ */
def This(sym: Symbol): Tree
+ /** A factory method for `Select` nodes.
+ * The string `name` argument is assumed to represent a [[scala.reflect.api.Names#TermName].
+ */
def Select(qualifier: Tree, name: String): Select
+ /** A factory method for `Select` nodes.
+ */
def Select(qualifier: Tree, sym: Symbol): Select
+ /** A factory method for `Ident` nodes.
+ */
def Ident(name: String): Ident
+ /** A factory method for `Ident` nodes.
+ */
def Ident(sym: Symbol): Ident
+ /** A factory method for `TypeTree` nodes.
+ */
def TypeTree(tp: Type): TypeTree
// ---------------------- copying ------------------------------------------------
- /** The standard (lazy) tree copier
+ /** The type of standard (lazy) tree copiers.
*/
type TreeCopier <: TreeCopierOps
+
+ /** The standard (lazy) tree copier.
+ */
val treeCopy: TreeCopier = newLazyTreeCopier
+ /** Creates a strict tree copier.
+ */
def newStrictTreeCopier: TreeCopier
+
+ /** Creates a lazy tree copier.
+ */
def newLazyTreeCopier: TreeCopier
- /** The API of a tree copier
- * tree copiers are made available by an implicit conversion in reflect.ops
+ /** The API of a tree copier.
*/
abstract class TreeCopierOps {
+ /** Creates a `ClassDef` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template): ClassDef
+
+ /** Creates a `PackageDef` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree]): PackageDef
+
+ /** Creates a `ModuleDef` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template): ModuleDef
+
+ /** Creates a `ValDef` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree): ValDef
+
+ /** Creates a `DefDef` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef
+
+ /** Creates a `TypeDef` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree): TypeDef
+
+ /** Creates a `LabelDef` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree): LabelDef
+
+ /** Creates a `Import` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]): Import
+
+ /** Creates a `Template` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]): Template
+
+ /** Creates a `Block` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Block(tree: Tree, stats: List[Tree], expr: Tree): Block
+
+ /** Creates a `CaseDef` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree): CaseDef
+
+ /** Creates a `Alternative` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Alternative(tree: Tree, trees: List[Tree]): Alternative
+
+ /** Creates a `Star` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Star(tree: Tree, elem: Tree): Star
+
+ /** Creates a `Bind` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Bind(tree: Tree, name: Name, body: Tree): Bind
+
+ /** Creates a `UnApply` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def UnApply(tree: Tree, fun: Tree, args: List[Tree]): UnApply
+
+ /** Creates a `Function` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Function(tree: Tree, vparams: List[ValDef], body: Tree): Function
+
+ /** Creates a `Assign` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Assign(tree: Tree, lhs: Tree, rhs: Tree): Assign
+
+ /** Creates a `AssignOrNamedArg` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg
+
+ /** Creates a `If` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree): If
+
+ /** Creates a `Match` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Match(tree: Tree, selector: Tree, cases: List[CaseDef]): Match
+
+ /** Creates a `Return` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Return(tree: Tree, expr: Tree): Return
+
+ /** Creates a `Try` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree): Try
+
+ /** Creates a `Throw` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Throw(tree: Tree, expr: Tree): Throw
+
+ /** Creates a `New` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def New(tree: Tree, tpt: Tree): New
+
+ /** Creates a `Typed` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Typed(tree: Tree, expr: Tree, tpt: Tree): Typed
+
+ /** Creates a `TypeApply` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def TypeApply(tree: Tree, fun: Tree, args: List[Tree]): TypeApply
+
+ /** Creates a `Apply` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Apply(tree: Tree, fun: Tree, args: List[Tree]): Apply
+
+ /** Creates a `Super` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Super(tree: Tree, qual: Tree, mix: TypeName): Super
+
+ /** Creates a `This` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def This(tree: Tree, qual: Name): This
+
+ /** Creates a `Select` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Select(tree: Tree, qualifier: Tree, selector: Name): Select
+
+ /** Creates a `Ident` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Ident(tree: Tree, name: Name): Ident
+
+ /** Creates a `ReferenceToBoxed` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def ReferenceToBoxed(tree: Tree, idt: Ident): ReferenceToBoxed
+
+ /** Creates a `Literal` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Literal(tree: Tree, value: Constant): Literal
+
+ /** Creates a `TypeTree` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def TypeTree(tree: Tree): TypeTree
+
+ /** Creates a `Annotated` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def Annotated(tree: Tree, annot: Tree, arg: Tree): Annotated
+
+ /** Creates a `SingletonTypeTree` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def SingletonTypeTree(tree: Tree, ref: Tree): SingletonTypeTree
+
+ /** Creates a `SelectFromTypeTree` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name): SelectFromTypeTree
+
+ /** Creates a `CompoundTypeTree` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def CompoundTypeTree(tree: Tree, templ: Template): CompoundTypeTree
+
+ /** Creates a `AppliedTypeTree` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]): AppliedTypeTree
+
+ /** Creates a `TypeBoundsTree` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree): TypeBoundsTree
+
+ /** Creates a `ExistentialTypeTree` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]): ExistentialTypeTree
}
// ---------------------- traversing and transforming ------------------------------
+ /** A class that implement a default tree traversal strategy: breadth-first component-wise.
+ */
class Traverser {
protected[scala] var currentOwner: Symbol = rootMirror.RootClass
+ /** Traverses a single tree. */
def traverse(tree: Tree): Unit = itraverse(this, tree)
+ /** Traverses a list of trees. */
def traverseTrees(trees: List[Tree]) {
trees foreach traverse
}
+
+ /** Traverses a list of lists of trees. */
def traverseTreess(treess: List[List[Tree]]) {
treess foreach traverseTrees
}
+
+ /** Traverses a list of trees with a given owner symbol. */
def traverseStats(stats: List[Tree], exprOwner: Symbol) {
stats foreach (stat =>
if (exprOwner != currentOwner) atOwner(exprOwner)(traverse(stat))
@@ -1874,6 +2490,7 @@ trait Trees { self: Universe =>
)
}
+ /** Performs a traversal with a given owner symbol. */
def atOwner(owner: Symbol)(traverse: => Unit) {
val prevOwner = currentOwner
currentOwner = owner
@@ -1886,49 +2503,78 @@ trait Trees { self: Universe =>
def apply[T <: Tree](tree: T): T = { traverse(tree); tree }
}
+ /** Delegates the traversal strategy to [[scala.reflect.internal.Trees]],
+ * because pattern matching on abstract types we have here degrades performance.
+ */
protected def itraverse(traverser: Traverser, tree: Tree): Unit = throw new MatchError(tree)
+ /** Provides an extension hook for the traversal strategy.
+ * Future-proofs against new node types.
+ */
protected def xtraverse(traverser: Traverser, tree: Tree): Unit = throw new MatchError(tree)
+ /** A class that implement a default tree transformation strategy: breadth-first component-wise cloning.
+ */
abstract class Transformer {
+ /** The underlying tree copier. */
val treeCopy: TreeCopier = newLazyTreeCopier
+
+ /** The current owner symbol. */
protected[scala] var currentOwner: Symbol = rootMirror.RootClass
+
+ /** The enclosing method of the currently transformed tree. */
protected def currentMethod = {
def enclosingMethod(sym: Symbol): Symbol =
if (sym.isMethod || sym == NoSymbol) sym else enclosingMethod(sym.owner)
enclosingMethod(currentOwner)
}
+
+ /** The enclosing class of the currently transformed tree. */
protected def currentClass = {
def enclosingClass(sym: Symbol): Symbol =
if (sym.isClass || sym == NoSymbol) sym else enclosingClass(sym.owner)
enclosingClass(currentOwner)
}
+
// protected def currentPackage = currentOwner.enclosingTopLevelClass.owner
+
+ /** Transforms a single tree. */
def transform(tree: Tree): Tree = itransform(this, tree)
- def transformTrees(trees: List[Tree]): List[Tree] =
- trees mapConserve (transform(_))
+ /** Transforms a list of trees. */
+ def transformTrees(trees: List[Tree]): List[Tree] = trees mapConserve (transform(_))
+
+ /** Transforms a `Template`. */
def transformTemplate(tree: Template): Template =
transform(tree: Tree).asInstanceOf[Template]
+ /** Transforms a list of `TypeDef` trees. */
def transformTypeDefs(trees: List[TypeDef]): List[TypeDef] =
trees mapConserve (tree => transform(tree).asInstanceOf[TypeDef])
+ /** Transforms a `ValDef`. */
def transformValDef(tree: ValDef): ValDef =
if (tree.isEmpty) tree else transform(tree).asInstanceOf[ValDef]
+ /** Transforms a list of `ValDef` nodes. */
def transformValDefs(trees: List[ValDef]): List[ValDef] =
trees mapConserve (transformValDef(_))
+ /** Transforms a list of lists of `ValDef` nodes. */
def transformValDefss(treess: List[List[ValDef]]): List[List[ValDef]] =
treess mapConserve (transformValDefs(_))
+ /** Transforms a list of `CaseDef` nodes. */
def transformCaseDefs(trees: List[CaseDef]): List[CaseDef] =
trees mapConserve (tree => transform(tree).asInstanceOf[CaseDef])
+ /** Transforms a list of `Ident` nodes. */
def transformIdents(trees: List[Ident]): List[Ident] =
trees mapConserve (tree => transform(tree).asInstanceOf[Ident])
+ /** Traverses a list of trees with a given owner symbol. */
def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] =
stats mapConserve (stat =>
if (exprOwner != currentOwner && stat.isTerm) atOwner(exprOwner)(transform(stat))
else transform(stat)) filter (EmptyTree != _)
+ /** Transforms `Modifiers`. */
def transformModifiers(mods: Modifiers): Modifiers =
mods.mapAnnotations(transformTrees)
+ /** Transforms a tree with a given owner symbol. */
def atOwner[A](owner: Symbol)(trans: => A): A = {
val prevOwner = currentOwner
currentOwner = owner
@@ -1938,12 +2584,17 @@ trait Trees { self: Universe =>
}
}
+ /** Delegates the transformation strategy to [[scala.reflect.internal.Trees]],
+ * because pattern matching on abstract types we have here degrades performance.
+ */
protected def itransform(transformer: Transformer, tree: Tree): Tree = throw new MatchError(tree)
+ /** Provides an extension hook for the transformation strategy.
+ * Future-proofs against new node types.
+ */
protected def xtransform(transformer: Transformer, tree: Tree): Tree = throw new MatchError(tree)
-
- /** ... */
+ /** The type of tree modifiers. */
type Modifiers >: Null <: AnyRef with ModifiersApi
/** A tag that preserves the identity of the `Modifiers` abstract type from erasure.
@@ -1951,26 +2602,49 @@ trait Trees { self: Universe =>
*/
implicit val ModifiersTag: ClassTag[Modifiers]
- /** ... */
+ /** The API that all Modifiers support */
abstract class ModifiersApi {
- def flags: FlagSet // default: NoFlags
+ /** The underlying flags of the enclosing definition.
+ * Is equal to `NoFlags` if none are specified explicitly.
+ */
+ def flags: FlagSet
+
def hasFlag(flag: FlagSet): Boolean
- def privateWithin: Name // default: EmptyTypeName
- def annotations: List[Tree] // default: List()
+
+ /** The visibility scope of the enclosing definition.
+ * Is equal to `tpnme.EMPTY` if none is specified explicitly.
+ */
+ def privateWithin: Name
+
+ /** The annotations of the enclosing definition.
+ * Empty list if none are specified explicitly.
+ */
+ def annotations: List[Tree]
+
+ /** Creates a new instance of `Modifiers` with
+ * the annotations transformed according to the given function.
+ */
def mapAnnotations(f: List[Tree] => List[Tree]): Modifiers =
Modifiers(flags, privateWithin, f(annotations))
}
+ /** The constructor/deconstructor for `Modifiers` instances. */
val Modifiers: ModifiersCreator
+ /** An extractor class to create and pattern match with syntax `Modifiers(flags, privateWithin, annotations)`.
+ * Modifiers encapsulate flags, visibility annotations and Scala annotations for member definitions.
+ */
abstract class ModifiersCreator {
def apply(): Modifiers = Modifiers(NoFlags, tpnme.EMPTY, List())
def apply(flags: FlagSet, privateWithin: Name, annotations: List[Tree]): Modifiers
}
+ /** The factory for `Modifiers` instances. */
def Modifiers(flags: FlagSet, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List())
+
+ /** The factory for `Modifiers` instances. */
def Modifiers(flags: FlagSet): Modifiers = Modifiers(flags, tpnme.EMPTY)
- /** ... */
+ /** An empty `Modifiers` object: no flags, empty visibility annotation and no Scala annotations. */
lazy val NoMods = Modifiers()
}
diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala
index fc3f067a96..0b1d3b8172 100644
--- a/src/reflect/scala/reflect/api/TypeTags.scala
+++ b/src/reflect/scala/reflect/api/TypeTags.scala
@@ -17,9 +17,10 @@ import scala.language.implicitConversions
* [Chris++] tag.in(some mirror) or expr.in(some mirror) (does not work for tag and exprs in macros)
* Backwards compat item1: [Eugene++] it might be useful, though, to guard against abstractness of the incoming type.
*/
-/**
- * A type tag encapsulates a representation of type T.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines type tags and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
*
+ * A type tag encapsulates a representation of type T.
* Type tags replace the pre-2.10 concept of a [[scala.reflect.Manifest]] and are integrated with reflection.
*
* === Overview and examples ===
@@ -27,8 +28,6 @@ import scala.language.implicitConversions
* Type tags are organized in a hierarchy of three classes:
* [[scala.reflect.ClassTag]], [[scala.reflect.api.Universe#TypeTag]] and [[scala.reflect.api.Universe#WeakTypeTag]].
*
- * @see [[scala.reflect.ClassTag]], [[scala.reflect.api.Universe#TypeTag]], [[scala.reflect.api.Universe#WeakTypeTag]]
- *
* Examples:
* {{{
* scala> class Person
@@ -117,23 +116,31 @@ import scala.language.implicitConversions
* The previous notion of a [[scala.reflect.ClassManifest]] corresponds to a scala.reflect.ClassTag,
* The previous notion of a [[scala.reflect.Manifest]] corresponds to scala.reflect.runtime.universe.TypeTag,
*
- * In Scala 2.10, manifests are deprecated, so it's advisable to migrate them to tags,
- * because manifests will probably be removed in the next major release.
+ * In Scala 2.10 class manifests are deprecated, and manifests are planned to be deprecated in one of the
+ * subsequent point releases. Therefore it's advisable to migrate manifests to tags.
*
- * In most cases it will be enough to replace ClassManifest with ClassTag and Manifest with TypeTag.
+ * In most cases it is enough to replace `ClassManifest` with `ClassTag` and `Manifest` with `TypeTag`.
* There are however a few caveats:
*
- * 1) The notion of OptManifest is no longer supported. Tags can reify arbitrary types, so they are always available.
+ * 1) Tags don't support the notion of `OptManifest`. Tags can reify arbitrary types, so they are always available.
*
- * 2) There's no equivalent for AnyValManifest. Consider comparing your tag with one of the base tags
+ * 2) There's no equivalent for `AnyValManifest`. Consider comparing your tag with one of the base tags
* (defined in the corresponding companion objects) to find out whether it represents a primitive value class.
- * You can also use `<tag>.tpe.typeSymbol.isPrimitiveValueClass` for that purpose (requires scala-reflect.jar).
+ * You can also use `<tag>.tpe.typeSymbol.isPrimitiveValueClass`.
*
* 3) There's no replacement for factory methods defined in `ClassManifest` and `Manifest` companion objects.
* Consider assembling corresponding types using the reflection APIs provided by Java (for classes) and Scala (for types).
*
* 4) Certain manifest functions (such as `<:<`, `>:>` and `typeArguments`) weren't included in the tag API.
* Consider using the reflection APIs provided by Java (for classes) and Scala (for types) instead.
+ *
+ * === Known issues ===
+ *
+ * Type tags are marked as serializable, but this functionality is not yet implemented.
+ * An issue tracker entry: [[https://issues.scala-lang.org/browse/SI-5919 https://issues.scala-lang.org/browse/SI-5919]]
+ * has been created to track the implementation of this feature.
+ *
+ * @see [[scala.reflect.ClassTag]], [[scala.reflect.api.Universe#TypeTag]], [[scala.reflect.api.Universe#WeakTypeTag]]
*/
trait TypeTags { self: Universe =>
@@ -171,10 +178,16 @@ trait TypeTags { self: Universe =>
*/
def tpe: Type
- // case class accessories
+ /** TODO how do I doc this? */
override def canEqual(x: Any) = x.isInstanceOf[WeakTypeTag[_]]
+
+ /** TODO how do I doc this? */
override def equals(x: Any) = x.isInstanceOf[WeakTypeTag[_]] && this.mirror == x.asInstanceOf[WeakTypeTag[_]].mirror && this.tpe == x.asInstanceOf[WeakTypeTag[_]].tpe
+
+ /** TODO how do I doc this? */
override def hashCode = mirror.hashCode * 31 + tpe.hashCode
+
+ /** TODO how do I doc this? */
override def toString = "WeakTypeTag[" + tpe + "]"
}
@@ -245,13 +258,22 @@ trait TypeTags { self: Universe =>
*/
override def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # TypeTag[T]
- // case class accessories
+ /** TODO how do I doc this? */
override def canEqual(x: Any) = x.isInstanceOf[TypeTag[_]]
+
+ /** TODO how do I doc this? */
override def equals(x: Any) = x.isInstanceOf[TypeTag[_]] && this.mirror == x.asInstanceOf[TypeTag[_]].mirror && this.tpe == x.asInstanceOf[TypeTag[_]].tpe
+
+ /** TODO how do I doc this? */
override def hashCode = mirror.hashCode * 31 + tpe.hashCode
+
+ /** TODO how do I doc this? */
override def toString = "TypeTag[" + tpe + "]"
}
+ /**
+ * Type tags corresponding to primitive types and constructor/extractor for WeakTypeTags.
+ */
object TypeTag {
val Byte: TypeTag[scala.Byte] = new PredefTypeTag[scala.Byte] (ByteTpe, _.TypeTag.Byte)
val Short: TypeTag[scala.Short] = new PredefTypeTag[scala.Short] (ShortTpe, _.TypeTag.Short)
diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala
index af70c9e761..060b0657b1 100644
--- a/src/reflect/scala/reflect/api/Types.scala
+++ b/src/reflect/scala/reflect/api/Types.scala
@@ -1,13 +1,104 @@
package scala.reflect
package api
-/**
- * Defines the type hierachy for types.
+/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines types and operations on them.
+ * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
*
- * Note: Because of implementation details, some type factories have return type `Type`
- * instead of a more precise type.
+ * While [[scala.reflect.api.Symbols symbols]] establish the structure of the program by representing the hierarchy
+ * of definitions, types bring meaning to symbols. A type is not, say, `Int` -- that's just its symbol
+ * (assuming we are talking about `scala.Int`, and not just the name). A type is the information about all members
+ * that compose that thing: methods, fields, type parameters, nested classes and traits, etc. If a symbol represents
+ * a definition, a type represents the whole structure of that definition. It is the union of all definitions that
+ * compose a class, the description of what goes into a method and what comes out, etc.
*
- * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here.
+ * === Instantiating types ===
+ *
+ * There are three ways to instantiate types. The simplest one involves the [[scala.reflect.api.TypeTags#typeOf]] method,
+ * which takes a type argument and produces a `Type` instance that represents that argument. For example, `typeOf[List[Int]]`
+ * produces a [[scala.reflect.api.Types#TypeRef]], which corresponds to a type `List` applied to a type argument `Int`.
+ * When type parameters are involved (as, for example, in `typeOf[List[A]]`), `typeOf` won't work, and one should use
+ * [[scala.reflect.api.TypeTags#weakTypeOf]] instead. Refer to [[scala.reflect.api.TypeTags the type tags page]] to find out
+ * more about this distinction.
+ *
+ * `typeOf` requires spelling out a type explicitly, but there's also a way to capture types implicitly with the [[scala.reflect.api.TypeTag#TypeTag]]
+ * context bound. Once a type parameter `T` is annotated with the `TypeTag` context bound, the for each usage of the enclosing class or method,
+ * the compiler will automatically produce a `Type` evidence, available via `typeTag[T]`. For example, inside a method
+ * `def test[T: TypeTag](x: T) = ...` one can use `typeTag[T]` to obtain the information about the exact type of `x` passed into that method.
+ * Similarly to the situation `typeOf`, sometimes `typeTag` does not work, and one has to use `weakTypeTag`.
+ * [[scala.reflect.api.TypeTags The type tags page]] tells more about this feature.
+ *
+ * Finally types can be instantiated manually using factory methods such as `typeRef` or `polyType`.
+ * This is necessary only in cases when `typeOf` or `typeTag` cannot be applied, because the type cannot be spelt out
+ * in a Scala snippet, usually when writing macros. Manual construction requires deep knowledge of Scala compiler internals
+ * and shouldn't be used, when there are other alternatives available.
+ *
+ * === Using types ===
+ *
+ * Arguably the most useful application of types is looking up members. Every type has `members` and `declarations` methods (along with
+ * their singular counterparts `member` and `declaration`), which provide the list of definitions associated with that type.
+ * For example, to look up the `map` method of `List`, one could write `typeOf[List[_]].member("map": TermName)`, getting a `MethodSymbol`
+ *
+ * Another popular use case is doing subtype tests. Types expose `<:<` and `weak_<:<` methods for that purpose. The latter is
+ * an extension of the former - it also works with numeric types (for example, `Int <:< Long` is false, but `Int weak_<:< Long` is true).
+ * Unlike the subtype tests implemented by manifests, tests provided by `Type`s are aware of all the intricacies of the Scala type system
+ * and work correctly even for involved types.
+ *
+ * Finally a word must be said about equality of types. Due to an implementation detail, the vanilla `==` method should not be used
+ * to compare types for equality, as it might work in some circumstances and fizzle under conditions that are slightly different.
+ * Instead one should always use the `=:=` method. As an added bonus, `=:=` also knows about type aliases, e.g.
+ * `typeOf[scala.List[_]] =:= typeOf[scala.collection.immutable.List[_]]`.
+ *
+ * === Exploring types ===
+ *
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> typeOf[List[_]].members.sorted take 5 foreach println
+ * constructor List
+ * method companion
+ * method ::
+ * method :::
+ * method reverse_:::
+ *
+ * scala> def test[T: TypeTag](x: T) = s"I've been called for an x typed as ${typeOf[T]}"
+ * test: [T](x: T)(implicit evidence$1: reflect.runtime.universe.TypeTag[T])String
+ *
+ * scala> test(2)
+ * res0 @ 3fc80fae: String = I've been called for an x typed as Int
+ *
+ * scala> test(List(2, "x"))
+ * res1 @ 10139edf: String = I've been called for an x typed as List[Any]
+ * }}}
+ *
+ * === How to get an internal representation of a type? ===
+ *
+ * The `toString` method on types is designed to print a close-to-Scala representation
+ * of the code that a given type represents. This is usually convenient, but sometimes
+ * one would like to look under the covers and see what exactly are the elements that
+ * constitute a certain type.
+ *
+ * Scala reflection provides a way to dig deeper through [[scala.reflect.api.Printers]]
+ * and their `showRaw` method. Refer to the page linked above for a series of detailed
+ * examples.
+ *
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ *
+ * scala> def tpe = typeOf[{ def x: Int; val y: List[Int] }]
+ * tpe: reflect.runtime.universe.Type
+ *
+ * scala> show(tpe)
+ * res0: String = scala.AnyRef{def x: Int; val y: scala.List[Int]}
+ *
+ * scala> showRaw(tpe)
+ * res1: String = RefinedType(
+ * List(TypeRef(ThisType(scala), newTypeName("AnyRef"), List())),
+ * Scope(
+ * newTermName("x"),
+ * newTermName("y")))
+ * }}}
*/
trait Types { self: Universe =>
@@ -31,7 +122,8 @@ trait Types { self: Universe =>
*/
val NoPrefix: Type
- /** The API of types
+ /** The API of types.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
*/
abstract class TypeApi {
/** The term symbol associated with the type, or `NoSymbol` for types
@@ -221,8 +313,11 @@ trait Types { self: Universe =>
def unapply(tpe: ThisType): Option[Symbol]
}
- /** The API that all this types support */
+ /** The API that all this types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait ThisTypeApi extends TypeApi { this: ThisType =>
+ /** The underlying class symbol. */
val sym: Symbol
}
@@ -253,9 +348,14 @@ trait Types { self: Universe =>
def unapply(tpe: SingleType): Option[(Type, Symbol)]
}
- /** The API that all single types support */
+ /** The API that all single types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait SingleTypeApi extends TypeApi { this: SingleType =>
+ /** The type of the qualifier. */
val pre: Type
+
+ /** The underlying symbol. */
val sym: Symbol
}
/** The `SuperType` type is not directly written, but arises when `C.super` is used
@@ -284,9 +384,18 @@ trait Types { self: Universe =>
def unapply(tpe: SuperType): Option[(Type, Type)]
}
- /** The API that all super types support */
+ /** The API that all super types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait SuperTypeApi extends TypeApi { this: SuperType =>
+ /** The type of the qualifier.
+ * See the example for [[scala.reflect.api.Trees#SuperExtractor]].
+ */
val thistpe: Type
+
+ /** The type of the selector.
+ * See the example for [[scala.reflect.api.Trees#SuperExtractor]].
+ */
val supertpe: Type
}
/** The `ConstantType` type is not directly written in user programs, but arises as the type of a constant.
@@ -314,8 +423,11 @@ trait Types { self: Universe =>
def unapply(tpe: ConstantType): Option[Constant]
}
- /** The API that all constant types support */
+ /** The API that all constant types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait ConstantTypeApi extends TypeApi { this: ConstantType =>
+ /** The compile-time constant underlying this type. */
val value: Constant
}
@@ -350,10 +462,21 @@ trait Types { self: Universe =>
def unapply(tpe: TypeRef): Option[(Type, Symbol, List[Type])]
}
- /** The API that all type refs support */
+ /** The API that all type refs support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait TypeRefApi extends TypeApi { this: TypeRef =>
+ /** The prefix of the type reference.
+ * Is equal to `NoPrefix` if the prefix is not applicable.
+ */
val pre: Type
+
+ /** The underlying symbol of the type reference. */
val sym: Symbol
+
+ /** The arguments of the type reference.
+ * Is equal to `Nil` if the arguments are not provided.
+ */
val args: List[Type]
}
@@ -398,9 +521,14 @@ trait Types { self: Universe =>
def unapply(tpe: RefinedType): Option[(List[Type], Scope)]
}
- /** The API that all refined types support */
+ /** The API that all refined types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait RefinedTypeApi extends TypeApi { this: RefinedType =>
+ /** The superclasses of the type. */
val parents: List[Type]
+
+ /** The scope that holds the definitions comprising the type. */
val decls: Scope
}
@@ -434,10 +562,17 @@ trait Types { self: Universe =>
def unapply(tpe: ClassInfoType): Option[(List[Type], Scope, Symbol)]
}
- /** The API that all class info types support */
+ /** The API that all class info types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait ClassInfoTypeApi extends TypeApi { this: ClassInfoType =>
+ /** The superclasses of the class type. */
val parents: List[Type]
+
+ /** The scope that holds the definitions comprising the class type. */
val decls: Scope
+
+ /** The symbol underlying the class type. */
val typeSymbol: Symbol
}
@@ -472,9 +607,14 @@ trait Types { self: Universe =>
def unapply(tpe: MethodType): Option[(List[Symbol], Type)]
}
- /** The API that all method types support */
+ /** The API that all method types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait MethodTypeApi extends TypeApi { this: MethodType =>
+ /** The symbols that correspond to the parameters of the method. */
val params: List[Symbol]
+
+ /** The result type of the method. */
val resultType: Type
}
@@ -499,8 +639,11 @@ trait Types { self: Universe =>
def unapply(tpe: NullaryMethodType): Option[(Type)]
}
- /** The API that all nullary method types support */
+ /** The API that all nullary method types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait NullaryMethodTypeApi extends TypeApi { this: NullaryMethodType =>
+ /** The result type of the method. */
val resultType: Type
}
@@ -526,9 +669,14 @@ trait Types { self: Universe =>
def unapply(tpe: PolyType): Option[(List[Symbol], Type)]
}
- /** The API that all polymorphic types support */
+ /** The API that all polymorphic types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait PolyTypeApi extends TypeApi { this: PolyType =>
+ /** The symbols corresponding to the type parameters. */
val typeParams: List[Symbol]
+
+ /** The underlying type. */
val resultType: Type
}
@@ -555,9 +703,14 @@ trait Types { self: Universe =>
def unapply(tpe: ExistentialType): Option[(List[Symbol], Type)]
}
- /** The API that all existential types support */
+ /** The API that all existential types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait ExistentialTypeApi extends TypeApi { this: ExistentialType =>
+ /** The symbols corresponding to the `forSome` clauses of the existential type. */
val quantified: List[Symbol]
+
+ /** The underlying type of the existential type. */
val underlying: Type
}
@@ -584,10 +737,17 @@ trait Types { self: Universe =>
def unapply(tpe: AnnotatedType): Option[(List[Annotation], Type, Symbol)]
}
- /** The API that all annotated types support */
+ /** The API that all annotated types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait AnnotatedTypeApi extends TypeApi { this: AnnotatedType =>
+ /** The annotations. */
val annotations: List[Annotation]
+
+ /** The annotee. */
val underlying: Type
+
+ /** A symbol that represents the annotated type itself. */
val selfsym: Symbol
}
@@ -620,9 +780,18 @@ trait Types { self: Universe =>
def unapply(tpe: TypeBounds): Option[(Type, Type)]
}
- /** The API that all type bounds support */
+ /** The API that all type bounds support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait TypeBoundsApi extends TypeApi { this: TypeBounds =>
+ /** The lower bound.
+ * Is equal to `definitions.NothingTpe` if not specified explicitly.
+ */
val lo: Type
+
+ /** The upper bound.
+ * Is equal to `definitions.AnyTpe` if not specified explicitly.
+ */
val hi: Type
}
@@ -659,8 +828,11 @@ trait Types { self: Universe =>
def unapply(tpe: BoundedWildcardType): Option[TypeBounds]
}
- /** The API that all this types support */
+ /** The API that all this types support.
+ * The main source of information about types is the [[scala.reflect.api.Types]] page.
+ */
trait BoundedWildcardTypeApi extends TypeApi { this: BoundedWildcardType =>
+ /** Type bounds for the wildcard type. */
val bounds: TypeBounds
}
diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala
index 7d0f6cf0d6..207dc98a91 100644
--- a/src/reflect/scala/reflect/api/Universe.scala
+++ b/src/reflect/scala/reflect/api/Universe.scala
@@ -1,6 +1,76 @@
package scala.reflect
package api
+/**
+ * The Scala reflection cake.
+ *
+ * See [[scala.reflect.api.package the overview page]] for a description of universes and infomation on getting started with Scala reflection API.
+ * This page lists the most important layers of the cake, and describes paculiarities of cake APIs.
+ *
+ * The reflection library is structured according to the 'cake pattern'. The main layer
+ * resides in package [[scala.reflect.api]] and defines an interface to the following main types:
+ *
+ * - [[scala.reflect.api.Types#Type Types]] represent types
+ * - [[scala.reflect.api.Symbols#Symbol Symbols]] represent definitions
+ * - [[scala.reflect.api.Trees#Tree Trees]] represent abstract syntax trees
+ * - [[scala.reflect.api.Names#Name Names]] represent term and type names
+ * - [[scala.reflect.api.Annotations#Annotation Annotations]] represent annotations
+ * - [[scala.reflect.api.Positions#Position Positions]] represent source positions of tree nodes
+ * - [[scala.reflect.api.FlagSets#FlagSet FlagSet]] represent sets of flags that apply to symbols and
+ * definition trees
+ * - [[scala.reflect.api.Constants#Constant Constants]] represent compile-time constants.
+ *
+ * Each of these types are defined in their own enclosing traits, which are ultimately all inherited by class
+ * [[scala.reflect.api.Universe Universe]]. The main universe defines a minimal interface to the above types.
+ * Universes that provide additional functionality such as deeper introspection or runtime code generation,
+ * are defined in packages [[scala.reflect.macros]] and `scala.tools.reflect`.
+ *
+ * The cake pattern employed here requires to write certain Scala idioms with more indirections that usual.
+ * What follows is a description of these indirections, which will help to navigate the Scaladocs easily.
+ *
+ * For instance, consider the base type of all abstract syntax trees: [[scala.reflect.api.Trees#Tree]].
+ * This type is not a class but is abstract and has an upper bound of [[scala.reflect.api.Trees#TreeApi]],
+ * which is a class defining the minimal base interface for all trees.
+ *
+ * For a more interesting tree type, consider [[scala.reflect.api.Trees#If]] representing if-expressions.
+ * It is defined next to a value `If` of type [[scala.reflect.api.Trees#IfExtractor]].
+ * This value serves as the companion object defining a factory method `apply` and a corresponding `unapply`
+ * for pattern matching.
+ *
+ * {{{
+ * import scala.reflect.runtime.universe._
+ * val cond = reify{ condition }.tree // <- just some tree representing a condition
+ * val body = Literal(Constant(1))
+ * val other = Literal(Constant(2))
+ * val iftree = If(cond,body,other)
+ * }}}
+ *
+ * is equivalent to
+ *
+ * {{{
+ * import scala.reflect.runtime.universe._
+ * val iftree = reify{ if( condition ) 1 else 2 }.tree
+ * }}}
+ *
+ * and can be pattern matched as
+ *
+ * {{{
+ * iftree match { case If(cond,body,other) => ... }
+ * }}}
+ *
+ * Moreover, there is an implicit value [[scala.reflect.api.Trees#IfTag]] of type
+ * `ClassTag[If]` that is used by the Scala compiler so that we can indeed pattern match on `If`:
+ * {{{
+ * iftree match { case _:If => ... }
+ * }}}
+ * Without the given implicit value, this pattern match would raise an "unchecked" warning at compile time
+ * since `If` is an abstract type that gets erased at runtime. See [[scala.reflect.ClassTag]] for details.
+ *
+ * To summarize: each tree type `X` (and similarly for other types such as `Type` or `Symbol`) is represented
+ * by an abstract type `X`, optionally together with a class `XApi` that defines `X`'s' interface.
+ * `X`'s companion object, if it exists, is represented by a value `X` that is of type `XExtractor`.
+ * Moreover, for each type `X`, there is a value `XTag` of type `ClassTag[X]` that allows to pattern match on `X`.
+ */
abstract class Universe extends Symbols
with Types
with FlagSets
diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala
index 0b2a43936e..d3eef59228 100644
--- a/src/reflect/scala/reflect/api/package.scala
+++ b/src/reflect/scala/reflect/api/package.scala
@@ -2,72 +2,211 @@ package scala.reflect
import scala.reflect.api.{Universe => ApiUniverse}
-/**
- * The main package of Scala's reflection library.
- *
- * The reflection library is structured according to the 'cake pattern'. The main layer
- * resides in package [[scala.reflect.api]] and defines an interface to the following main types:
- *
- * - [[scala.reflect.api.Types#Type Types]] represent types
- * - [[scala.reflect.api.Symbols#Symbol Symbols]] represent definitions
- * - [[scala.reflect.api.Trees#Tree Trees]] represent abstract syntax trees
- * - [[scala.reflect.api.Names#Name Names]] represent term and type names
- * - [[scala.reflect.api.Annotations#Annotation Annotations]] represent annotations
- * - [[scala.reflect.api.Positions#Position Positions]] represent source positions of tree nodes
- * - [[scala.reflect.api.FlagSets#FlagSet FlagSet]] represent sets of flags that apply to symbols and
- * definition trees
- * - [[scala.reflect.api.Constants#Constant Constants]] represent compile-time constants.
- *
- * Each of these types are defined in their own enclosing traits, which are ultimately all inherited by class
- * [[scala.reflect.api.Universe Universe]]. The main universe defines a minimal interface to the above types.
- * Universes that provide additional functionality such as deeper introspection or runtime code generation,
- * are defined in packages [[scala.reflect.api]] and `scala.tools.reflect`.
- *
- * The cake pattern employed here requires to write certain Scala idioms with more indirections that usual.
- * What follows is a description of these indirections, which will help to navigate the Scaladocs easily.
- *
- * For instance, consider the base type of all abstract syntax trees: [[scala.reflect.api.Trees#Tree]].
- * This type is not a class but is abstract and has an upper bound of [[scala.reflect.api.Trees#TreeApi]],
- * which is a class defining the minimal base interface for all trees.
- *
- * For a more interesting tree type, consider [[scala.reflect.api.Trees#If]] representing if-expressions.
- * It is defined next to a value `If` of type [[scala.reflect.api.Trees#IfExtractor]].
- * This value serves as the companion object defining a factory method `apply` and a corresponding `unapply`
- * for pattern matching.
- *
- * {{{
- * import scala.reflect.runtime.universe._
- * val cond = reify{ condition }.tree // <- just some tree representing a condition
- * val body = Literal(Constant(1))
- * val other = Literal(Constant(2))
- * val iftree = If(cond,body,other)
- * }}}
- *
- * is equivalent to
- *
- * {{{
- * import scala.reflect.runtime.universe._
- * val iftree = reify{ if( condition ) 1 else 2 }.tree
- * }}}
- *
- * and can be pattern matched as
- *
- * {{{
- * iftree match { case If(cond,body,other) => ... }
- * }}}
- *
- * Moreover, there is an implicit value [[scala.reflect.api.Trees#IfTag]] of type
- * `ClassTag[If]` that is used by the Scala compiler so that we can indeed pattern match on `If`:
- * {{{
- * iftree match { case _:If => ... }
- * }}}
- * Without the given implicit value, this pattern match would raise an "unchecked" warning at compile time
- * since `If` is an abstract type that gets erased at runtime. See [[scala.reflect.ClassTag]] for details.
- *
- * To summarize: each tree type `X` (and similarly for other types such as `Type` or `Symbol`) is represented
- * by an abstract type `X`, optionally together with a class `XApi` that defines `X`'s' interface.
- * `X`'s companion object, if it exists, is represented by a value `X` that is of type `XExtractor`.
- * Moreover, for each type `X`, there is a value `XTag` of type `ClassTag[X]` that allows to pattern match on `X`.
+/** The Scala reflection API.
+ *
+ * === Universes ===
+ *
+ * Standard reflection interfaces and implementations are all contained in the package scala-reflect.jar.
+ * This jar is needed for all operations involving either Java reflection or macro implementations.
+ * The two share a large set of operations, which are all abstracted out in the reflective core API in [[scala.reflect.api.Universe]].
+ * This universe provides a fairly complete set of reflection operations that allow to query key Scala type relations such as membership or subtyping.
+ *
+ * [[scala.reflect.api.Universe]] has two specialized sub-universes. [[scala.reflect.api.JavaUniverse]] adds operations that link symbols and types
+ * to the underlying classes and runtime values of a JVM. [[scala.reflect.macros.Universe]] adds operations which allow macros to access selected
+ * compiler data structures and operations.
+ *
+ * The main implementation object of scala-reflect.jar is named [[scala.reflect.runtime.package#universe scala.reflect.runtime.universe]].
+ * It is a global singleton, which serves as an entry point to runtime reflection.
+ * There is no analogous global singleton universe for macros. Instead, macros access the currently running compiler instance as their universe,
+ * accessible via [[scala.reflect.macros.Context#universe]].
+ *
+ * === Mirrors ===
+ *
+ * Each universe has one or more mirrors. A mirror defines a hierarchy of symbols starting with the root package
+ * `_root_` and provides methods to locate and define classes and singleton objects in that hierarchy.
+ * Mirrors for runtime reflection also provide operations to reflect on runtime instances.
+ *
+ * All universes have one root mirror each, available in the `rootMirror` field.
+ * This mirror contains standard Scala classes and types
+ * such as `Any`, `AnyRef`, `AnyVal`, `Nothing`, `Null`, and all classes loaded from scala-library.
+ * The root package of the root mirror contains the root packages of all other mirrors as members.
+ *
+ * In a Java universe each mirror is associated with a classloader. This reflects the fact that multiple classes
+ * with the same name can exist in a JVM instance, where each class is loaded by a different classloader.
+ * To model this behavior, each JVM classloader is associated with a mirror, and each mirror contains its own
+ * hierarchy of packages and classes. However, the same class may also exist in several different classloaders
+ * and mirrors because classloaders can delegate to each other. This is modelled by one level of indirection:
+ * several packages in different mirrors can link to the same class.
+ *
+ * The main access point to mirrors in runtime reflection is [[scala.reflect.runtime.package#currentMirror]],
+ * which gives a JVM reflection mirror that corresponds to the current lexical context.
+ * `currentMirror` is typically equivalent to `universe.runtimeMirror(getClass.getClassLoader)` invoked at the call site.
+ * Macro universe is not based on classloaders, therefore it has only one mirror that corresponds to the compiler classpath,
+ * accessible via [[scala.reflect.macros.Context#mirror]].
+ *
+ * === Toolboxes ===
+ *
+ * Along with runtime Java universe [[scala.reflect.api.Universe]] and compile-time macro universe [[scala.reflect.macros.Universe]],
+ * reflection API also includes a runtime compiler universe implemented in `scala.tools.reflect`. One interacts with such universes
+ * via toolboxes, instances of `scala.tools.reflect.ToolBox` declared in scala-compiler.jar.
+ *
+ * After importing the `scala.tools.reflect.ToolBox` implicit conversion, runtime reflection mirrors gain the `mkToolBox` method
+ * that lets one create runtime compiler instances, optionally providing custom `options` string and a custom `frontEnd` that determines
+ * how to process warnings and errors emitted by the compilers. Toolboxes have such methods as `parse`, `typeCheck`, `inferImplicitValue`, `compile` and `eval`.
+ *
+ * === Known issues ===
+ *
+ * In Scala 2.10.0, reflection API and its implementation have experimental status. This means that the API and the docs are not complete and can be changed
+ * in binary- and source-incompatible manner in 2.10.1. This also means that the implementation has known issues. Here are some useful links:
+ * - [[https://issues.scala-lang.org/secure/IssueNavigator.jspa?mode=hide&requestId=10908 Known issues in reflection and macros]]
+ * - [[http://stackoverflow.com/questions/tagged/scala+reflection Questions tagged "scala" and "reflection" at Stack Overflow]]
+ *
+ * === Using runtime reflection ===
+ *
+ * Suppose we want to invoke the `head` method on `List(1, 2)`. This can be done in four steps, which include:
+ * 1) setting up the environment, 2) getting to a symbol that represents `head`, 3) creating
+ * a method mirror for `head`, 4) invoking the method mirror.
+ *
+ * === Step 1: Setting up the environment ===
+ *
+ * To do anything with reflection one needs to decide on a universe. The universe of choice for
+ * runtime reflection is [[scala.reflect.runtime.package#universe scala.reflect.runtime.universe]].
+ * A commonplace idiom is to do a blanket import `import scala.reflect.runtime.universe._` to get
+ * access to all types and methods declared inside the universe.
+ *
+ * {{{
+ * scala> import scala.reflect.runtime.universe._
+ * import scala.reflect.runtime.universe._
+ * }}}
+ *
+ * The next step is creating a mirror. On JVM mirrors are in one-to-one correspondence with classloaders.
+ * Another common idiom is to create a mirror from `getClass.getClassLoader`, the classloader of the
+ * current class. In most cases that will do, but if the structure of classloaders in your application
+ * is more complex than that, adjust accordingly.
+ *
+ * {{{
+ * scala> val cm = runtimeMirror(getClass.getClassLoader)
+ * cm: reflect.runtime.universe.Mirror = JavaMirror with <translating classloader> of type
+ * class scala.tools.nsc.interpreter.IMain$TranslatingClassLoader with classpath [(memory)]
+ * and parent being <url classloader> of type class scala.tools.nsc.util.ScalaClassLoader$
+ * URLClassLoader with classpath [file:/c:/PROGRA~1/Java/JDK/jre/lib/resources.jar...
+ * }}}
+ *
+ * === Step 2: Getting to a symbol that represents `head` ===
+ *
+ * We start with obtaining a type of `List` to get to the `head` symbol that represents the given method.
+ * There are three ways of doing that.
+ *
+ * The best way is to write `typeOf[List[Int]]`, which is applicable when the type
+ * of the value being inspected is known in advance, and which gives the exact information about the type.
+ * When the type is dynamic, we have to first obtain a Java class and then convert it to a Scala type,
+ * e.g. `cm.runtimeClass(list.getClass).toType`. Unfortunately then the information about the type
+ * suffers from erasure.
+ *
+ * {{{
+ * scala> typeOf[List[Int]]
+ * res0: reflect.runtime.universe.Type = scala.List[Int]
+ *
+ * scala> cm.classSymbol(List(1, 2).getClass).toType
+ * res1: reflect.runtime.universe.Type = scala.collection.immutable.::[B]
+ * }}}
+ *
+ * A compromise solution, which allows to preserve the exact type information, involves `TypeTag`
+ * context bounds. If the value being inspected is an argument of a function, then we can make
+ * the corresponding parameter generic and annotated the introduced type parameter with a type tag.
+ * After we do that, the compiler will preserve exact types of arguments passed to a function,
+ * available via `typeOf`.
+ *
+ * {{{
+ * scala> def invokeHead(x: Any): Any = {
+ * | // type of x is unknown, the best we can do is to approximate
+ * | println(cm.classSymbol(x.getClass).toType)
+ * | }
+ * invokeHead: (x: Any)Any
+ *
+ * scala> invokeHead(List(1, 2))
+ * scala.collection.immutable.::[B]
+ *
+ * scala> invokeHead(List("x"))
+ * scala.collection.immutable.::[B]
+ *
+ * scala> def invokeHead[T: TypeTag](x: T): Any = {
+ * | // type of x is preserved by the compiler
+ * | println(typeOf[T])
+ * | }
+ * invokeHead: [T](x: T)(implicit evidence$1: reflect.runtime.universe.TypeTag[T])Any
+ *
+ * scala> invokeHead(List(1, 2))
+ * List[Int]
+ *
+ * scala> invokeHead(List("x"))
+ * List[java.lang.String]
+ * }}}
+ *
+ * Having a type at hand it is straightforward to traverse its members and obtain a symbol
+ * that represents `head`.
+ *
+ * {{{
+ * scala> val head = typeOf[List[Int]].member("head": TermName).asMethod
+ * head: reflect.runtime.universe.MethodSymbol = method head
+ * }}}
+ *
+ * Note the `asMethod` cast following the invocation of `member`. In Scala reflection symbol-returning methods
+ * don't raise exceptions, but rather produce `NoSymbol`, a special singleton, which is a null object for symbols.
+ * Therefore to use such APIs one has to first check whether a callee returned a valid symbol and, if yes, then perform
+ * a cast using one of the `asTerm`, `asMethod`, `asModule`, `asType` or `asClass` methods.
+ *
+ * Also be careful with overloaded methods, which are represented as instances of `TermSymbol`, not `MethodSymbol`,
+ * with multiple `alternatives` of type `MethodSymbol` that have to be resolved manually. This and other gotchas with
+ * symbol loading are discussed on [[scala.reflect.api.Symbols the documentation page about symbols]].
+ *
+ * === Step 3: Creating a method mirror for `head` ===
+ *
+ * In Scala reflection, all reflective invocations go through mirrors created with `reflectXXX` methods.
+ * For example, to get a singleton instance of an `object`, one needs to reflect a `ModuleSymbol` to obtain
+ * a `ModuleMirror`, which provides the `instance` method.
+ *
+ * In our case we need to reflect an instance being processed, producing an `InstanceMirror`, then reflect
+ * a method symbol loaded during the previous step, producing a `MethodMirror`. Finally, method mirrors
+ * provide the `apply` method that performs reflective invocations.
+ *
+ * {{{
+ * scala> val im = cm.reflect(List(1, 2))
+ * im: reflect.runtime.universe.InstanceMirror = instance mirror for List(1, 2)
+ *
+ * scala> val mm = im.reflectMethod(head)
+ * mm: reflect.runtime.universe.MethodMirror = method mirror for
+ * scala.collection.IterableLike.head: A (bound to List(1, 2))
+ * }}}
+ *
+ * === Step 4: Invoking the method mirror ===
+ *
+ * The final step is straightforward. Reflective invocation of a method is as simple as calling
+ * the `apply` method of a `MethodMirror`:
+ *
+ * {{{
+ * scala> mm()
+ * res1 @ 758f3dae: Any = 1
+ * }}}
+ *
+ * === Conclusion ===
+ *
+ * As specified in the documentation of traits declared in [[scala.reflect.api.Mirrors]],
+ * in a similar fashion (by using `reflectXXX` methods), it is possible to:
+ * - Get and set field values
+ * - Instantiate classes
+ * - Obtain singleton instances of objects
+ *
+ * However there's much more to Scala reflection, with examples on other documentation pages answering the following questions:
+ * - [[scala.reflect.api.Symbols How to get a Symbol that corresponds to a given definition?]]
+ * - [[scala.reflect.api.Types How to get a Type of some Scala code?]]
+ * - [[scala.reflect.api.Trees How to get a Tree that corresponds to some Scala code?]]
+ * - [[scala.reflect.api.Trees How to parse a string into a Tree?]]
+ * - [[scala.reflect.api.Trees How to compile or evaluate a Tree?]]
+ * - [[scala.reflect.api.Annotations How to get Java and/or Scala annotations attached to a given definition?]]
+ * - [[scala.reflect.api.Printers How to inspect internal structure of reflection artifacts?]]
+ * - [[scala.reflect.api.Importers How to move reflection artifacts from one universe to another?]]
+ * - [[scala.reflect.macros.package How to use compile-time reflection in macros?]]
*/
package object api {
diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala
index d4225bcff5..5456d66584 100644
--- a/src/reflect/scala/reflect/internal/util/Position.scala
+++ b/src/reflect/scala/reflect/internal/util/Position.scala
@@ -35,6 +35,50 @@ object Position {
}
}
+/** The Position class and its subclasses represent positions of ASTs and symbols.
+ * Except for NoPosition and FakePos, every position refers to a SourceFile
+ * and to an offset in the sourcefile (its `point`). For batch compilation,
+ * that's all. For interactive IDE's there are also RangePositions
+ * and TransparentPositions. A RangePosition indicates a start and an end
+ * in addition to its point. TransparentPositions are a subclass of RangePositions.
+ * Range positions that are not transparent are called opaque.
+ * Trees with RangePositions need to satisfy the following invariants.
+ *
+ * INV1: A tree with an offset position never contains a child
+ * with a range position
+ * INV2: If the child of a tree with a range position also has a range position,
+ * then the child's range is contained in the parent's range.
+ * INV3: Opaque range positions of children of the same node are non-overlapping
+ * (this means their overlap is at most a single point).
+ *
+ * The following tests are useful on positions:
+ *
+ * pos.isDefined true if position is not a NoPosition nor a FakePosition
+ * pos.isRange true if position is a range
+ * pos.isOpaqueRange true if position is an opaque range
+ *
+ * The following accessor methods are provided:
+ *
+ * pos.source The source file of the position, which must be defined
+ * pos.point The offset of the position's point, which must be defined
+ * pos.start The start of the position, which must be a range
+ * pos.end The end of the position, which must be a range
+ *
+ * There are also convenience methods, such as
+ *
+ * pos.startOrPoint
+ * pos.endOrPoint
+ * pos.pointOrElse(default)
+ *
+ * These are less strict about the kind of position on which they can be applied.
+ *
+ * The following conversion methods are often used:
+ *
+ * pos.focus converts a range position to an offset position, keeping its point;
+ * returns all other positions unchanged.
+ * pos.makeTransparent converts an opaque range position into a transparent one.
+ * returns all other positions unchanged.
+ */
abstract class Position extends scala.reflect.api.Position { self =>
type Pos = Position
diff --git a/src/reflect/scala/reflect/macros/Aliases.scala b/src/reflect/scala/reflect/macros/Aliases.scala
index 754335d50d..7f7ab66848 100644
--- a/src/reflect/scala/reflect/macros/Aliases.scala
+++ b/src/reflect/scala/reflect/macros/Aliases.scala
@@ -1,33 +1,109 @@
package scala.reflect
package macros
+/** A slice of [[scala.reflect.macros.Context the Scala macros context]] that defines shorthands for the
+ * most frequently used types and functions of the underlying compiler universe.
+ */
trait Aliases {
self: Context =>
+ /** The type of symbols representing declarations. */
type Symbol = universe.Symbol
+
+ /** The type of Scala types, and also Scala type signatures.
+ * (No difference is internally made between the two).
+ */
type Type = universe.Type
+
+ /** The abstract type of names. */
type Name = universe.Name
+
+ /** The abstract type of names representing terms. */
type TermName = universe.TermName
+
+ /** The abstract type of names representing types. */
type TypeName = universe.TypeName
+
+ /** The type of Scala abstract syntax trees. */
type Tree = universe.Tree
+
+ /** Defines a universe-specific notion of positions. */
type Position = universe.Position
+
+ /** The base type of all scopes. */
type Scope = universe.Scope
+
+ /** The type of tree modifiers. */
type Modifiers = universe.Modifiers
+
+ /** The type of compilation runs. */
type Run = universe.Run
+
+ /** The type of compilation units. */
type CompilationUnit = universe.CompilationUnit
+ /** Expr wraps an abstract syntax tree and tags it with its type. */
type Expr[+T] = universe.Expr[T]
+
+ /** Constructor/Extractor for `Expr`. */
val Expr = universe.Expr
+
+ /** A shorthand to create an expr.
+ *
+ * Unlike the conventional expr factory, which requires a [[scala.reflect.api.TreeCreator]],
+ * this one accepts a regular tree, but the resulting exprs are unable of being migrated
+ * to other universes/mirrors (the functionality normally not needed for macros, since there is
+ * only one compile-time universe and only one compile-time mirror).
+ */
def Expr[T: WeakTypeTag](tree: Tree): Expr[T]
+ /** The type of weak type tags. */
type WeakTypeTag[T] = universe.WeakTypeTag[T]
+
+ /** The type of type tags. */
type TypeTag[T] = universe.TypeTag[T]
+
+ /** Constructor/Extractor for `WeakTypeTag`. */
val WeakTypeTag = universe.WeakTypeTag
+
+ /** Constructor/Extractor for `TypeTag`. */
val TypeTag = universe.TypeTag
+
+ /** A shorthand to create a weak type tag.
+ *
+ * Unlike the conventional type tag factory, which requires a [[scala.reflect.api.TypeCreator]],
+ * this one accepts a regular type, but the resulting type tags are unable of being migrated
+ * to other universes/mirrors (the functionality normally not needed for macros, since there is
+ * only one compile-time universe and only one compile-time mirror).
+ */
def WeakTypeTag[T](tpe: Type): WeakTypeTag[T]
+
+ /** A shorthand to create a type tag.
+ *
+ * Unlike the conventional type tag factory, which requires a [[scala.reflect.api.TypeCreator]],
+ * this one accepts a regular type, but the resulting type tags are unable of being migrated
+ * to other universes/mirrors (the functionality normally not needed for macros, since there is
+ * only one compile-time universe and only one compile-time mirror).
+ */
def TypeTag[T](tpe: Type): TypeTag[T]
+
+ /**
+ * Shortcut for `implicitly[WeakTypeTag[T]]`
+ */
def weakTypeTag[T](implicit attag: WeakTypeTag[T]) = attag
+
+ /**
+ * Shortcut for `implicitly[TypeTag[T]]`
+ */
def typeTag[T](implicit ttag: TypeTag[T]) = ttag
+
+ /**
+ * Shortcut for `implicitly[WeakTypeTag[T]].tpe`
+ */
def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = attag.tpe
+
+ /**
+ * Shortcut for `implicitly[TypeTag[T]].tpe`
+ */
def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
}
diff --git a/src/reflect/scala/reflect/macros/Context.scala b/src/reflect/scala/reflect/macros/Context.scala
index 7a365ed37b..1c01bbd5dc 100644
--- a/src/reflect/scala/reflect/macros/Context.scala
+++ b/src/reflect/scala/reflect/macros/Context.scala
@@ -5,6 +5,25 @@ package macros
// the most lightweight context should just expose the stuff from the SIP
// the full context should include all traits from scala.reflect.macros (and probably reside in scala-compiler.jar)
+/** The Scala macros context.
+ *
+ * See [[scala.reflect.macros.package the overview page]] for a description of how macros work. This documentation
+ * entry provides information on the API available to macro writers.
+ *
+ * A macro context wraps a compiler universe exposed in `universe` and having type [[scala.reflect.macros.Universe]].
+ * This type is a refinement over the generic reflection API provided in [[scala.reflect.api.Universe]]. The
+ * extended Universe provides mutability for reflection artifacts (e.g. macros can change types of compiler trees,
+ * add annotation to symbols representing definitions, etc) and exposes some internal compiler functionality
+ * such as `Symbol.deSkolemize` or `Tree.attachments`.
+ *
+ * Another fundamental part of a macro context is `macroApplication`, which provides access to the tree undergoing
+ * macro expansion. Parts of this tree can be found in arguments of the corresponding macro implementations and
+ * in `prefix`, but `macroApplication` gives the full picture.
+ *
+ * Other than that, macro contexts provide facilities for typechecking, exploring the compiler's symbol table and
+ * enclosing trees and compilation units, evaluating trees, logging warnings/errors and much more.
+ * Refer to the documentation of top-level traits in this package to learn the details.
+ */
trait Context extends Aliases
with Enclosures
with Names
@@ -16,15 +35,53 @@ trait Context extends Aliases
with Evals
with ExprUtils {
- /** The compile-time universe */
+ /** The compile-time universe. */
val universe: Universe
- /** The mirror of the compile-time universe */
+ /** The mirror of the compile-time universe. */
val mirror: universe.Mirror
- /** The type of the prefix tree from which the macro is selected */
+ /** The type of the prefix tree from which the macro is selected.
+ * See the documentation entry for `prefix` for an example.
+ */
type PrefixType
- /** The prefix tree from which the macro is selected */
+ /** The prefix tree from which the macro is selected.
+ *
+ * For a example, for a macro `filter` defined as an instance method on a collection `Coll`,
+ * `prefix` represents an equivalent of `this` for normal instance methods:
+ *
+ * {{{
+ * scala> class Coll[T] {
+ * | def filter(p: T => Boolean): Coll[T] = macro M.filter[T]
+ * | }; object M {
+ * | def filter[T](c: Context { type PrefixType = Coll[T] })
+ * | (p: c.Expr[T => Boolean]): c.Expr[Coll[T]] =
+ * | {
+ * | println(c.prefix.tree)
+ * | c.prefix
+ * | }
+ * | }
+ * defined class Coll
+ * defined module Macros
+ *
+ * scala> new Coll[Int]().filter(_ % 2 == 0)
+ * new Coll[Int]()
+ * res0: Coll[Int] = ...
+ *
+ * scala> val x = new Coll[String]()
+ * x: Coll[String] = ...
+ *
+ * scala> x.filter(_ != "")
+ * $line11.$read.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.x
+ * res1 @ 35563b4b: x.type = ...
+ * }}}
+ *
+ * Note how the value of `prefix` changes depending on the qualifier of the macro call
+ * (i.e. the expression that is at the left-hand side of the dot).
+ *
+ * Another noteworthy thing about the snippet above is the `Context { type PrefixType = Coll[T] }`
+ * type that is used to stress that the macro implementation works with prefixes of type `Coll[T]`.
+ */
val prefix: Expr[PrefixType]
}
diff --git a/src/reflect/scala/reflect/macros/Enclosures.scala b/src/reflect/scala/reflect/macros/Enclosures.scala
index 218cf6ebb3..41d6af94e3 100644
--- a/src/reflect/scala/reflect/macros/Enclosures.scala
+++ b/src/reflect/scala/reflect/macros/Enclosures.scala
@@ -1,6 +1,11 @@
package scala.reflect
package macros
+/** A slice of [[scala.reflect.macros.Context the Scala macros context]] that exposes
+ * enclosing trees (method, class, compilation unit and currently compiled application),
+ * the enclosing position of the macro expansion, as well as macros and implicits
+ * that are currently in-flight.
+ */
trait Enclosures {
self: Context =>
diff --git a/src/reflect/scala/reflect/macros/Evals.scala b/src/reflect/scala/reflect/macros/Evals.scala
index 3837d749da..69885c219c 100644
--- a/src/reflect/scala/reflect/macros/Evals.scala
+++ b/src/reflect/scala/reflect/macros/Evals.scala
@@ -1,9 +1,54 @@
package scala.reflect
package macros
+/** A slice of [[scala.reflect.macros.Context the Scala macros context]] that provides
+ * a facility to evaluate trees.
+ */
trait Evals {
self: Context =>
- /** .. */
+ /** Takes a typed wrapper for a tree of type `T` and evaluates it to a value of type `T`.
+ *
+ * Can be used to perform compile-time computations on macro arguments to the extent
+ * permitted by the shape of the arguments.
+ *
+ * Known issues: because of [[https://issues.scala-lang.org/browse/SI-5748 https://issues.scala-lang.org/browse/SI-5748]]
+ * trees being evaluated first need to undergo `resetAllAttrs`. Resetting symbols and types
+ * mutates the tree in place, therefore the conventional approach is to `duplicate` the tree first.
+ *
+ * {{{
+ * scala> def impl(c: Context)(x: c.Expr[String]) = {
+ * | val x1 = c.Expr[String](c.resetAllAttrs(x.tree.duplicate))
+ * | println(s"compile-time value is: ${c.eval(x1)}")
+ * | x
+ * | }
+ * impl: (c: Context)(x: c.Expr[String])c.Expr[String]
+ *
+ * scala> def test(x: String) = macro impl
+ * test: (x: String)String
+ *
+ * scala> test("x")
+ * compile-time value is: x
+ * res0: String = x
+ *
+ * scala> test("x" + "y")
+ * compile-time value is: xy
+ * res1: String = xy
+ *
+ * scala> val x = "x"
+ * x: String = x
+ *
+ * scala> test(x + "y")
+ * compile-time value is: xy
+ * res2: String = xy
+ *
+ * scala> { val x = "x"; test(x + "y") }
+ * error: exception during macro expansion:
+ * scala.tools.reflect.ToolBoxError: reflective compilation failed
+ * }}}
+ *
+ * Note that in the last case evaluation has failed, because the argument of a macro
+ * refers to a runtime value `x`, which is unknown at compile time.
+ */
def eval[T](expr: Expr[T]): T
} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/macros/ExprUtils.scala b/src/reflect/scala/reflect/macros/ExprUtils.scala
index adcdc78c78..a9acc61735 100644
--- a/src/reflect/scala/reflect/macros/ExprUtils.scala
+++ b/src/reflect/scala/reflect/macros/ExprUtils.scala
@@ -1,32 +1,48 @@
package scala.reflect
package macros
+/** A slice of [[scala.reflect.macros.Context the Scala macros context]] that defines shorthands for the
+ * most common `Expr`-creating functions.
+ */
trait ExprUtils {
self: Context =>
+ /** Shorthand for `Literal(Constant(null))` in the underlying `universe`. */
def literalNull: Expr[Null]
+ /** Shorthand for `Literal(Constant(()))` in the underlying `universe`. */
def literalUnit: Expr[Unit]
+ /** Shorthand for `Literal(Constant(true))` in the underlying `universe`. */
def literalTrue: Expr[Boolean]
+ /** Shorthand for `Literal(Constant(false))` in the underlying `universe`. */
def literalFalse: Expr[Boolean]
+ /** Shorthand for `Literal(Constant(x: Boolean))` in the underlying `universe`. */
def literal(x: Boolean): Expr[Boolean]
+ /** Shorthand for `Literal(Constant(x: Byte))` in the underlying `universe`. */
def literal(x: Byte): Expr[Byte]
+ /** Shorthand for `Literal(Constant(x: Short))` in the underlying `universe`. */
def literal(x: Short): Expr[Short]
+ /** Shorthand for `Literal(Constant(x: Int))` in the underlying `universe`. */
def literal(x: Int): Expr[Int]
+ /** Shorthand for `Literal(Constant(x: Long))` in the underlying `universe`. */
def literal(x: Long): Expr[Long]
+ /** Shorthand for `Literal(Constant(x: Float))` in the underlying `universe`. */
def literal(x: Float): Expr[Float]
+ /** Shorthand for `Literal(Constant(x: Double))` in the underlying `universe`. */
def literal(x: Double): Expr[Double]
+ /** Shorthand for `Literal(Constant(x: String))` in the underlying `universe`. */
def literal(x: String): Expr[String]
+ /** Shorthand for `Literal(Constant(x: Char))` in the underlying `universe`. */
def literal(x: Char): Expr[Char]
}
diff --git a/src/reflect/scala/reflect/macros/FrontEnds.scala b/src/reflect/scala/reflect/macros/FrontEnds.scala
index e6b67cfc87..8c47202342 100644
--- a/src/reflect/scala/reflect/macros/FrontEnds.scala
+++ b/src/reflect/scala/reflect/macros/FrontEnds.scala
@@ -1,30 +1,44 @@
package scala.reflect
package macros
+/** A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * provides facilities to communicate with the compiler's front end
+ * (emit warnings, errors and other sorts of messages).
+ */
trait FrontEnds {
self: Context =>
/** For sending a message which should not be labeled as a warning/error,
* but also shouldn't require -verbose to be visible.
- * Use ``enclosingPosition'' if you're in doubt what position to pass to ``pos''.
+ * Use `enclosingPosition` if you're in doubt what position to pass to `pos`.
*/
def echo(pos: Position, msg: String): Unit
- /** Informational messages, suppressed unless -verbose or force=true.
- * Use ``enclosingPosition'' if you're in doubt what position to pass to ``pos''.
+ /** Emits an informational message, suppressed unless `-verbose` or `force=true`.
+ * Use `enclosingPosition` if you're in doubt what position to pass to `pos`.
*/
def info(pos: Position, msg: String, force: Boolean): Unit
- /** Warnings and errors.
- * Use ``enclosingPosition'' if you're in doubt what position to pass to ``pos''.
+ /** Does the compilation session have any warnings?
*/
def hasWarnings: Boolean
- def hasErrors: Boolean
+
+ /** Emits a warning.
+ * Use `enclosingPosition` if you're in doubt what position to pass to `pos`.
+ */
def warning(pos: Position, msg: String): Unit
+
+ /** Does the compilation session have any errors?
+ */
+ def hasErrors: Boolean
+
+ /** Emits a compilation error.
+ * Use `enclosingPosition` if you're in doubt what position to pass to `pos`.
+ */
def error(pos: Position, msg: String): Unit
/** Abruptly terminates current macro expansion leaving a note about what happened.
- * Use ``enclosingPosition'' if you're in doubt what position to pass to ``pos''.
+ * Use `enclosingPosition` if you're in doubt what position to pass to `pos`.
*/
def abort(pos: Position, msg: String): Nothing
} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/macros/Infrastructure.scala b/src/reflect/scala/reflect/macros/Infrastructure.scala
index a1ef1c87a3..2f3b8e8d19 100644
--- a/src/reflect/scala/reflect/macros/Infrastructure.scala
+++ b/src/reflect/scala/reflect/macros/Infrastructure.scala
@@ -1,6 +1,9 @@
package scala.reflect
package macros
+/** A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * provides facilities to communicate with the compiler's infrastructure.
+ */
trait Infrastructure {
self: Context =>
diff --git a/src/reflect/scala/reflect/macros/Names.scala b/src/reflect/scala/reflect/macros/Names.scala
index fab9bbbca5..20e750b225 100644
--- a/src/reflect/scala/reflect/macros/Names.scala
+++ b/src/reflect/scala/reflect/macros/Names.scala
@@ -1,15 +1,20 @@
package scala.reflect
package macros
+/** A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * provides functions that generate unique names.
+ */
trait Names {
self: Context =>
- /** Creates a fresh string */
+ /** Creates a unique string. */
def fresh(): String
- /** Creates a fresh string from the provided string */
+ /** Creates a unique string having a given prefix. */
def fresh(name: String): String
- /** Creates a fresh name from the provided name */
+ /** Creates a unique name having a given name as a prefix and
+ * having the same flavor (term name or type name) as the given name.
+ */
def fresh[NameType <: Name](name: NameType): NameType
}
diff --git a/src/reflect/scala/reflect/macros/Parsers.scala b/src/reflect/scala/reflect/macros/Parsers.scala
index d3aabcff0d..daf490c275 100644
--- a/src/reflect/scala/reflect/macros/Parsers.scala
+++ b/src/reflect/scala/reflect/macros/Parsers.scala
@@ -1,12 +1,16 @@
package scala.reflect
package macros
+/** A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * exposes functions to parse strings with Scala code into trees.
+ */
trait Parsers {
self: Context =>
- /** .. */
- // todo. distinguish between parsing an expression and parsing arbitrary code
- // for example, parsing in expression mode will fail on packages
+ /** Parses a string with a Scala expression into an abstract syntax tree.
+ * Only works for expressions, i.e. parsing a package declaration will fail.
+ * @throws [[scala.reflect.macros.ParseException]]
+ */
def parse(code: String): Tree
}
diff --git a/src/reflect/scala/reflect/macros/Reifiers.scala b/src/reflect/scala/reflect/macros/Reifiers.scala
index 0022a488b9..d7ee30c7d9 100644
--- a/src/reflect/scala/reflect/macros/Reifiers.scala
+++ b/src/reflect/scala/reflect/macros/Reifiers.scala
@@ -1,6 +1,9 @@
package scala.reflect
package macros
+/** A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * exposes functions to save reflection artifacts for runtime.
+ */
trait Reifiers {
self: Context =>
diff --git a/src/reflect/scala/reflect/macros/TreeBuilder.scala b/src/reflect/scala/reflect/macros/TreeBuilder.scala
index 5f18ab9ee8..727387c5af 100644
--- a/src/reflect/scala/reflect/macros/TreeBuilder.scala
+++ b/src/reflect/scala/reflect/macros/TreeBuilder.scala
@@ -1,6 +1,9 @@
package scala.reflect
package macros
+/** A helper available in [[scala.reflect.macros.Universe]] that defines shorthands for the
+ * most common tree-creating functions.
+ */
abstract class TreeBuilder {
val global: Universe
@@ -46,12 +49,26 @@ abstract class TreeBuilder {
* @return the newly created trees.
*/
def mkMethodCall(receiver: Symbol, methodName: Name, targs: List[Type], args: List[Tree]): Tree
+
+ /** TODO how to refer to the main `mkMethodCall`? */
def mkMethodCall(method: Symbol, targs: List[Type], args: List[Tree]): Tree
+
+ /** TODO how to refer to the main `mkMethodCall`? */
def mkMethodCall(method: Symbol, args: List[Tree]): Tree
+
+ /** TODO how to refer to the main `mkMethodCall`? */
def mkMethodCall(target: Tree, args: List[Tree]): Tree
+
+ /** TODO how to refer to the main `mkMethodCall`? */
def mkMethodCall(receiver: Symbol, methodName: Name, args: List[Tree]): Tree
+
+ /** TODO how to refer to the main `mkMethodCall`? */
def mkMethodCall(receiver: Tree, method: Symbol, targs: List[Type], args: List[Tree]): Tree
+
+ /** TODO how to refer to the main `mkMethodCall`? */
def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree
+
+ /** TODO how to refer to the main `mkMethodCall`? */
def mkNullaryCall(method: Symbol, targs: List[Type]): Tree
/** A tree that refers to the runtime reflexive universe, ``scala.reflect.runtime.universe''. */
diff --git a/src/reflect/scala/reflect/macros/Typers.scala b/src/reflect/scala/reflect/macros/Typers.scala
index 9c4854f89f..016a08bd01 100644
--- a/src/reflect/scala/reflect/macros/Typers.scala
+++ b/src/reflect/scala/reflect/macros/Typers.scala
@@ -1,6 +1,9 @@
package scala.reflect
package macros
+/** A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * partially exposes the type checker to macro writers.
+ */
trait Typers {
self: Context =>
diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala
index 3e38691d85..f270671fb1 100644
--- a/src/reflect/scala/reflect/macros/Universe.scala
+++ b/src/reflect/scala/reflect/macros/Universe.scala
@@ -1,18 +1,33 @@
package scala.reflect
package macros
+/** The refinement of [[scala.reflect.api.Universe]] for the use by macro writers.
+ *
+ * This universe provides mutability for reflection artifacts (e.g. macros can change types of compiler trees,
+ * add annotation to symbols representing definitions, etc) and exposes some internal compiler functionality
+ * such as `Symbol.deSkolemize` or `Tree.attachments`.
+ */
abstract class Universe extends scala.reflect.api.Universe {
+ /** A factory that encapsulates common tree-building functions. */
val treeBuild: TreeBuilder { val global: Universe.this.type }
+ /** The API of reflection artifacts that support [[scala.reflect.macros.Attachments]].
+ * These artifacts are trees and symbols.
+ */
trait AttachableApi {
- /** ... */
+ /** The attachment of the reflection artifact. */
def attachments: Attachments { type Pos = Position }
- /** ... */
+ /** Updates the attachment with the payload slot of T added/updated with the provided value.
+ * Replaces an existing payload of the same type, if exists.
+ * Returns the reflection artifact itself.
+ */
def updateAttachment[T: ClassTag](attachment: T): AttachableApi.this.type
- /** ... */
+ /** Update the attachment with the payload of the given class type `T` removed.
+ * Returns the reflection artifact itself.
+ */
def removeAttachment[T: ClassTag]: AttachableApi.this.type
}
@@ -24,18 +39,43 @@ abstract class Universe extends scala.reflect.api.Universe {
*/
trait SymbolContextApi extends SymbolApi with AttachableApi { self: Symbol =>
+ /** If this symbol is a skolem, its corresponding type parameter, otherwise the symbol itself.
+ *
+ * [[https://groups.google.com/forum/#!msg/scala-internals/0j8laVNTQsI/kRXMF_c8bGsJ To quote Martin Odersky]],
+ * skolems are synthetic type "constants" that are copies of existentially bound or universally
+ * bound type variables. E.g. if one is inside the right-hand side of a method:
+ *
+ * {{{
+ * def foo[T](x: T) = ... foo[List[T]]....
+ * }}}
+ *
+ * the skolem named `T` refers to the unknown type instance of `T` when `foo` is called. It needs to be different
+ * from the type parameter because in a recursive call as in the `foo[List[T]]` above the type parameter gets
+ * substituted with `List[T]`, but the ''type skolem'' stays what it is.
+ *
+ * The other form of skolem is an ''existential skolem''. Say one has a function
+ *
+ * {{{
+ * def bar(xs: List[T] forSome { type T }) = xs.head
+ * }}}
+ *
+ * then each occurrence of `xs` on the right will have type `List[T']` where `T'` is a fresh copy of `T`.
+ */
def deSkolemize: Symbol
- /** The position of this symbol
- */
+ /** The position of this symbol. */
def pos: Position
+ /** Sets the `typeSignature` of the symbol. */
def setTypeSignature(tpe: Type): Symbol
+ /** Sets the `annotations` of the symbol. */
def setAnnotations(annots: Annotation*): Symbol
+ /** Sets the `name` of the symbol. */
def setName(name: Name): Symbol
+ /** Sets the `privateWithin` of the symbol. */
def setPrivateWithin(sym: Symbol): Symbol
}
@@ -47,17 +87,16 @@ abstract class Universe extends scala.reflect.api.Universe {
*/
trait TreeContextApi extends TreeApi with AttachableApi { self: Tree =>
- /** ... */
+ /** Sets the `pos` of the tree. Returns `Unit`. */
def pos_=(pos: Position): Unit
- /** ... */
+ /** Sets the `pos` of the tree. Returns the tree itself. */
def setPos(newpos: Position): Tree
- /** ... */
+ /** Sets the `tpe` of the tree. Returns `Unit`. */
def tpe_=(t: Type): Unit
- /** Set tpe to give `tp` and return this.
- */
+ /** Sets the `tpe` of the tree. Returns the tree itself. */
def setType(tp: Type): Tree
/** Like `setType`, but if this is a previously empty TypeTree that
@@ -79,34 +118,40 @@ abstract class Universe extends scala.reflect.api.Universe {
*/
def defineType(tp: Type): Tree
- /** ... */
+ /** Sets the `symbol` of the tree. Returns `Unit`. */
def symbol_=(sym: Symbol): Unit
- /** ... */
+ /** Sets the `symbol` of the tree. Returns the tree itself. */
def setSymbol(sym: Symbol): Tree
}
+ /** @inheritdoc */
override type SymTree >: Null <: Tree with SymTreeContextApi
/** The extended API of sym trees that's supported in macro context universes
*/
trait SymTreeContextApi extends SymTreeApi { this: SymTree =>
+ /** Sets the `symbol` field of the sym tree. */
var symbol: Symbol
}
+ /** @inheritdoc */
override type TypeTree >: Null <: TypTree with TypeTreeContextApi
/** The extended API of sym trees that's supported in macro context universes
*/
trait TypeTreeContextApi extends TypeTreeApi { this: TypeTree =>
+ /** Sets the `original` field of the type tree. */
def setOriginal(tree: Tree): this.type
}
+ /** @inheritdoc */
override type Ident >: Null <: RefTree with IdentContextApi
/** The extended API of idents that's supported in macro context universes
*/
trait IdentContextApi extends IdentApi { this: Ident =>
+ /** Was this ident created from a backquoted identifier? */
def isBackquoted: Boolean
}
@@ -123,6 +168,7 @@ abstract class Universe extends scala.reflect.api.Universe {
*/
def capturedVariableType(vble: Symbol): Type
+ /** The type of compilation runs. */
type Run <: RunContextApi
/** Compilation run uniquely identifies current invocation of the compiler
@@ -137,6 +183,7 @@ abstract class Universe extends scala.reflect.api.Universe {
def units: Iterator[CompilationUnit]
}
+ /** The type of compilation units. */
type CompilationUnit <: CompilationUnitContextApi
/** Compilation unit describes a unit of work of the compilation run.
diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala
index 6a69872367..a3211b67af 100644
--- a/src/reflect/scala/reflect/macros/package.scala
+++ b/src/reflect/scala/reflect/macros/package.scala
@@ -1,4 +1,261 @@
package scala.reflect
+/** Scala macros.
+ *
+ * === Overview ===
+ *
+ * Macros are functions that are called by the compiler during compilation.
+ * Within these functions the programmer has access to compiler APIs exposed in [[scala.reflect.macros.Context]].
+ * For example, it is possible to generate, analyze and typecheck code.
+ *
+ * Since the 2.10.0 Scala includes macros that can be enabled
+ * with `import language.experimental.macros` on per-file basis
+ * or with `-language:experimental.macros` on per-compilation basis.
+ *
+ * Macros significantly simplify code analysis and code generation, which makes them a tool of choice for
+ * a multitude of [[http://scalamacros.org/usecases/index.html real-world use cases]].
+ * Scenarios that traditionally involve writing and maintaining boilerplate can be addressed
+ * with macros in concise and maintainable way.
+ *
+ * === Writing macros ===
+ *
+ * This documentation page explains a type-safe `printf` macro through an end-to-end example.
+ * To follow the example, create a file named <code>Macros.scala</code> and paste the following
+ * code (be sure to follow the comments in the code, they reveal important things to know about
+ * the macro system, accompanying APIs and infrastructure):
+ *
+ * {{{
+ * import scala.reflect.macros.Context
+ * import collection.mutable.ListBuffer
+ * import collection.mutable.Stack
+ *
+ * object Macros {
+ * // macro definition is a normal function with almost no restrictions on its signature
+ * // its body, though, is nothing more that a reference to an implementation
+ * def printf(format: String, params: Any*): Unit = macro impl
+ *
+ * // macro implementation must correspond to macro definitions that use it
+ * // required signature is quite involved, but the compiler knows what it wants
+ * // should a mismatch occur, it will print the expected signature in the error message
+ * def impl(c: Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = {
+ * // STEP I: compiler API is exposed in scala.reflect.macros.Context
+ * // its most important part, reflection API, is accessible via c.universe
+ * // it's customary to import c.universe._
+ * // because it includes a lot of routinely used types and functions
+ * import c.universe._
+ *
+ * // STEP II: the macro starts with parsing the provided format string
+ * // macros run during the compile-time, so they operate on trees, not on values
+ * // this means that the format parameter of the macro will be a compile-time literal
+ * // not an object of type java.lang.String
+ * // this also means that the code below won't work for printf("%d" + "%d", ...)
+ * // because in that case format won't be a string literal
+ * // but rather an abstract syntax that represents addition of two string literals
+ * val Literal(Constant(s_format: String)) = format.tree
+ *
+ * // STEP IIIa: after parsing the format string, the macro needs to generate the code
+ * // that will partially perform formatting at compile-time
+ * // the paragraph below creates temporary vals that precompute the arguments
+ * // to learn about dynamic generation of Scala code, follow the documentation
+ * // on trees, available in the scala.reflect.api package
+ * val evals = ListBuffer[ValDef]()
+ * def precompute(value: Tree, tpe: Type): Ident = {
+ * val freshName = newTermName(c.fresh("eval$"))
+ * evals += ValDef(Modifiers(), freshName, TypeTree(tpe), value)
+ * Ident(freshName)
+ * }
+ *
+ * // STEP IIIb: tree manipulations proceed in this code snippet
+ * // the snippet extracts trees from parameters of a macro and transforms them
+ * // note the use of typeOf to create Scala types corresponding to forma specifiers
+ * // information on types can be found in the docs for the scala.reflect.api package
+ * val paramsStack = Stack[Tree]((params map (_.tree)): _*)
+ * val refs = s_format.split("(?<=%[\\w%])|(?=%[\\w%])") map {
+ * case "%d" => precompute(paramsStack.pop, typeOf[Int])
+ * case "%s" => precompute(paramsStack.pop, typeOf[String])
+ * case "%%" => Literal(Constant("%"))
+ * case part => Literal(Constant(part))
+ * }
+ *
+ * // STEP IV: the code that has been generated is now combined into a Block
+ * // note the call to reify, which provides a shortcut for creating ASTs
+ * // reify is discussed in details in docs for scala.reflect.api.Universe
+ * val stats = evals ++ refs.map(ref => reify(print(c.Expr[Any](ref).splice)).tree)
+ * c.Expr[Unit](Block(stats.toList, Literal(Constant(()))))
+ * }
+ * }
+ * }}}
+ *
+ * To summarize the code provided above, macros are mini-compiler plugins that get executed whenever a compiler
+ * comes across an invocation of a method declared as a macro. Such methods, dubbed ''macro definitions'', use
+ * the `macro` keyword to reference ''macro implementations''.
+ *
+ * Macro implementations use [[scala.reflect.api.package reflection API]] to communicate
+ * with the compiler. The gateway to that API is `c`, a ubiquitous parameter of type [[scala.reflect.macros.Context]]
+ * that must be present in all macro implementations. Compiler universe is available through `c.universe`.
+ *
+ * Input arguments to a macro implementation are [[scala.reflect.api.Trees abstract syntax trees]], which
+ * correspond to the arguments of the method invocation that triggered a macro expansion. These trees
+ * are wrapped in [[scala.reflect.api.Exprs exprs]], typed wrappers over trees.
+ *
+ * The end result produced by a macro implementation is an abstract syntax tree
+ * wrapped in an expr. This tree represents the code that the compiler will use
+ * to replace the original method invocation.
+ * To learn more about how to create trees that correspond to given Scala code and how to perform
+ * tree manipulations, visit [[scala.reflect.api.Trees the documentation page on trees]].
+ *
+ * === Compiling macros ===
+ *
+ * In 2.10.0 macros are an experimental feature, so they need to be enabled before use.
+ * Normal compilation of the snippet written above (using `scalac Macros.scala`) fails as follows:
+ *
+ * {{{
+ * C:/Projects/Kepler/sandbox>scalac Macros.scala
+ * Macros.scala:8: error: macro definition needs to be enabled
+ * by making the implicit value language.experimental.macros visible.
+ * This can be achieved by adding the import clause 'import language.experimental.macros'
+ * or by setting the compiler option -language:experimental.macros.
+ * See the Scala docs for value scala.language.experimental.macros for a discussion
+ * why the feature needs to be explicitly enabled.
+ * def printf(format: String, params: Any*): Unit = macro printf_impl
+ * ^
+ * one error found
+ * }}}
+ *
+ * To enable macros one should use either `import language.experimental.macros` on per-file basis
+ * or `-language:experimental.macros` (providing a compiler switch) on per-compilation basis.
+ *
+ * {{{
+ * C:/Projects/Kepler/sandbox>scalac -language:experimental.macros Macros.scala
+ * <scalac has exited with code 0>
+ * }}}
+ *
+ * === Using macros ===
+ *
+ * Create a file named <code>Test.scala</code> and paste the following code (just as simple as that,
+ * to use a macro, it's only necessary to import it and call it as it were a regular function).
+ *
+ * {{{
+ * object Test extends App {
+ * import Macros._
+ * printf("hello %s!", "world")
+ * }
+ * }}}
+ *
+ * An important rule about using macros is separate compilation. To perform macro expansion, compiler
+ * needs a macro implementation in executable form. Thus macro implementations need to be compiled before
+ * the main compilation, otherwise compiler will produce `macro implementation not found` errors.
+ *
+ * In the REPL, however, macros and their usages can be written in the same session. That's because
+ * the REPL compiles every line of input in a separate compilation run.
+ *
+ * {{{
+ * C:/Projects/Kepler/sandbox>scalac Test.scala
+ * <scalac has exited with code 0>
+ *
+ * C:/Projects/Kepler/sandbox>scala Test
+ * hello world!
+ * }}}
+ *
+ * The test snippet seems to work! To see what happens under the covers, enable the `-Ymacro-debug-lite` compiler flag.
+ *
+ * {{{
+ * C:/Projects/Kepler/sandbox>scalac -Ymacro-debug-lite Test.scala
+ * typechecking macro expansion Macros.printf("hello %s!", "world") at
+ * source-C:/Projects/Kepler/sandbox\Test.scala,line-3,offset=52
+ * {
+ * val eval$1: String = "world";
+ * scala.this.Predef.print("hello ");
+ * scala.this.Predef.print(eval$1);
+ * scala.this.Predef.print("!");
+ * ()
+ * }
+ * Block(List(
+ * ValDef(Modifiers(), newTermName("eval$1"), TypeTree(String), Literal(Constant("world"))),
+ * Apply(
+ * Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("print")),
+ * List(Literal(Constant("hello")))),
+ * Apply(
+ * Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("print")),
+ * List(Ident(newTermName("eval$1")))),
+ * Apply(
+ * Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("print")),
+ * List(Literal(Constant("!"))))),
+ * Literal(Constant(())))
+ * }}}
+ *
+ * With `-Ymacro-debug-lite` one can see both pseudo-Scala representation of the code generated by macro expansion
+ * and raw AST representation of the expansion. Both have their merits: the former is useful for surface analysis,
+ * while the latter is invaluable for fine-grained debugging.
+ *
+ * === Writing bigger macros ===
+ *
+ * When the code of a macro implementation grows big enough to warrant modularization beyond the body
+ * of the implementation method, it becomes apparent that one needs to carry around the context parameter,
+ * because most things of interest are path-dependent on the context.
+ *
+ * One of the approaches is to write a class that takes a parameter of type `Context` and then split the
+ * macro implementation into a series of methods of that class. This is natural and simple, except that
+ * it's hard to get it right. Here's a typical compilation error.
+ *
+ * {{{
+ * scala> class Helper(val c: Context) {
+ * | def generate: c.Tree = ???
+ * | }
+ * defined class Helper
+ *
+ * scala> def impl(c: Context): c.Expr[Unit] = {
+ * | val helper = new Helper(c)
+ * | c.Expr(helper.generate)
+ * | }
+ * <console>:32: error: type mismatch;
+ * found : helper.c.Tree
+ * (which expands to) helper.c.universe.Tree
+ * required: c.Tree
+ * (which expands to) c.universe.Tree
+ * c.Expr(helper.generate)
+ * ^
+ * }}}
+ *
+ * The problem in this snippet is in a path-dependent type mismatch. The Scala compiler
+ * does not understand that `c` in `impl` is the same object as `c` in `Helper`, even though the helper
+ * is constructed using the original `c`.
+ *
+ * Luckily just a small nudge is all that is needed for the compiler to figure out what's going on.
+ * One of the possible ways of doing that is using refinement types (the example below is the simplest
+ * application of the idea; for example, one could also write an implicit conversion from `Context`
+ * to `Helper` to avoid explicit instantiations and simplify the calls).
+ *
+ * {{{
+ * scala> abstract class Helper {
+ * | val c: Context
+ * | def generate: c.Tree = ???
+ * | }
+ * defined class Helper
+ *
+ * scala> def impl(c1: Context): c1.Expr[Unit] = {
+ * | val helper = new { val c: c1.type = c1 } with Helper
+ * | c1.Expr(helper.generate)
+ * | }
+ * impl: (c1: scala.reflect.macros.Context)c1.Expr[Unit]
+ * }}}
+ *
+ * An alternative approach is to use the [[scala.Singleton]] upper bound to express the fact
+ * that `Helper`'s `C` has the same identity as `impl`'s `C` (note that it is mandatory to
+ * explicitly spell out the type argument when instantiating `Helper`).
+ *
+ * {{{
+ * scala> class Helper[C <: Context with Singleton](val c: C) {
+ * | def generate: c.Tree = ???
+ * | }
+ * defined class Helper
+ *
+ * scala> def impl(c: Context): c.Expr[Unit] = {
+ * | val helper = new Helper[c.type](c)
+ * | c.Expr(helper.generate)
+ * | }
+ * impl: (c: scala.reflect.macros.Context)c.Expr[Unit]
+ * }}}
+ */
package object macros {
} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
index 1d875b10f1..87520d406c 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
@@ -3,8 +3,9 @@ package runtime
import internal.{SomePhase, NoPhase, Phase, TreeGen}
-/** The universe for standard runtime reflection from Java.
- * This type implements all abstract term members in internal.SymbolTable.
+/** An implementation of [[scala.reflect.api.Universe]] for runtime reflection using JVM classloaders.
+ *
+ * Should not be instantiated directly, use [[scala.reflect.runtime.package#universe]] instead.
*/
class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.SymbolTable { self =>
diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala
index 278629adb6..b3f9ba5817 100644
--- a/src/reflect/scala/reflect/runtime/package.scala
+++ b/src/reflect/scala/reflect/runtime/package.scala
@@ -1,10 +1,19 @@
package scala.reflect
+/** Entry points into runtime reflection.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use them.
+ */
package object runtime {
- // type is api.JavaUniverse because we only want to expose the `scala.reflect.api.*` subset of reflection
+ /** The entry point into runtime reflection.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use it.
+ */
lazy val universe: api.JavaUniverse = new runtime.JavaUniverse
+ /** The runtime reflection mirror that corresponds to the current lexical context.
+ * Is typically equivalent to `universe.runtimeMirror(getClass.getClassLoader)` invoked at the call site.
+ * See [[scala.reflect.api.package the overview page]] for details on how to use it.
+ */
// implementation hardwired to the `currentMirror` method below
// using the mechanism implemented in `scala.tools.reflect.FastTrack`
def currentMirror: universe.Mirror = ??? // macro