From 6eb48f9602c3a21c85a38651c2e0b887e06b8d18 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 4 Oct 2012 07:37:41 +0200 Subject: docs for reflection and macros --- src/reflect/scala/reflect/api/Annotations.scala | 133 +++- src/reflect/scala/reflect/api/Constants.scala | 84 +- src/reflect/scala/reflect/api/Exprs.scala | 55 +- src/reflect/scala/reflect/api/FlagSets.scala | 36 + src/reflect/scala/reflect/api/Importers.scala | 84 ++ src/reflect/scala/reflect/api/JavaMirrors.scala | 21 + src/reflect/scala/reflect/api/JavaUniverse.scala | 7 + src/reflect/scala/reflect/api/Mirror.scala | 9 +- src/reflect/scala/reflect/api/Mirrors.scala | 44 +- src/reflect/scala/reflect/api/Names.scala | 69 +- src/reflect/scala/reflect/api/Position.scala | 65 +- src/reflect/scala/reflect/api/Positions.scala | 10 +- src/reflect/scala/reflect/api/Printers.scala | 126 +++ src/reflect/scala/reflect/api/Scopes.scala | 20 +- .../scala/reflect/api/StandardDefinitions.scala | 234 +++++- src/reflect/scala/reflect/api/StandardNames.scala | 55 +- src/reflect/scala/reflect/api/Symbols.scala | 243 +++++- src/reflect/scala/reflect/api/TagInterop.scala | 20 +- src/reflect/scala/reflect/api/Trees.scala | 850 ++++++++++++++++++--- src/reflect/scala/reflect/api/TypeTags.scala | 46 +- src/reflect/scala/reflect/api/Types.scala | 212 ++++- src/reflect/scala/reflect/api/Universe.scala | 70 ++ src/reflect/scala/reflect/api/package.scala | 271 +++++-- .../scala/reflect/internal/util/Position.scala | 44 ++ src/reflect/scala/reflect/macros/Aliases.scala | 76 ++ src/reflect/scala/reflect/macros/Context.scala | 65 +- src/reflect/scala/reflect/macros/Enclosures.scala | 5 + src/reflect/scala/reflect/macros/Evals.scala | 47 +- src/reflect/scala/reflect/macros/ExprUtils.scala | 16 + src/reflect/scala/reflect/macros/FrontEnds.scala | 28 +- .../scala/reflect/macros/Infrastructure.scala | 3 + src/reflect/scala/reflect/macros/Names.scala | 11 +- src/reflect/scala/reflect/macros/Parsers.scala | 10 +- src/reflect/scala/reflect/macros/Reifiers.scala | 3 + src/reflect/scala/reflect/macros/TreeBuilder.scala | 17 + src/reflect/scala/reflect/macros/Typers.scala | 3 + src/reflect/scala/reflect/macros/Universe.scala | 71 +- src/reflect/scala/reflect/macros/package.scala | 257 +++++++ .../scala/reflect/runtime/JavaUniverse.scala | 5 +- src/reflect/scala/reflect/runtime/package.scala | 11 +- 40 files changed, 3051 insertions(+), 385 deletions(-) (limited to 'src') 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(), 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, ``. + * 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 () = { + * super.(); + * () + * }; + * 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., // <-- 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 = [Object] + * + * scala> showRaw(m.params(0)(0).typeSignature) + * res2: String = TypeRef( + * ThisType(scala), + * scala., // <-- 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., // <-- 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 `` 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 ``. + * 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 ``. + * 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 `.moduleClass`. For the sake of completeness, it is possible + * to go back from a module class to a module via `.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) + * :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 () = { + * super.(); + * () + * }; + * 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 `` 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 `` 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()` if not specified explicitly. + */ val lo: Tree + + /** The upper bound. + * Is equal to `Ident()` 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 `.tpe.typeSymbol.isPrimitiveValueClass` for that purpose (requires scala-reflect.jar). + * You can also use `.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 of type + * class scala.tools.nsc.interpreter.IMain$TranslatingClassLoader with classpath [(memory)] + * and parent being 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 Macros.scala 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 + * + * }}} + * + * === Using macros === + * + * Create a file named Test.scala 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 + * + * + * 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) + * | } + * :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 -- cgit v1.2.3