summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authoringoem <ingoem@gmail.com>2012-10-08 18:38:37 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-10-11 19:54:49 +0200
commit0c619f18ec275c25af65f4c7bdba4b73cb60855d (patch)
tree07e867ea92ece62637293a552b265848d89dc259 /src/reflect
parent92dc8f81130b26475b0540a2226c340caac4c9ac (diff)
downloadscala-0c619f18ec275c25af65f4c7bdba4b73cb60855d.tar.gz
scala-0c619f18ec275c25af65f4c7bdba4b73cb60855d.tar.bz2
scala-0c619f18ec275c25af65f4c7bdba4b73cb60855d.zip
Rearranged some reflection docs, moving things to the guide
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/api/Annotations.scala97
-rw-r--r--src/reflect/scala/reflect/api/Exprs.scala27
-rw-r--r--src/reflect/scala/reflect/api/Importers.scala23
-rw-r--r--src/reflect/scala/reflect/api/JavaUniverse.scala2
-rw-r--r--src/reflect/scala/reflect/api/Mirror.scala15
-rw-r--r--src/reflect/scala/reflect/api/Mirrors.scala6
-rw-r--r--src/reflect/scala/reflect/api/Scopes.scala7
-rw-r--r--src/reflect/scala/reflect/api/Symbols.scala11
-rw-r--r--src/reflect/scala/reflect/api/TagInterop.scala2
-rw-r--r--src/reflect/scala/reflect/api/Types.scala80
-rw-r--r--src/reflect/scala/reflect/macros/package.scala253
11 files changed, 86 insertions, 437 deletions
diff --git a/src/reflect/scala/reflect/api/Annotations.scala b/src/reflect/scala/reflect/api/Annotations.scala
index 92dda2c75f..10d1e5df7a 100644
--- a/src/reflect/scala/reflect/api/Annotations.scala
+++ b/src/reflect/scala/reflect/api/Annotations.scala
@@ -3,87 +3,28 @@ package api
import scala.collection.immutable.ListMap
-/** 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.
+/** This trait provides annotation support for the reflection API.
*
- * 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]]
+ * The API distinguishes between two kinds of annotations:
+ * 1. ''Java annotations'': 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)
- * }
- * }}}
+ * 2. ''Scala annotations'': annotations on definitions or types produced by the Scala compiler.
+ *
+ * When a Scala annotation that inherits from [[scala.annotation.StaticAnnotation]] or [[scala.annotation.ClassfileAnnotation]] is compiled,
+ * it is stored as special attributes in the corresponding classfile, and not as a Java annotation. Note that subclassing
+ * just [[scala.annotation.Annotation]] is not enough to have the corresponding metadata persisted for runtime reflection.
+ *
+ * The distinction between Java and Scala annotations is manifested in the contract of [[scala.reflect.api.Annotations#Annotation]], which exposes
+ * both `scalaArgs` and `javaArgs`. For Scala or Java annotations extending [[scala.annotation.ClassfileAnnotation]] `scalaArgs` is empty
+ * and arguments are stored in `javaArgs`. For all other 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. Arguments in `javaArgs` are repesented as a map from [[scala.reflect.api.Names#Name]] to
+ * [[scala.reflect.api.Annotations#JavaArgument]]. Instances of `JavaArgument` represent different kinds of Java annotation arguments:
+ * - literals (primitive and string constants),
+ * - arrays and
+ * - nested annotations.
*/
trait Annotations { self: Universe =>
diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala
index eb4c49c808..9b2cba1391 100644
--- a/src/reflect/scala/reflect/api/Exprs.scala
+++ b/src/reflect/scala/reflect/api/Exprs.scala
@@ -11,29 +11,20 @@ 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]]).
+ * `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
+ * Usually `Expr`s 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]].
+ * `Expr`s can also be created manually via the `Expr` companion object, but then the burden of providing a `TreeCreator` lies on the programmer.
+ * Compile-time reflection via macros, as described in [[scala.reflect.macros.Aliases]], provides an easier way to instantiate exprs manually.
+ * Manual creation, however, is very rarely needed when working with runtime reflection.
*
- * === 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.
+ * `Expr` can be migrated from one mirror to another by using the `in` method. 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). The default universe of an `Expr` is typically
+ * [[scala.reflect.runtime.package#universe]], the default mirror is typically [[scala.reflect.runtime.package#currentMirror]].
*/
trait Exprs { self: Universe =>
diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala
index f745c37b1d..f25f5a95e2 100644
--- a/src/reflect/scala/reflect/api/Importers.scala
+++ b/src/reflect/scala/reflect/api/Importers.scala
@@ -1,25 +1,24 @@
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.
+/** This trait provides support for importers, a facility to migrate reflection artifacts between universes.
*
- * 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, such as symbols and types, 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. For example, 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,
+ * Reflection artifacts are firmly grounded in their universes, which is reflected by the fact that types of artifacts
+ * from different universes are not compatible. By using importers, however, they be imported from one universe
+ * into another. 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).
+ * 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 ===
*
diff --git a/src/reflect/scala/reflect/api/JavaUniverse.scala b/src/reflect/scala/reflect/api/JavaUniverse.scala
index b96a6cf4f8..b899d1f6d7 100644
--- a/src/reflect/scala/reflect/api/JavaUniverse.scala
+++ b/src/reflect/scala/reflect/api/JavaUniverse.scala
@@ -6,7 +6,7 @@ package api
* 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.
+ * See the [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for details on how to use runtime reflection.
*/
trait JavaUniverse extends Universe with JavaMirrors { self =>
diff --git a/src/reflect/scala/reflect/api/Mirror.scala b/src/reflect/scala/reflect/api/Mirror.scala
index 281953926f..ae2c48fa14 100644
--- a/src/reflect/scala/reflect/api/Mirror.scala
+++ b/src/reflect/scala/reflect/api/Mirror.scala
@@ -2,14 +2,15 @@ package scala.reflect
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.
+ * The base class for all mirrors.
*
- * 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 the [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for a description of mirrors
+ * and infomation on getting started with Scala reflection API.
+ *
+ * Note: Unlike most Scala reflection artifact classes, `Mirror` is not defined as an inner class,
+ * 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.
*
* @tparam U the type of 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 789dc42f2a..1e742f4145 100644
--- a/src/reflect/scala/reflect/api/Mirrors.scala
+++ b/src/reflect/scala/reflect/api/Mirrors.scala
@@ -1,8 +1,10 @@
package scala.reflect
package api
-/** 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.
+/** This trait provides support for Mirrors in the reflection API.
+ *
+ * See the [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for a description of mirrors
+ * and infomation on getting started with Scala reflection API.
*/
trait Mirrors { self: Universe =>
diff --git a/src/reflect/scala/reflect/api/Scopes.scala b/src/reflect/scala/reflect/api/Scopes.scala
index e0142470e5..ec9aba6567 100644
--- a/src/reflect/scala/reflect/api/Scopes.scala
+++ b/src/reflect/scala/reflect/api/Scopes.scala
@@ -1,15 +1,14 @@
package scala.reflect
package api
-/** 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.
+/** This trait provides support for scopes in the reflection API.
*
- * A scope object generally maps names to symbols available in some lexical scope.
+ * A scope object generally maps names to symbols available in a corresponding 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]],
+ * 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
diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala
index 371e20cdd4..063e12f49c 100644
--- a/src/reflect/scala/reflect/api/Symbols.scala
+++ b/src/reflect/scala/reflect/api/Symbols.scala
@@ -1,14 +1,15 @@
package scala.reflect
package api
-/** 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.
+/** This trait defines symbols and operations on them.
+ *
+ * See the [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for a description of symbols
+ * and infomation on getting started with Scala reflection API.
*
* === 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.
+ * 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]]
diff --git a/src/reflect/scala/reflect/api/TagInterop.scala b/src/reflect/scala/reflect/api/TagInterop.scala
index 916be3c324..4653eb975f 100644
--- a/src/reflect/scala/reflect/api/TagInterop.scala
+++ b/src/reflect/scala/reflect/api/TagInterop.scala
@@ -1,7 +1,7 @@
package scala.reflect
package api
-/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that provides type tag <-> manifest interop.
+/** This trait provides type tag <-> manifest interoperability.
*/
trait TagInterop { self: Universe =>
// TODO `mirror` parameters are now of type `Any`, because I can't make these path-dependent types work
diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala
index 060b0657b1..164dd2c50d 100644
--- a/src/reflect/scala/reflect/api/Types.scala
+++ b/src/reflect/scala/reflect/api/Types.scala
@@ -1,52 +1,43 @@
package scala.reflect
package api
-/** 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.
+/** A trait that defines types and operations on them.
*
- * 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.
+ * Type instances represent information about the type of a corresponding symbol. This includes its members
+ * (methods, fields, type parameters, nested classes, traits, etc) either declared directly or inherited, its base types,
+ * its erasure and so on. Types also provide operation to test for type conformance or euqivalence or for widening.
*
* === 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
+ * Method `typeOf` does not work for types with type parameters, such as `typeOf[List[A]]` where `A` is a type variable.
+ * In this case, 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.
+ * context bound. See [[scala.reflect.api.TypeTags the type tags page]] for details.
*
- * 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
+ * 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.
+ * and should be avoided if possible.
*
* === 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`
+ * Common operations on types are querying them for inner declarations or type conformance tests.
*
- * 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.
+ * 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 can
+ * write `typeOf[List[_]].member("map": TermName)`, getting a `MethodSymbol`
*
- * 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[_]]`.
+ * Types expose `<:<` and `weak_<:<` methods to test for subtype relationships. 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
+ * type tags, tests provided by `Type`s are aware of all the intricacies of the Scala type system and work correctly even for involved types.
+ *
+ * The vanilla `==` method should not be used to compare types for equality. Instead, one should always use the `=:=` method.
+ * Operator `=:=` knows about type aliases, e.g., `typeOf[scala.List[_]] =:= typeOf[scala.collection.immutable.List[_]]`.
*
* === Exploring types ===
*
@@ -71,34 +62,6 @@ package api
* 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 =>
@@ -184,7 +147,8 @@ trait Types { self: Universe =>
/** Does this type conform to given type argument `that`? */
def <:< (that: Type): Boolean
- /** Is this type a weak subtype of that type? True also for numeric types, i.e. Int weak_<:< Long.
+ /** Does this type weakly conform to given type argument `that`, i.e., either conforms in terms of `<:<` or both are primitive number types
+ * that conform according to Section "Weak Conformance" in the spec. For example, Int weak_<:< Long.
*/
def weak_<:<(that: Type): Boolean
diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala
index a3211b67af..84a307e60e 100644
--- a/src/reflect/scala/reflect/macros/package.scala
+++ b/src/reflect/scala/reflect/macros/package.scala
@@ -1,261 +1,12 @@
package scala.reflect
-/** Scala macros.
- *
- * === Overview ===
+/** The base package for Scala macros.
*
* Macros are functions that are called by the compiler during compilation.
* Within these functions the programmer has access to compiler APIs exposed in [[scala.reflect.macros.Context]].
* For example, it is possible to generate, analyze and typecheck code.
*
- * Since the 2.10.0 Scala includes macros that can be enabled
- * with `import language.experimental.macros` on per-file basis
- * or with `-language:experimental.macros` on per-compilation basis.
- *
- * Macros significantly simplify code analysis and code generation, which makes them a tool of choice for
- * a multitude of [[http://scalamacros.org/usecases/index.html real-world use cases]].
- * Scenarios that traditionally involve writing and maintaining boilerplate can be addressed
- * with macros in concise and maintainable way.
- *
- * === Writing macros ===
- *
- * This documentation page explains a type-safe `printf` macro through an end-to-end example.
- * To follow the example, create a file named <code>Macros.scala</code> and paste the following
- * code (be sure to follow the comments in the code, they reveal important things to know about
- * the macro system, accompanying APIs and infrastructure):
- *
- * {{{
- * import scala.reflect.macros.Context
- * import collection.mutable.ListBuffer
- * import collection.mutable.Stack
- *
- * object Macros {
- * // macro definition is a normal function with almost no restrictions on its signature
- * // its body, though, is nothing more that a reference to an implementation
- * def printf(format: String, params: Any*): Unit = macro impl
- *
- * // macro implementation must correspond to macro definitions that use it
- * // required signature is quite involved, but the compiler knows what it wants
- * // should a mismatch occur, it will print the expected signature in the error message
- * def impl(c: Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = {
- * // STEP I: compiler API is exposed in scala.reflect.macros.Context
- * // its most important part, reflection API, is accessible via c.universe
- * // it's customary to import c.universe._
- * // because it includes a lot of routinely used types and functions
- * import c.universe._
- *
- * // STEP II: the macro starts with parsing the provided format string
- * // macros run during the compile-time, so they operate on trees, not on values
- * // this means that the format parameter of the macro will be a compile-time literal
- * // not an object of type java.lang.String
- * // this also means that the code below won't work for printf("%d" + "%d", ...)
- * // because in that case format won't be a string literal
- * // but rather an abstract syntax that represents addition of two string literals
- * val Literal(Constant(s_format: String)) = format.tree
- *
- * // STEP IIIa: after parsing the format string, the macro needs to generate the code
- * // that will partially perform formatting at compile-time
- * // the paragraph below creates temporary vals that precompute the arguments
- * // to learn about dynamic generation of Scala code, follow the documentation
- * // on trees, available in the scala.reflect.api package
- * val evals = ListBuffer[ValDef]()
- * def precompute(value: Tree, tpe: Type): Ident = {
- * val freshName = newTermName(c.fresh("eval$"))
- * evals += ValDef(Modifiers(), freshName, TypeTree(tpe), value)
- * Ident(freshName)
- * }
- *
- * // STEP IIIb: tree manipulations proceed in this code snippet
- * // the snippet extracts trees from parameters of a macro and transforms them
- * // note the use of typeOf to create Scala types corresponding to forma specifiers
- * // information on types can be found in the docs for the scala.reflect.api package
- * val paramsStack = Stack[Tree]((params map (_.tree)): _*)
- * val refs = s_format.split("(?<=%[\\w%])|(?=%[\\w%])") map {
- * case "%d" => precompute(paramsStack.pop, typeOf[Int])
- * case "%s" => precompute(paramsStack.pop, typeOf[String])
- * case "%%" => Literal(Constant("%"))
- * case part => Literal(Constant(part))
- * }
- *
- * // STEP IV: the code that has been generated is now combined into a Block
- * // note the call to reify, which provides a shortcut for creating ASTs
- * // reify is discussed in details in docs for scala.reflect.api.Universe
- * val stats = evals ++ refs.map(ref => reify(print(c.Expr[Any](ref).splice)).tree)
- * c.Expr[Unit](Block(stats.toList, Literal(Constant(()))))
- * }
- * }
- * }}}
- *
- * To summarize the code provided above, macros are mini-compiler plugins that get executed whenever a compiler
- * comes across an invocation of a method declared as a macro. Such methods, dubbed ''macro definitions'', use
- * the `macro` keyword to reference ''macro implementations''.
- *
- * Macro implementations use [[scala.reflect.api.package reflection API]] to communicate
- * with the compiler. The gateway to that API is `c`, a ubiquitous parameter of type [[scala.reflect.macros.Context]]
- * that must be present in all macro implementations. Compiler universe is available through `c.universe`.
- *
- * Input arguments to a macro implementation are [[scala.reflect.api.Trees abstract syntax trees]], which
- * correspond to the arguments of the method invocation that triggered a macro expansion. These trees
- * are wrapped in [[scala.reflect.api.Exprs exprs]], typed wrappers over trees.
- *
- * The end result produced by a macro implementation is an abstract syntax tree
- * wrapped in an expr. This tree represents the code that the compiler will use
- * to replace the original method invocation.
- * To learn more about how to create trees that correspond to given Scala code and how to perform
- * tree manipulations, visit [[scala.reflect.api.Trees the documentation page on trees]].
- *
- * === Compiling macros ===
- *
- * In 2.10.0 macros are an experimental feature, so they need to be enabled before use.
- * Normal compilation of the snippet written above (using `scalac Macros.scala`) fails as follows:
- *
- * {{{
- * C:/Projects/Kepler/sandbox>scalac Macros.scala
- * Macros.scala:8: error: macro definition needs to be enabled
- * by making the implicit value language.experimental.macros visible.
- * This can be achieved by adding the import clause 'import language.experimental.macros'
- * or by setting the compiler option -language:experimental.macros.
- * See the Scala docs for value scala.language.experimental.macros for a discussion
- * why the feature needs to be explicitly enabled.
- * def printf(format: String, params: Any*): Unit = macro printf_impl
- * ^
- * one error found
- * }}}
- *
- * To enable macros one should use either `import language.experimental.macros` on per-file basis
- * or `-language:experimental.macros` (providing a compiler switch) on per-compilation basis.
- *
- * {{{
- * C:/Projects/Kepler/sandbox>scalac -language:experimental.macros Macros.scala
- * <scalac has exited with code 0>
- * }}}
- *
- * === Using macros ===
- *
- * Create a file named <code>Test.scala</code> and paste the following code (just as simple as that,
- * to use a macro, it's only necessary to import it and call it as it were a regular function).
- *
- * {{{
- * object Test extends App {
- * import Macros._
- * printf("hello %s!", "world")
- * }
- * }}}
- *
- * An important rule about using macros is separate compilation. To perform macro expansion, compiler
- * needs a macro implementation in executable form. Thus macro implementations need to be compiled before
- * the main compilation, otherwise compiler will produce `macro implementation not found` errors.
- *
- * In the REPL, however, macros and their usages can be written in the same session. That's because
- * the REPL compiles every line of input in a separate compilation run.
- *
- * {{{
- * C:/Projects/Kepler/sandbox>scalac Test.scala
- * <scalac has exited with code 0>
- *
- * C:/Projects/Kepler/sandbox>scala Test
- * hello world!
- * }}}
- *
- * The test snippet seems to work! To see what happens under the covers, enable the `-Ymacro-debug-lite` compiler flag.
- *
- * {{{
- * C:/Projects/Kepler/sandbox>scalac -Ymacro-debug-lite Test.scala
- * typechecking macro expansion Macros.printf("hello %s!", "world") at
- * source-C:/Projects/Kepler/sandbox\Test.scala,line-3,offset=52
- * {
- * val eval$1: String = "world";
- * scala.this.Predef.print("hello ");
- * scala.this.Predef.print(eval$1);
- * scala.this.Predef.print("!");
- * ()
- * }
- * Block(List(
- * ValDef(Modifiers(), newTermName("eval$1"), TypeTree(String), Literal(Constant("world"))),
- * Apply(
- * Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("print")),
- * List(Literal(Constant("hello")))),
- * Apply(
- * Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("print")),
- * List(Ident(newTermName("eval$1")))),
- * Apply(
- * Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("print")),
- * List(Literal(Constant("!"))))),
- * Literal(Constant(())))
- * }}}
- *
- * With `-Ymacro-debug-lite` one can see both pseudo-Scala representation of the code generated by macro expansion
- * and raw AST representation of the expansion. Both have their merits: the former is useful for surface analysis,
- * while the latter is invaluable for fine-grained debugging.
- *
- * === Writing bigger macros ===
- *
- * When the code of a macro implementation grows big enough to warrant modularization beyond the body
- * of the implementation method, it becomes apparent that one needs to carry around the context parameter,
- * because most things of interest are path-dependent on the context.
- *
- * One of the approaches is to write a class that takes a parameter of type `Context` and then split the
- * macro implementation into a series of methods of that class. This is natural and simple, except that
- * it's hard to get it right. Here's a typical compilation error.
- *
- * {{{
- * scala> class Helper(val c: Context) {
- * | def generate: c.Tree = ???
- * | }
- * defined class Helper
- *
- * scala> def impl(c: Context): c.Expr[Unit] = {
- * | val helper = new Helper(c)
- * | c.Expr(helper.generate)
- * | }
- * <console>:32: error: type mismatch;
- * found : helper.c.Tree
- * (which expands to) helper.c.universe.Tree
- * required: c.Tree
- * (which expands to) c.universe.Tree
- * c.Expr(helper.generate)
- * ^
- * }}}
- *
- * The problem in this snippet is in a path-dependent type mismatch. The Scala compiler
- * does not understand that `c` in `impl` is the same object as `c` in `Helper`, even though the helper
- * is constructed using the original `c`.
- *
- * Luckily just a small nudge is all that is needed for the compiler to figure out what's going on.
- * One of the possible ways of doing that is using refinement types (the example below is the simplest
- * application of the idea; for example, one could also write an implicit conversion from `Context`
- * to `Helper` to avoid explicit instantiations and simplify the calls).
- *
- * {{{
- * scala> abstract class Helper {
- * | val c: Context
- * | def generate: c.Tree = ???
- * | }
- * defined class Helper
- *
- * scala> def impl(c1: Context): c1.Expr[Unit] = {
- * | val helper = new { val c: c1.type = c1 } with Helper
- * | c1.Expr(helper.generate)
- * | }
- * impl: (c1: scala.reflect.macros.Context)c1.Expr[Unit]
- * }}}
- *
- * An alternative approach is to use the [[scala.Singleton]] upper bound to express the fact
- * that `Helper`'s `C` has the same identity as `impl`'s `C` (note that it is mandatory to
- * explicitly spell out the type argument when instantiating `Helper`).
- *
- * {{{
- * scala> class Helper[C <: Context with Singleton](val c: C) {
- * | def generate: c.Tree = ???
- * | }
- * defined class Helper
- *
- * scala> def impl(c: Context): c.Expr[Unit] = {
- * | val helper = new Helper[c.type](c)
- * | c.Expr(helper.generate)
- * | }
- * impl: (c: scala.reflect.macros.Context)c.Expr[Unit]
- * }}}
+ * See the [[docs.scala-lang.org/overviews/macros.html Macros Guide]] on how to get started with Scala macros.
*/
package object macros {
} \ No newline at end of file