diff options
author | ingoem <ingoem@gmail.com> | 2012-10-08 18:38:37 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-10-11 19:54:49 +0200 |
commit | 0c619f18ec275c25af65f4c7bdba4b73cb60855d (patch) | |
tree | 07e867ea92ece62637293a552b265848d89dc259 | |
parent | 92dc8f81130b26475b0540a2226c340caac4c9ac (diff) | |
download | scala-0c619f18ec275c25af65f4c7bdba4b73cb60855d.tar.gz scala-0c619f18ec275c25af65f4c7bdba4b73cb60855d.tar.bz2 scala-0c619f18ec275c25af65f4c7bdba4b73cb60855d.zip |
Rearranged some reflection docs, moving things to the guide
-rw-r--r-- | src/reflect/scala/reflect/api/Annotations.scala | 97 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/Exprs.scala | 27 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/Importers.scala | 23 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/JavaUniverse.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/Mirror.scala | 15 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/Mirrors.scala | 6 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/Scopes.scala | 7 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/Symbols.scala | 11 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/TagInterop.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/Types.scala | 80 | ||||
-rw-r--r-- | src/reflect/scala/reflect/macros/package.scala | 253 |
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 |