From c6866a28faf67cd2e455f9a0a829859a73e38819 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Tue, 25 Sep 2012 01:25:20 +0200 Subject: SI-6422: add missing Fractional and Integral alias in scala package --- src/library/scala/package.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/library/scala/package.scala b/src/library/scala/package.scala index a41cdedfa9..fbb98d0582 100644 --- a/src/library/scala/package.scala +++ b/src/library/scala/package.scala @@ -95,7 +95,10 @@ package object scala { val Equiv = scala.math.Equiv type Fractional[T] = scala.math.Fractional[T] + val Fractional = scala.math.Fractional + type Integral[T] = scala.math.Integral[T] + val Integral = scala.math.Integral type Numeric[T] = scala.math.Numeric[T] val Numeric = scala.math.Numeric -- cgit v1.2.3 From d46f2d519de0f155d37a43927fb3924d2f2fbdb2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 29 Sep 2012 19:58:18 +0200 Subject: SI-6215 Fix compiler crash on private method in value class Fixes the problem with private defs in value classes by moving the $extension after the name proper rather than before. The previous scheme did not commute with makeNonPrivate: I.e. if -ext-> is "generate extension name" and -mnp-> is "make not private" we did get for method foo in value class Foo: foo -ext-> extension$foo -mnp-> Foo$$extension$foo but foo -mnp-> Foo$$foo -ext-> extension$Foo$$foo With the change both variations give the same name: foo -ext-> foo$extension -mnp-> Foo$$foo$extension but foo -mnp-> Foo$$foo -ext-> Foo$$foo$extension --- .../scala/tools/nsc/transform/ExtensionMethods.scala | 8 ++++---- test/files/pos/t6215.scala | 1 + test/files/run/t6344.check | 16 ++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 test/files/pos/t6215.scala diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 8a9d0e58ec..6dd937c0ad 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -56,11 +56,11 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { case OverloadedType(_, alts) => val index = alts indexOf imeth assert(index >= 0, alts+" does not contain "+imeth) - def altName(index: Int) = newTermName("extension"+index+"$"+imeth.name) + def altName(index: Int) = newTermName(imeth.name+"$extension"+index) altName(index) #:: ((0 until alts.length).toStream filter (index != _) map altName) case tpe => assert(tpe != NoType, imeth.name+" not found in "+imeth.owner+"'s decls: "+imeth.owner.info.decls) - Stream(newTermName("extension$"+imeth.name)) + Stream(newTermName(imeth.name+"$extension")) } } @@ -68,10 +68,10 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { */ def extensionMethod(imeth: Symbol): Symbol = atPhase(currentRun.refchecksPhase) { val companionInfo = imeth.owner.companionModule.info - val candidates = extensionNames(imeth) map (companionInfo.decl(_)) + val candidates = extensionNames(imeth) map (companionInfo.decl(_)) filter (_.exists) val matching = candidates filter (alt => normalize(alt.tpe, imeth.owner) matches imeth.tpe) assert(matching.nonEmpty, - s"no extension method found for $imeth:${imeth.tpe}+among ${candidates map (c => c.name+":"+c.tpe)} / ${extensionNames(imeth)}") + s"no extension method found for $imeth:${imeth.tpe} among ${candidates map (c => c.name+":"+c.tpe)} / ${extensionNames(imeth)}") matching.head } diff --git a/test/files/pos/t6215.scala b/test/files/pos/t6215.scala new file mode 100644 index 0000000000..2f66892b69 --- /dev/null +++ b/test/files/pos/t6215.scala @@ -0,0 +1 @@ +class Foo(val v: String) extends AnyVal { private def len = v.length ; def f = len } diff --git a/test/files/run/t6344.check b/test/files/run/t6344.check index 5ac04d0320..8d9adac849 100644 --- a/test/files/run/t6344.check +++ b/test/files/run/t6344.check @@ -101,14 +101,14 @@ public int ValueInt.x() public int ValueInt.x() public java.lang.Object ValueInt.x() public java.lang.Object ValueInt.x() -public static Gen ValueInt.extension$plus(int,Gen,Gen) -public static Gen ValueInt.extension$plus(int,Gen,Gen) -public static boolean ValueInt.extension$equals(int,java.lang.Object) -public static boolean ValueInt.extension$equals(int,java.lang.Object) -public static int ValueInt.extension$hashCode(int) -public static int ValueInt.extension$hashCode(int) -public static int ValueInt.extension$iplus(int,int,int) -public static int ValueInt.extension$iplus(int,int,int) +public static Gen ValueInt.plus$extension(int,Gen,Gen) +public static Gen ValueInt.plus$extension(int,Gen,Gen) +public static boolean ValueInt.equals$extension(int,java.lang.Object) +public static boolean ValueInt.equals$extension(int,java.lang.Object) +public static int ValueInt.hashCode$extension(int) +public static int ValueInt.hashCode$extension(int) +public static int ValueInt.iplus$extension(int,int,int) +public static int ValueInt.iplus$extension(int,int,int) RefInt public Gen RefInt.plus(Gen,Gen) -- cgit v1.2.3 From 9930b559fe657d517abeb3e4e4ffb3a2a6e00ee0 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:24:03 +0200 Subject: turns on documentation of scala.reflect.runtime We definitely need to document scala.reflect.runtime.universe, therefore adding scala.reflect.runtime to skipPackages was a mistake. But then we need to make a bunch of internal classes private to reflect or to scala. Not very pretty, but it works. --- build.xml | 2 +- src/reflect/scala/reflect/runtime/JavaMirrors.scala | 6 +++--- src/reflect/scala/reflect/runtime/ReflectionUtils.scala | 2 +- src/reflect/scala/reflect/runtime/Settings.scala | 2 +- src/reflect/scala/reflect/runtime/SymbolLoaders.scala | 2 +- src/reflect/scala/reflect/runtime/SymbolTable.scala | 2 +- src/reflect/scala/reflect/runtime/SynchronizedOps.scala | 2 +- src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala | 2 +- src/reflect/scala/reflect/runtime/SynchronizedTypes.scala | 2 +- src/reflect/scala/reflect/runtime/package.scala | 2 +- test/files/run/reflection-magicsymbols-invoke.scala | 8 +++++++- test/files/run/reflection-valueclasses-magic.scala | 8 +++++++- 12 files changed, 26 insertions(+), 14 deletions(-) diff --git a/build.xml b/build.xml index 67d715bfe9..9109da5276 100644 --- a/build.xml +++ b/build.xml @@ -2337,7 +2337,7 @@ DOCUMENTATION docfooter="epfl" docsourceurl="${scaladoc.url}€{FILE_PATH}.scala#L1" docUncompilable="${src.dir}/library-aux" - skipPackages="scala.reflect.macros.internal:scala.reflect.internal:scala.reflect.runtime:scala.reflect.io" + skipPackages="scala.reflect.macros.internal:scala.reflect.internal:scala.reflect.io" sourcepath="${src.dir}" classpathref="pack.classpath" addparams="${scalac.args.all}" diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index b6b2537dc4..b917eac779 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -24,7 +24,7 @@ import scala.language.existentials import scala.runtime.{ScalaRunTime, BoxesRunTime} import scala.reflect.internal.util.Collections._ -trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUniverse: SymbolTable => +private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUniverse: SymbolTable => private lazy val mirrors = new WeakHashMap[ClassLoader, WeakReference[JavaMirror]]() @@ -1279,6 +1279,6 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUnive } } -class ReflectError(msg: String) extends java.lang.Error(msg) +private[reflect] class ReflectError(msg: String) extends java.lang.Error(msg) -class HasJavaClass[J](val getClazz: J => java.lang.Class[_]) +private[reflect] class HasJavaClass[J](val getClazz: J => java.lang.Class[_]) diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala index 44d9d94a46..73425bae55 100644 --- a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala +++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala @@ -10,7 +10,7 @@ import java.lang.reflect.{ Method, InvocationTargetException, UndeclaredThrowabl /** A few java-reflection oriented utility functions useful during reflection bootstrapping. */ -object ReflectionUtils { +private[scala] object ReflectionUtils { // Unwraps some chained exceptions which arise during reflective calls. def unwrapThrowable(x: Throwable): Throwable = x match { case _: InvocationTargetException | // thrown by reflectively invoked method or constructor diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala index da4f4fbda1..0e0cf3fc40 100644 --- a/src/reflect/scala/reflect/runtime/Settings.scala +++ b/src/reflect/scala/reflect/runtime/Settings.scala @@ -7,7 +7,7 @@ import scala.reflect.internal.settings.MutableSettings * This should be refined, so that settings are settable via command * line options or properties. */ -class Settings extends MutableSettings { +private[reflect] class Settings extends MutableSettings { trait Setting extends SettingValue { } diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index d1be73bed3..61663f6181 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -5,7 +5,7 @@ import internal.Flags import java.lang.{Class => jClass, Package => jPackage} import scala.collection.mutable -trait SymbolLoaders { self: SymbolTable => +private[reflect] trait SymbolLoaders { self: SymbolTable => /** The standard completer for top-level classes * @param clazz The top-level class diff --git a/src/reflect/scala/reflect/runtime/SymbolTable.scala b/src/reflect/scala/reflect/runtime/SymbolTable.scala index 73632be965..5c08e9a508 100644 --- a/src/reflect/scala/reflect/runtime/SymbolTable.scala +++ b/src/reflect/scala/reflect/runtime/SymbolTable.scala @@ -8,7 +8,7 @@ import scala.reflect.internal.Flags._ * It can be used either from a reflexive universe (class scala.reflect.runtime.JavaUniverse), or else from * a runtime compiler that uses reflection to get a class information (class scala.tools.reflect.ReflectGlobal) */ -trait SymbolTable extends internal.SymbolTable with JavaMirrors with SymbolLoaders with SynchronizedOps { +private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors with SymbolLoaders with SynchronizedOps { def info(msg: => String) = if (settings.verbose.value) println("[reflect-compiler] "+msg) diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala index 1a17dd12d2..7b280e59b9 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala @@ -2,7 +2,7 @@ package scala.reflect package runtime // SI-6240: test thread-safety, make trees synchronized as well -trait SynchronizedOps extends internal.SymbolTable +private[reflect] trait SynchronizedOps extends internal.SymbolTable with SynchronizedSymbols with SynchronizedTypes { self: SymbolTable => diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 3c2885a9f4..950718267a 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -3,7 +3,7 @@ package runtime import scala.reflect.io.AbstractFile -trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable => +private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable => override protected def nextId() = synchronized { super.nextId() } diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala index 9b4d8d1d48..a3e7c28ca4 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala @@ -7,7 +7,7 @@ import java.lang.ref.WeakReference /** This trait overrides methods in reflect.internal, bracketing * them in synchronized { ... } to make them thread-safe */ -trait SynchronizedTypes extends internal.Types { self: SymbolTable => +private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTable => // No sharing of map objects: override protected def commonOwnerMap = new CommonOwnerMap diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala index 7b9f69e657..278629adb6 100644 --- a/src/reflect/scala/reflect/runtime/package.scala +++ b/src/reflect/scala/reflect/runtime/package.scala @@ -11,7 +11,7 @@ package object runtime { } package runtime { - object Macros { + private[scala] object Macros { def currentMirror(c: scala.reflect.macros.Context): c.Expr[universe.Mirror] = { import c.universe._ val runtimeClass = c.reifyEnclosingRuntimeClass diff --git a/test/files/run/reflection-magicsymbols-invoke.scala b/test/files/run/reflection-magicsymbols-invoke.scala index b38d1be7b2..5f39370708 100644 --- a/test/files/run/reflection-magicsymbols-invoke.scala +++ b/test/files/run/reflection-magicsymbols-invoke.scala @@ -2,6 +2,12 @@ import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe.definitions._ import scala.reflect.runtime.{currentMirror => cm} +package scala { + object ExceptionUtils { + def unwrapThrowable(ex: Throwable): Throwable = scala.reflect.runtime.ReflectionUtils.unwrapThrowable(ex) + } +} + object Test extends App { def key(sym: Symbol) = sym + ": " + sym.typeSignature def test(tpe: Type, receiver: Any, method: String, args: Any*) { @@ -13,7 +19,7 @@ object Test extends App { println(result) } catch { case ex: Throwable => - val realex = scala.reflect.runtime.ReflectionUtils.unwrapThrowable(ex) + val realex = scala.ExceptionUtils.unwrapThrowable(ex) println(realex.getClass + ": " + realex.getMessage) } print(s"testing ${tpe.typeSymbol.name}.$method: ") diff --git a/test/files/run/reflection-valueclasses-magic.scala b/test/files/run/reflection-valueclasses-magic.scala index f9feb2d504..577939d2db 100644 --- a/test/files/run/reflection-valueclasses-magic.scala +++ b/test/files/run/reflection-valueclasses-magic.scala @@ -3,6 +3,12 @@ import scala.reflect.runtime.universe.definitions._ import scala.reflect.runtime.{currentMirror => cm} import scala.reflect.ClassTag +package scala { + object ExceptionUtils { + def unwrapThrowable(ex: Throwable): Throwable = scala.reflect.runtime.ReflectionUtils.unwrapThrowable(ex) + } +} + object Test extends App { def key(sym: Symbol) = { sym match { @@ -35,7 +41,7 @@ object Test extends App { println(s"[${result.getClass}] =======> $result") } catch { case ex: Throwable => - val realex = scala.reflect.runtime.ReflectionUtils.unwrapThrowable(ex) + val realex = scala.ExceptionUtils.unwrapThrowable(ex) println(realex.getClass + ": " + realex.getMessage) } val meth = tpe.declaration(newTermName(method).encodedName.toTermName) -- cgit v1.2.3 From 1b2415865984071036c5f61e82a4a7048d4d18ee Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:06:12 +0200 Subject: renames macros.ParseError to ParseException Because it's not a fatal error. Neither it should subclass Throwable. --- src/compiler/scala/reflect/macros/runtime/Parsers.scala | 2 +- src/reflect/scala/reflect/macros/Parsers.scala | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/compiler/scala/reflect/macros/runtime/Parsers.scala b/src/compiler/scala/reflect/macros/runtime/Parsers.scala index ab9b94ec9f..566bcde73d 100644 --- a/src/compiler/scala/reflect/macros/runtime/Parsers.scala +++ b/src/compiler/scala/reflect/macros/runtime/Parsers.scala @@ -19,6 +19,6 @@ trait Parsers { } catch { case ToolBoxError(msg, cause) => // todo. provide a position - throw new ParseError(universe.NoPosition, msg) + throw new ParseException(universe.NoPosition, msg) } } diff --git a/src/reflect/scala/reflect/macros/Parsers.scala b/src/reflect/scala/reflect/macros/Parsers.scala index c2d4d8a3ab..d3aabcff0d 100644 --- a/src/reflect/scala/reflect/macros/Parsers.scala +++ b/src/reflect/scala/reflect/macros/Parsers.scala @@ -10,5 +10,6 @@ trait Parsers { def parse(code: String): Tree } -// should be path-dependent, otherwise exception handling becomes a mess -case class ParseError(val pos: scala.reflect.api.Position, val msg: String) extends Throwable(msg) +/** Indicates an error during [[scala.reflect.macros.Parsers#Parse]]. + */ +case class ParseException(val pos: scala.reflect.api.Position, val msg: String) extends Exception(msg) -- cgit v1.2.3 From 992d255e2fc1ca487a60e38196ec4aa952617b92 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:09:42 +0200 Subject: renames macros.TypeError to TypecheckException Again, this is not a fatal error, so it should end with an Error, and it should subclass not Throwable, but Exception. Also moved the exception outside the cake to simplify error handling, along the same lines of what've been done for parsing and reification exceptions. --- .../scala/reflect/macros/runtime/Typers.scala | 10 ++------- src/compiler/scala/reflect/reify/Taggers.scala | 6 ++--- src/reflect/scala/reflect/macros/Typers.scala | 26 ++++++++++++---------- .../run/macro-typecheck-implicitsdisabled.check | 2 +- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/compiler/scala/reflect/macros/runtime/Typers.scala b/src/compiler/scala/reflect/macros/runtime/Typers.scala index 9fa8567ada..be70181126 100644 --- a/src/compiler/scala/reflect/macros/runtime/Typers.scala +++ b/src/compiler/scala/reflect/macros/runtime/Typers.scala @@ -25,7 +25,7 @@ trait Typers { result case error @ universe.analyzer.SilentTypeError(_) => macroLogVerbose(error.err.errMsg) - if (!silent) throw new universe.TypeError(error.err.errPos, error.err.errMsg) + if (!silent) throw new TypecheckException(error.err.errPos, error.err.errMsg) universe.EmptyTree }) } @@ -49,19 +49,13 @@ trait Typers { wrapper(universe.analyzer.inferImplicit(tree, pt, reportAmbiguous = true, isView = isView, context = context, saveAmbiguousDivergent = !silent, pos = pos)) match { case failure if failure.tree.isEmpty => macroLogVerbose("implicit search has failed. to find out the reason, turn on -Xlog-implicits") - if (context.hasErrors) throw new universe.TypeError(context.errBuffer.head.errPos, context.errBuffer.head.errMsg) + if (context.hasErrors) throw new TypecheckException(context.errBuffer.head.errPos, context.errBuffer.head.errMsg) universe.EmptyTree case success => success.tree } } - type TypeError = universe.TypeError - - object TypeError extends TypeErrorExtractor { - def unapply(error: TypeError): Option[(Position, String)] = Some((error.pos, error.msg)) - } - def resetAllAttrs(tree: Tree): Tree = universe.resetAllAttrs(tree) def resetLocalAttrs(tree: Tree): Tree = universe.resetLocalAttrs(tree) diff --git a/src/compiler/scala/reflect/reify/Taggers.scala b/src/compiler/scala/reflect/reify/Taggers.scala index 7db6394734..513ce020cc 100644 --- a/src/compiler/scala/reflect/reify/Taggers.scala +++ b/src/compiler/scala/reflect/reify/Taggers.scala @@ -1,6 +1,6 @@ package scala.reflect.reify -import scala.reflect.macros.{ReificationError, UnexpectedReificationError} +import scala.reflect.macros.{ReificationError, UnexpectedReificationError, TypecheckException} import scala.reflect.macros.runtime.Context abstract class Taggers { @@ -65,13 +65,13 @@ abstract class Taggers { translatingReificationErrors(materializer) } try c.typeCheck(result) - catch { case terr @ c.TypeError(pos, msg) => failTag(result, terr) } + catch { case terr @ TypecheckException(pos, msg) => failTag(result, terr) } } def materializeExpr(universe: Tree, mirror: Tree, expr: Tree): Tree = { val result = translatingReificationErrors(c.reifyTree(universe, mirror, expr)) try c.typeCheck(result) - catch { case terr @ c.TypeError(pos, msg) => failExpr(result, terr) } + catch { case terr @ TypecheckException(pos, msg) => failExpr(result, terr) } } private def translatingReificationErrors(materializer: => Tree): Tree = { diff --git a/src/reflect/scala/reflect/macros/Typers.scala b/src/reflect/scala/reflect/macros/Typers.scala index eef6507418..9c4854f89f 100644 --- a/src/reflect/scala/reflect/macros/Typers.scala +++ b/src/reflect/scala/reflect/macros/Typers.scala @@ -24,11 +24,11 @@ trait Typers { * Unlike `enclosingImplicits`, this is a def, which means that it gets recalculated on every invocation, * so it might change depending on what is going on during macro expansion. */ - def openImplicits: List[(Type, Tree)] + def openImplicits: List[(Type, Tree)] /** Typechecks the provided tree against the expected type `pt` in the macro callsite context. * - * If `silent` is false, `TypeError` will be thrown in case of a typecheck error. + * If `silent` is false, `TypecheckException` will be thrown in case of a typecheck error. * If `silent` is true, the typecheck is silent and will return `EmptyTree` if an error occurs. * Such errors don't vanish and can be inspected by turning on -Ymacro-debug-verbose. * Unlike in `inferImplicitValue` and `inferImplicitView`, `silent` is false by default. @@ -36,26 +36,32 @@ trait Typers { * Typechecking can be steered with the following optional parameters: * `withImplicitViewsDisabled` recursively prohibits implicit views (though, implicit vals will still be looked up and filled in), default value is false * `withMacrosDisabled` recursively prohibits macro expansions and macro-based implicits, default value is false + * + * @throws [[scala.reflect.macros.TypecheckException]] */ def typeCheck(tree: Tree, pt: Type = WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree /** Infers an implicit value of the expected type `pt` in the macro callsite context. * Optional `pos` parameter provides a position that will be associated with the implicit search. * - * If `silent` is false, `TypeError` will be thrown in case of an inference error. + * If `silent` is false, `TypecheckException` will be thrown in case of an inference error. * If `silent` is true, the typecheck is silent and will return `EmptyTree` if an error occurs. * Such errors don't vanish and can be inspected by turning on -Xlog-implicits. * Unlike in `typeCheck`, `silent` is true by default. + * + * @throws [[scala.reflect.macros.TypecheckException]] */ def inferImplicitValue(pt: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree /** Infers an implicit view from the provided tree `tree` of the type `from` to the type `to` in the macro callsite context. * Optional `pos` parameter provides a position that will be associated with the implicit search. * - * If `silent` is false, `TypeError` will be thrown in case of an inference error. + * If `silent` is false, `TypecheckException` will be thrown in case of an inference error. * If `silent` is true, the typecheck is silent and will return `EmptyTree` if an error occurs. * Such errors don't vanish and can be inspected by turning on -Xlog-implicits. * Unlike in `typeCheck`, `silent` is true by default. + * + * @throws [[scala.reflect.macros.TypecheckException]] */ def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree @@ -72,12 +78,8 @@ trait Typers { * For more info, read up https://issues.scala-lang.org/browse/SI-5464. */ def resetLocalAttrs(tree: Tree): Tree +} - /** Represents an error during typechecking - */ - type TypeError <: Throwable - val TypeError: TypeErrorExtractor - abstract class TypeErrorExtractor { - def unapply(error: TypeError): Option[(Position, String)] - } -} \ No newline at end of file +/** Indicates an error during one of the methods in [[scala.reflect.macros.Typers]]. + */ +case class TypecheckException(val pos: scala.reflect.api.Position, val msg: String) extends Exception(msg) diff --git a/test/files/run/macro-typecheck-implicitsdisabled.check b/test/files/run/macro-typecheck-implicitsdisabled.check index 6cf25076a7..c4fa2c5c28 100644 --- a/test/files/run/macro-typecheck-implicitsdisabled.check +++ b/test/files/run/macro-typecheck-implicitsdisabled.check @@ -1,2 +1,2 @@ scala.this.Predef.any2ArrowAssoc[Int](1).->[Int](2) -scala.reflect.internal.Types$TypeError: value -> is not a member of Int +scala.reflect.macros.TypecheckException: value -> is not a member of Int -- cgit v1.2.3 From fb515bca0549cbc84a40b23889d1f038bcb0ef3a Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:13:04 +0200 Subject: renames macros.ReificationError to ReificationException And again, this is not a fatal error, so it should end with an Error, and it should subclass not Throwable, but Exception. --- src/compiler/scala/reflect/reify/Errors.scala | 22 +++++++++++----------- src/compiler/scala/reflect/reify/Reifier.scala | 10 +++++----- src/compiler/scala/reflect/reify/Taggers.scala | 6 +++--- src/compiler/scala/reflect/reify/package.scala | 4 ++-- .../scala/tools/reflect/MacroImplementations.scala | 2 +- src/compiler/scala/tools/util/PathResolver.scala | 2 +- src/reflect/scala/reflect/macros/Reifiers.scala | 12 ++++++++++-- 7 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/compiler/scala/reflect/reify/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala index 73c13901b6..c25112941c 100644 --- a/src/compiler/scala/reflect/reify/Errors.scala +++ b/src/compiler/scala/reflect/reify/Errors.scala @@ -1,7 +1,7 @@ package scala.reflect.reify -import scala.reflect.macros.ReificationError -import scala.reflect.macros.UnexpectedReificationError +import scala.reflect.macros.ReificationException +import scala.reflect.macros.UnexpectedReificationException trait Errors { self: Reifier => @@ -19,17 +19,17 @@ trait Errors { def CannotReifyType(tpe: Type) = { val msg = "implementation restriction: cannot reify type %s (%s)".format(tpe, tpe.kind) - throw new ReificationError(defaultErrorPosition, msg) + throw new ReificationException(defaultErrorPosition, msg) } def CannotReifySymbol(sym: Symbol) = { val msg = "implementation restriction: cannot reify symbol %s (%s)".format(sym, sym.accurateKindString) - throw new ReificationError(defaultErrorPosition, msg) + throw new ReificationException(defaultErrorPosition, msg) } def CannotReifyWeakType(details: Any) = { val msg = "cannot create a TypeTag" + details - throw new ReificationError(defaultErrorPosition, msg) + throw new ReificationException(defaultErrorPosition, msg) } def CannotConvertManifestToTagWithoutScalaReflect(tpe: Type, manifestInScope: Tree) = { @@ -37,7 +37,7 @@ trait Errors { |to create a type tag here, it is necessary to interoperate with the manifest `$manifestInScope` in scope. |however manifest -> typetag conversion requires Scala reflection, which is not present on the classpath. |to proceed put scala-reflect.jar on your compilation classpath and recompile.""".trim.stripMargin - throw new ReificationError(defaultErrorPosition, msg) + throw new ReificationException(defaultErrorPosition, msg) } def CannotReifyRuntimeSplice(tree: Tree) = { @@ -46,7 +46,7 @@ trait Errors { |cross-stage evaluations need to be invoked explicitly, so we're showing you this error. |if you're sure this is not an oversight, add scala-compiler.jar to the classpath, |import `scala.tools.reflect.Eval` and call `.eval` instead.""".trim.stripMargin - throw new ReificationError(tree.pos, msg) + throw new ReificationException(tree.pos, msg) } // unexpected errors: these can never happen under normal conditions unless there's a bug in the compiler (or in a compiler plugin or in a macro) @@ -54,21 +54,21 @@ trait Errors { def CannotReifyUntypedPrefix(prefix: Tree) = { val msg = "internal error: untyped prefixes are not supported, consider typechecking the prefix before passing it to the reifier" - throw new UnexpectedReificationError(defaultErrorPosition, msg) + throw new UnexpectedReificationException(defaultErrorPosition, msg) } def CannotReifyUntypedReifee(reifee: Any) = { val msg = "internal error: untyped trees are not supported, consider typechecking the reifee before passing it to the reifier" - throw new UnexpectedReificationError(defaultErrorPosition, msg) + throw new UnexpectedReificationException(defaultErrorPosition, msg) } def CannotReifyErroneousPrefix(prefix: Tree) = { val msg = "internal error: erroneous prefixes are not supported, make sure that your prefix has typechecked successfully before passing it to the reifier" - throw new UnexpectedReificationError(defaultErrorPosition, msg) + throw new UnexpectedReificationException(defaultErrorPosition, msg) } def CannotReifyErroneousReifee(reifee: Any) = { val msg = "internal error: erroneous reifees are not supported, make sure that your reifee has typechecked successfully before passing it to the reifier" - throw new UnexpectedReificationError(defaultErrorPosition, msg) + throw new UnexpectedReificationException(defaultErrorPosition, msg) } } diff --git a/src/compiler/scala/reflect/reify/Reifier.scala b/src/compiler/scala/reflect/reify/Reifier.scala index f48fcd8ada..47669f57b0 100644 --- a/src/compiler/scala/reflect/reify/Reifier.scala +++ b/src/compiler/scala/reflect/reify/Reifier.scala @@ -1,8 +1,8 @@ package scala.reflect.reify import scala.tools.nsc.Global -import scala.reflect.macros.ReificationError -import scala.reflect.macros.UnexpectedReificationError +import scala.reflect.macros.ReificationException +import scala.reflect.macros.UnexpectedReificationException import scala.reflect.reify.utils.Utils /** Given a tree or a type, generate a tree that when executed at runtime produces the original tree or type. @@ -132,12 +132,12 @@ abstract class Reifier extends States untyped } catch { - case ex: ReificationError => + case ex: ReificationException => throw ex - case ex: UnexpectedReificationError => + case ex: UnexpectedReificationException => throw ex case ex: Throwable => - throw new UnexpectedReificationError(defaultErrorPosition, "reification crashed", ex) + throw new UnexpectedReificationException(defaultErrorPosition, "reification crashed", ex) } } } \ No newline at end of file diff --git a/src/compiler/scala/reflect/reify/Taggers.scala b/src/compiler/scala/reflect/reify/Taggers.scala index 513ce020cc..cbaee41890 100644 --- a/src/compiler/scala/reflect/reify/Taggers.scala +++ b/src/compiler/scala/reflect/reify/Taggers.scala @@ -1,6 +1,6 @@ package scala.reflect.reify -import scala.reflect.macros.{ReificationError, UnexpectedReificationError, TypecheckException} +import scala.reflect.macros.{ReificationException, UnexpectedReificationException, TypecheckException} import scala.reflect.macros.runtime.Context abstract class Taggers { @@ -77,10 +77,10 @@ abstract class Taggers { private def translatingReificationErrors(materializer: => Tree): Tree = { try materializer catch { - case ReificationError(pos, msg) => + case ReificationException(pos, msg) => c.error(pos.asInstanceOf[c.Position], msg) // this cast is a very small price for the sanity of exception handling EmptyTree - case UnexpectedReificationError(pos, err, cause) if cause != null => + case UnexpectedReificationException(pos, err, cause) if cause != null => throw cause } } diff --git a/src/compiler/scala/reflect/reify/package.scala b/src/compiler/scala/reflect/reify/package.scala index 5a23ab7214..55f8684df2 100644 --- a/src/compiler/scala/reflect/reify/package.scala +++ b/src/compiler/scala/reflect/reify/package.scala @@ -1,7 +1,7 @@ package scala.reflect import scala.language.implicitConversions -import scala.reflect.macros.{Context, ReificationError, UnexpectedReificationError} +import scala.reflect.macros.{Context, ReificationException, UnexpectedReificationException} import scala.tools.nsc.Global package object reify { @@ -53,7 +53,7 @@ package object reify { if (tpe.isSpliceable) { val classTagInScope = typer0.resolveClassTag(enclosingMacroPosition, tpe, allowMaterialization = false) if (!classTagInScope.isEmpty) return Select(classTagInScope, nme.runtimeClass) - if (concrete) throw new ReificationError(enclosingMacroPosition, "tpe %s is an unresolved spliceable type".format(tpe)) + if (concrete) throw new ReificationException(enclosingMacroPosition, "tpe %s is an unresolved spliceable type".format(tpe)) } tpe.normalize match { diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/reflect/MacroImplementations.scala index 48a4811744..86cd845c54 100644 --- a/src/compiler/scala/tools/reflect/MacroImplementations.scala +++ b/src/compiler/scala/tools/reflect/MacroImplementations.scala @@ -1,6 +1,6 @@ package scala.tools.reflect -import scala.reflect.macros.{ReificationError, UnexpectedReificationError} +import scala.reflect.macros.{ReificationException, UnexpectedReificationException} import scala.reflect.macros.runtime.Context import scala.collection.mutable.ListBuffer import scala.collection.mutable.Stack diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index f6dc92f96e..7cf3586d3d 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -195,7 +195,7 @@ class PathResolver(settings: Settings, context: JavaContext) { def scalaExtDirs = cmdLineOrElse("extdirs", Defaults.scalaExtDirs) /** Scaladoc doesn't need any bootstrapping, otherwise will create errors such as: * [scaladoc] ../scala-trunk/src/reflect/scala/reflect/macros/Reifiers.scala:89: error: object api is not a member of package reflect - * [scaladoc] case class ReificationError(val pos: reflect.api.PositionApi, val msg: String) extends Throwable(msg) + * [scaladoc] case class ReificationException(val pos: reflect.api.PositionApi, val msg: String) extends Throwable(msg) * [scaladoc] ^ * because the bootstrapping will look at the sourcepath and create package "reflect" in "" * and then when typing relative names, instead of picking .scala.relect, typedIdentifier will pick up the diff --git a/src/reflect/scala/reflect/macros/Reifiers.scala b/src/reflect/scala/reflect/macros/Reifiers.scala index ed31663c68..0022a488b9 100644 --- a/src/reflect/scala/reflect/macros/Reifiers.scala +++ b/src/reflect/scala/reflect/macros/Reifiers.scala @@ -76,6 +76,14 @@ trait Reifiers { // made these guys non path-dependent, otherwise exception handling quickly becomes a mess -case class ReificationError(val pos: scala.reflect.api.Position, val msg: String) extends Throwable(msg) +/** Indicates an expected error during one of the `reifyXXX` methods in [[scala.reflect.macros.Reifiers]]. + * Such errors represent one of the standard ways for reification to go wrong, e.g. + * an attempt to create a `TypeTag` from a weak type. + */ +case class ReificationException(val pos: scala.reflect.api.Position, val msg: String) extends Exception(msg) -case class UnexpectedReificationError(val pos: scala.reflect.api.Position, val msg: String, val cause: Throwable = null) extends Throwable(msg, cause) +/** Indicates an unexpected expected error during one of the `reifyXXX` methods in [[scala.reflect.macros.Reifiers]]. + * Such errors wrap random crashes in reification logic and are distinguished from expected [[scala.reflect.macros.ReificationException]]s + * so that the latter can be reported as compilation errors, while the former manifest themselves as compiler crashes. + */ +case class UnexpectedReificationException(val pos: scala.reflect.api.Position, val msg: String, val cause: Throwable = null) extends Exception(msg, cause) -- cgit v1.2.3 From d6bbf9bb9c8d0bd74abe47a1c2f4be66e0c19c03 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:15:24 +0200 Subject: removes EmptyTermName and EmptyTypeName We have nme.EMPTY and tpnme.EMPTY for that. --- src/compiler/scala/reflect/reify/utils/SymbolTables.scala | 2 +- src/reflect/scala/reflect/api/Names.scala | 8 -------- src/reflect/scala/reflect/api/Trees.scala | 4 ++-- .../files/run/macro-reflective-mamd-normal-mi/Macros_Test_2.scala | 2 +- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/compiler/scala/reflect/reify/utils/SymbolTables.scala b/src/compiler/scala/reflect/reify/utils/SymbolTables.scala index 3ec43c863d..dbb0836e0a 100644 --- a/src/compiler/scala/reflect/reify/utils/SymbolTables.scala +++ b/src/compiler/scala/reflect/reify/utils/SymbolTables.scala @@ -28,7 +28,7 @@ trait SymbolTables { symtab.get(sym) match { case Some(FreeDef(_, name, _, _, _)) => name case Some(SymDef(_, name, _, _)) => name - case None => EmptyTermName + case None => nme.EMPTY } def symAliases(sym: Symbol): List[TermName] = diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index e8665ca736..6cb226c32f 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -75,12 +75,4 @@ trait Names { /** Creates a new type name. */ def newTypeName(s: String): TypeName - - /** Wraps the empty string. Can be used as the null object for term name. - */ - def EmptyTermName: TermName = newTermName("") - - /** Wraps the empty string. Can be used as the null object for type name. - */ - def EmptyTypeName: TypeName = EmptyTermName.toTypeName } diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 1f15ee6070..63a06ab2e8 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -1967,12 +1967,12 @@ trait Trees { self: Universe => val Modifiers: ModifiersCreator abstract class ModifiersCreator { - def apply(): Modifiers = Modifiers(NoFlags, EmptyTypeName, List()) + def apply(): Modifiers = Modifiers(NoFlags, tpnme.EMPTY, List()) def apply(flags: FlagSet, privateWithin: Name, annotations: List[Tree]): Modifiers } def Modifiers(flags: FlagSet, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List()) - def Modifiers(flags: FlagSet): Modifiers = Modifiers(flags, EmptyTypeName) + def Modifiers(flags: FlagSet): Modifiers = Modifiers(flags, tpnme.EMPTY) /** ... */ lazy val NoMods = Modifiers() diff --git a/test/files/run/macro-reflective-mamd-normal-mi/Macros_Test_2.scala b/test/files/run/macro-reflective-mamd-normal-mi/Macros_Test_2.scala index 089f30f389..adecfcff17 100644 --- a/test/files/run/macro-reflective-mamd-normal-mi/Macros_Test_2.scala +++ b/test/files/run/macro-reflective-mamd-normal-mi/Macros_Test_2.scala @@ -11,7 +11,7 @@ object Test extends App { val macrobody = Select(Ident(newTermName("Impls")), newTermName("foo")) val macroparam = ValDef(NoMods, newTermName("x"), TypeTree(definitions.IntClass.toType), EmptyTree) val macrodef = DefDef(Modifiers(MACRO), newTermName("foo"), Nil, List(List(macroparam)), TypeTree(), macrobody) - val modulector = DefDef(NoMods, nme.CONSTRUCTOR, Nil, List(List()), TypeTree(), Block(Apply(Select(Super(This(EmptyTypeName), EmptyTypeName), nme.CONSTRUCTOR), List()))) + val modulector = DefDef(NoMods, nme.CONSTRUCTOR, Nil, List(List()), TypeTree(), Block(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List()))) val module = ModuleDef(NoMods, newTermName("Macros"), Template(Nil, emptyValDef, List(modulector, macrodef))) val macroapp = Apply(Select(Ident("Macros"), newTermName("foo")), List(Literal(Constant(42)))) val tree = Block(macrodef, module, macroapp) -- cgit v1.2.3 From b25f6514b77b1a93ea5a4a57041c9419e0efbe10 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:18:46 +0200 Subject: removes extraneous methods from api.Constants The next round of scaladoc-driven cleanup kicks in. --- src/reflect/scala/reflect/api/Constants.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/reflect/scala/reflect/api/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala index f2d8ef2eb9..0bb64b3b12 100644 --- a/src/reflect/scala/reflect/api/Constants.scala +++ b/src/reflect/scala/reflect/api/Constants.scala @@ -37,7 +37,6 @@ trait Constants { abstract class ConstantApi { val value: Any def tpe: Type - def isNaN: Boolean def booleanValue: Boolean def byteValue: Byte @@ -50,7 +49,5 @@ trait Constants { def stringValue: String def typeValue: Type def symbolValue: Symbol - - def convertTo(pt: Type): Constant } } -- cgit v1.2.3 From 7ee5bc9e549f07b8e73babce456e72539d7413d3 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:19:45 +0200 Subject: removes extraneous indirection from FlagValues We don't really need that abstract type. --- src/reflect/scala/reflect/api/FlagSets.scala | 4 +--- src/reflect/scala/reflect/internal/FlagSets.scala | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala index 599c4ca426..3eda54b28a 100644 --- a/src/reflect/scala/reflect/api/FlagSets.scala +++ b/src/reflect/scala/reflect/api/FlagSets.scala @@ -21,14 +21,12 @@ trait FlagSets { self: Universe => val Flag: FlagValues - type FlagValues >: Null <: FlagValuesApi - // Q: I have a pretty flag. Can I put it here? // A: Only if there's a tree that cannot be built without it. // 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. - trait FlagValuesApi { + trait FlagValues { /** Flag indicating that tree represents a trait */ val TRAIT: FlagSet diff --git a/src/reflect/scala/reflect/internal/FlagSets.scala b/src/reflect/scala/reflect/internal/FlagSets.scala index 6270416d4f..6a3b6870a0 100644 --- a/src/reflect/scala/reflect/internal/FlagSets.scala +++ b/src/reflect/scala/reflect/internal/FlagSets.scala @@ -17,8 +17,6 @@ trait FlagSets extends api.FlagSets { self: SymbolTable => val NoFlags: FlagSet = 0L - trait FlagValues extends FlagValuesApi - object Flag extends FlagValues { val TRAIT : FlagSet = Flags.TRAIT val INTERFACE : FlagSet = Flags.INTERFACE -- cgit v1.2.3 From f4521c7f4fd77bc42d4b3d9e6f8f8309a00fa922 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:20:53 +0200 Subject: removes extraneous methods from api.Scopes It's been more than a year, and I never used these methods. --- src/reflect/scala/reflect/api/Scopes.scala | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/reflect/scala/reflect/api/Scopes.scala b/src/reflect/scala/reflect/api/Scopes.scala index d30da07ad5..770349c5b5 100644 --- a/src/reflect/scala/reflect/api/Scopes.scala +++ b/src/reflect/scala/reflect/api/Scopes.scala @@ -21,6 +21,9 @@ trait Scopes { self: Universe => */ implicit val ScopeTag: ClassTag[Scope] + /** Create a new scope with the given initial elements. */ + def newScopeWith(elems: Symbol*): Scope + /** The type of member scopes, as in class definitions, for example. */ type MemberScope >: Null <: Scope with MemberScopeApi @@ -28,7 +31,7 @@ trait Scopes { self: Universe => trait MemberScopeApi extends ScopeApi { /** Sorts the symbols included in this scope so that: * 1) Symbols appear in the linearization order of their owners. - * 2) Symbols with the same owner appear in reverse order of their declarations. + * 2) Symbols with the same owner appear in same order of their declarations. * 3) Synthetic members (e.g. getters/setters for vals/vars) might appear in arbitrary order. */ def sorted: List[Symbol] @@ -38,13 +41,4 @@ trait Scopes { self: Universe => * Can be used for pattern matching, instance tests, serialization and likes. */ implicit val MemberScopeTag: ClassTag[MemberScope] - - /** Create a new scope. */ - def newScope: Scope - - /** Create a new scope nested in another one with which it shares its elements. */ - def newNestedScope(outer: Scope): Scope - - /** Create a new scope with the given initial elements. */ - def newScopeWith(elems: Symbol*): Scope } \ No newline at end of file -- cgit v1.2.3 From be493483b55548f06b5bebff689b99208272a4a9 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:22:53 +0200 Subject: removes extraneous methods from api.Mirrors We decided to give up on providing symbol table traversal facilities in the current incarnation of mirrors. Let's be consistent with ourselves. --- src/reflect/scala/reflect/api/Mirrors.scala | 31 ---------------------- .../scala/reflect/runtime/JavaMirrors.scala | 11 +------- 2 files changed, 1 insertion(+), 41 deletions(-) diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala index bff899daa4..bfd60dfba0 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -166,9 +166,6 @@ trait Mirrors { self: Universe => /** A mirror that reflects the instance or static parts of a runtime class */ trait TemplateMirror { - /** The runtime class reflected by this mirror */ - def runtimeClass: RuntimeClass - /** True if the mirror represents the static part * of a runtime class or the companion object of a Scala class. * One has: @@ -180,18 +177,6 @@ trait Mirrors { self: Universe => /** The Scala symbol corresponding to the reflected runtime class or object */ def symbol: Symbol - - /** Optionally, the mirror of the companion reflected by this mirror. - * If this mirror reflects a Scala object, the mirror for the companion class, or None - * if the mirror represents a Scala object that comes without a class. - * Otherwise, if the mirror represents the static part of a runtime class, the - * mirror representing the instance part of the same class. - * Otherwise, if the mirror represents a Scala instance class, the mirror for the companion - * object of that class, or None if no such object exists. - * Otherwise, if the mirror represents a runtime instance class, a mirror representing the static - * part of the same class. - */ - def companion: Option[TemplateMirror] } /** A mirror that reflects a Scala object definition or the static parts of a runtime class */ @@ -205,14 +190,6 @@ trait Mirrors { self: Universe => * If this mirror reflects the static part of a runtime class, returns `null`. */ def instance: Any - - /** Optionally, the mirror of the companion class if the object reflected by this mirror. - * If this mirror reflects a Scala object, the mirror for the companion class, or None - * if the mirror represents a Scala object that comes without a class. - * Otherwise, if the mirror represents the static part of a runtime class, the - * mirror representing the instance part of the same class. - */ - override def companion: Option[ClassMirror] } /** A mirror that reflects the instance parts of a runtime class */ @@ -232,14 +209,6 @@ trait Mirrors { self: Universe => * It must be a member (declared or inherited) of the class underlying this mirror. */ def reflectConstructor(constructor: MethodSymbol): MethodMirror - - /** Optionally, the mirror of the companion object of the class reflected by this mirror. - * If this mirror represents a Scala instance class, the mirror for the companion - * object of that class, or None if no such object exists. - * Otherwise, if the mirror represents a runtime instance class, a mirror representing the static - * part of the same class. - */ - override def companion: Option[ModuleMirror] } /** A mirror that reflects instances and static classes */ diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index b917eac779..e5ff9d62f2 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -446,8 +446,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni extends TemplateMirror { def outer: AnyRef def erasure: ClassSymbol - lazy val runtimeClass = classToJava(erasure) - lazy val signature = typeToScala(runtimeClass) + lazy val signature = typeToScala(classToJava(erasure)) } private class JavaClassMirror(val outer: AnyRef, val symbol: ClassSymbol) @@ -458,10 +457,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni checkConstructorOf(constructor, symbol) new JavaConstructorMirror(outer, constructor) } - def companion: Option[ModuleMirror] = symbol.companionModule match { - case module: ModuleSymbol => Some(new JavaModuleMirror(outer, module)) - case _ => None - } override def toString = s"class mirror for ${symbol.fullName} (bound to $outer)" } @@ -476,10 +471,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni if (outer == null) staticSingletonInstance(classToJava(symbol.moduleClass.asClass)) else innerSingletonInstance(outer, symbol.name) } - def companion: Option[ClassMirror] = symbol.companionClass match { - case cls: ClassSymbol => Some(new JavaClassMirror(outer, cls)) - case _ => None - } override def toString = s"module mirror for ${symbol.fullName} (bound to $outer)" } -- cgit v1.2.3 From 27003cc53e10528b55a9604f60a5f73ac8d0f702 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:29:03 +0200 Subject: hides internal methods of api.Printers --- src/reflect/scala/reflect/api/Printers.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala index 65ff2ed9fa..72a9bf8f3d 100644 --- a/src/reflect/scala/reflect/api/Printers.scala +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -5,7 +5,7 @@ import java.io.{ PrintWriter, StringWriter } trait Printers { self: Universe => - trait TreePrinter { + protected trait TreePrinter { def print(args: Any*) protected var printTypes = false protected var printIds = false @@ -52,7 +52,7 @@ trait Printers { self: Universe => /** Hook to define what `show(...)` means. */ - def newTreePrinter(out: PrintWriter): TreePrinter + protected def newTreePrinter(out: PrintWriter): TreePrinter /** Renders internal structure of a reflection artifact. */ @@ -61,7 +61,7 @@ trait Printers { self: Universe => /** Hook to define what `showRaw(...)` means. */ - def newRawTreePrinter(out: PrintWriter): TreePrinter + protected def newRawTreePrinter(out: PrintWriter): TreePrinter /** Renders a prettified representation of a name. */ -- cgit v1.2.3 From 9262c42db144cd3b9491fa087faa819d3c75247d Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:30:07 +0200 Subject: removes extraneous methods from api.Trees Tree.hasSymbol is really too much to document for its merit. --- src/reflect/scala/reflect/api/Trees.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 63a06ab2e8..5a87d1a90e 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -99,9 +99,6 @@ trait Trees { self: Universe => */ def symbol: Symbol - /** ... */ - def hasSymbol: Boolean - /** Provides an alternate if tree is empty * @param alt The alternate tree * @return If this tree is non empty, this tree, otherwise `alt`. -- cgit v1.2.3 From 8ff35b0dc4a41c1061a23da77ab5da668b27f17f Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 4 Oct 2012 07:30:41 +0200 Subject: removes extraneous methods from api.StandardDefinitions Never got to use these guys, so let's better remove them. --- src/reflect/scala/reflect/api/StandardDefinitions.scala | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/reflect/scala/reflect/api/StandardDefinitions.scala b/src/reflect/scala/reflect/api/StandardDefinitions.scala index 03f2a6b0aa..7197542370 100644 --- a/src/reflect/scala/reflect/api/StandardDefinitions.scala +++ b/src/reflect/scala/reflect/api/StandardDefinitions.scala @@ -67,12 +67,7 @@ trait StandardDefinitions { def Array_length: TermSymbol // todo. fix the bug in Definitions.getMemberMethod def Array_update: TermSymbol // todo. fix the bug in Definitions.getMemberMethod def ByNameParamClass: ClassSymbol - def ConsClass: ClassSymbol def FunctionClass : Array[ClassSymbol] - def IterableClass: ClassSymbol - def IteratorClass: ClassSymbol - def IteratorModule: ModuleSymbol - def Iterator_apply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod def JavaRepeatedParamClass: ClassSymbol def ListModule: ModuleSymbol def List_apply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod @@ -81,13 +76,7 @@ trait StandardDefinitions { def OptionClass: ClassSymbol def ProductClass : Array[ClassSymbol] def RepeatedParamClass: ClassSymbol - def SeqClass: ClassSymbol - def SeqModule: ModuleSymbol - def SomeClass: ClassSymbol def SomeModule: ModuleSymbol - def StringBuilderClass: ClassSymbol - def SymbolClass : ClassSymbol - def TraversableClass: ClassSymbol def TupleClass: Array[Symbol] // cannot make it Array[ClassSymbol], because TupleClass(0) is supposed to be NoSymbol. weird def ScalaPrimitiveValueClasses: List[ClassSymbol] def ScalaNumericValueClasses: List[ClassSymbol] -- cgit v1.2.3 From ca611e38e2ca9f10927f207b98ee0c0f7b8aca06 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 4 Oct 2012 07:32:50 +0200 Subject: removes extraneous methods from api.StandardNames nme.ROOT doesn't have much use in the public API (unlike nme.ROOTPKG). tpnme.EMPTY duplicates a method inherited from the base class. --- src/reflect/scala/reflect/api/StandardNames.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/reflect/scala/reflect/api/StandardNames.scala b/src/reflect/scala/reflect/api/StandardNames.scala index 354a9f9328..36ba840c84 100644 --- a/src/reflect/scala/reflect/api/StandardNames.scala +++ b/src/reflect/scala/reflect/api/StandardNames.scala @@ -23,7 +23,6 @@ trait StandardNames { trait NamesApi { type NameType >: Null <: Name val WILDCARD: NameType - val ROOT: NameType val EMPTY: NameType val ERROR: NameType val PACKAGE: NameType @@ -38,7 +37,6 @@ trait StandardNames { trait TypeNamesApi extends NamesApi { type NameType = TypeName - val EMPTY: NameType val WILDCARD_STAR: NameType } } -- cgit v1.2.3 From 02b9c23d1ab9d12eb31526d3edbc76d8ee43abf2 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:34:50 +0200 Subject: introduces macros.package.scala For the sole reason of putting docs on it in a separate pull request, which is being prepared elsewhere --- src/reflect/scala/reflect/macros/package.scala | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/reflect/scala/reflect/macros/package.scala diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala new file mode 100644 index 0000000000..6a69872367 --- /dev/null +++ b/src/reflect/scala/reflect/macros/package.scala @@ -0,0 +1,4 @@ +package scala.reflect + +package object macros { +} \ No newline at end of file -- cgit v1.2.3 From c868038423b5c28234e66788158e379754ed47b3 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:17:31 +0200 Subject: moves Attachments from api to macros Because they are only available in macros.Universe, not in api.Universe, therefore I'd argue that the confusion factor is stronger than the weirdness of scala.reflect.api.Position extending scala.reflect.macros.Attachments. --- src/reflect/scala/reflect/api/Attachments.scala | 50 ------------------- src/reflect/scala/reflect/api/Position.scala | 2 + .../scala/reflect/internal/StdAttachments.scala | 2 +- .../scala/reflect/internal/util/Position.scala | 2 +- src/reflect/scala/reflect/macros/Attachments.scala | 57 ++++++++++++++++++++++ src/reflect/scala/reflect/macros/Universe.scala | 2 +- 6 files changed, 62 insertions(+), 53 deletions(-) delete mode 100644 src/reflect/scala/reflect/api/Attachments.scala create mode 100644 src/reflect/scala/reflect/macros/Attachments.scala diff --git a/src/reflect/scala/reflect/api/Attachments.scala b/src/reflect/scala/reflect/api/Attachments.scala deleted file mode 100644 index edbb0131ca..0000000000 --- a/src/reflect/scala/reflect/api/Attachments.scala +++ /dev/null @@ -1,50 +0,0 @@ -package scala.reflect -package api - -/** Attachments is a generalization of Position. Typically it stores a Position of a tree, but this can be extended to - * encompass arbitrary payloads. Payloads are stored in type-indexed slots, which can be read with `get[T]` and written - * with `update[T]` and `remove[T]`. - * - * Attachments always carry positions because we don't want to introduce an additional field for attachments in `Tree` - * imposing an unnecessary memory tax because of something that will not be used in most cases. - */ -abstract class Attachments { self => - - /** The position type of this attachment */ - type Pos >: Null - - /** The underlying position */ - def pos: Pos - - /** Creates a copy of this attachment with the position replaced by `newPos` */ - def withPos(newPos: Pos): Attachments { type Pos = self.Pos } - - /** The underlying payload with the guarantee that no two elements have the same type. */ - def all: Set[Any] = Set.empty - - private def matchesTag[T: ClassTag](datum: Any) = - classTag[T].runtimeClass == datum.getClass - - /** An underlying payload of the given class type `T`. */ - def get[T: ClassTag]: Option[T] = - (all filter matchesTag[T]).headOption.asInstanceOf[Option[T]] - - /** Creates a copy of this attachment with the payload slot of T added/updated with the provided value. - * - * Replaces an existing payload of the same type, if exists. - */ - def update[T: ClassTag](attachment: T): Attachments { type Pos = self.Pos } = - new NonemptyAttachments(this.pos, remove[T].all + attachment) - - /** Creates a copy of this attachment with the payload of the given class type `T` removed. */ - def remove[T: ClassTag]: Attachments { type Pos = self.Pos } = { - val newAll = all filterNot matchesTag[T] - if (newAll.isEmpty) pos.asInstanceOf[Attachments { type Pos = self.Pos }] - else new NonemptyAttachments(this.pos, newAll) - } - - private class NonemptyAttachments(override val pos: Pos, override val all: Set[Any]) extends Attachments { - type Pos = self.Pos - def withPos(newPos: Pos) = new NonemptyAttachments(newPos, all) - } -} diff --git a/src/reflect/scala/reflect/api/Position.scala b/src/reflect/scala/reflect/api/Position.scala index 9c63e4becf..d3dc9c884f 100644 --- a/src/reflect/scala/reflect/api/Position.scala +++ b/src/reflect/scala/reflect/api/Position.scala @@ -1,6 +1,8 @@ package scala.reflect 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, diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 5c4d1f7e28..9fe443bf50 100644 --- a/src/reflect/scala/reflect/internal/StdAttachments.scala +++ b/src/reflect/scala/reflect/internal/StdAttachments.scala @@ -8,7 +8,7 @@ trait StdAttachments { * Common code between reflect-internal Symbol and Tree related to Attachments. */ trait Attachable { - protected var rawatt: scala.reflect.api.Attachments { type Pos = Position } = NoPosition + protected var rawatt: scala.reflect.macros.Attachments { type Pos = Position } = NoPosition def attachments = rawatt def updateAttachment[T: ClassTag](attachment: T): this.type = { rawatt = rawatt.update(attachment); this } def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this } diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala index 151a64daff..d4225bcff5 100644 --- a/src/reflect/scala/reflect/internal/util/Position.scala +++ b/src/reflect/scala/reflect/internal/util/Position.scala @@ -7,7 +7,7 @@ package scala.reflect.internal.util import scala.reflect.ClassTag -import scala.reflect.api.Attachments +import scala.reflect.macros.Attachments object Position { val tabInc = 8 diff --git a/src/reflect/scala/reflect/macros/Attachments.scala b/src/reflect/scala/reflect/macros/Attachments.scala new file mode 100644 index 0000000000..ba5ccf88f1 --- /dev/null +++ b/src/reflect/scala/reflect/macros/Attachments.scala @@ -0,0 +1,57 @@ +package scala.reflect +package macros + +/** Attachments provide a way to associate custom metadata with symbols and trees. + * + * Along with `symbol` and `tpe`, which represent core metadata of trees, each tree + * carries the `attachments` field that can store other metadata: compiler-defined (e.g. positions) or user-defined. + * Same story is true for symbols, which also have extensible metadata by the virtue + * of the same `attachments` field. + * + * Typically attachments just store a [[scala.reflect.api.Position]], but they can be extended to + * encompass arbitrary payloads. Payloads are stored in type-indexed slots, which can be read with `get[T]` and written + * with `update[T]` and `remove[T]`. + * + * This API doesn't have much use in the runtime reflection API (the [[scala.reflect.api]] package), but it might be of help + * for macro writers, providing a way to coordinate multiple macros operating on the same code. Therefore the `attachments` + * field is only declared in trees and symbols belonging to [[scala.reflect.macros.Universe]]. + */ +abstract class Attachments { self => + + /** The position type of this attachment */ + type Pos >: Null + + /** The underlying position */ + def pos: Pos + + /** Creates a copy of this attachment with the position replaced by `newPos` */ + def withPos(newPos: Pos): Attachments { type Pos = self.Pos } + + /** The underlying payload with the guarantee that no two elements have the same type. */ + def all: Set[Any] = Set.empty + + private def matchesTag[T: ClassTag](datum: Any) = + classTag[T].runtimeClass == datum.getClass + + /** An underlying payload of the given class type `T`. */ + def get[T: ClassTag]: Option[T] = + (all filter matchesTag[T]).headOption.asInstanceOf[Option[T]] + + /** Creates a copy of this attachment with the payload slot of T added/updated with the provided value. + * Replaces an existing payload of the same type, if exists. + */ + def update[T: ClassTag](attachment: T): Attachments { type Pos = self.Pos } = + new NonemptyAttachments(this.pos, remove[T].all + attachment) + + /** Creates a copy of this attachment with the payload of the given class type `T` removed. */ + def remove[T: ClassTag]: Attachments { type Pos = self.Pos } = { + val newAll = all filterNot matchesTag[T] + if (newAll.isEmpty) pos.asInstanceOf[Attachments { type Pos = self.Pos }] + else new NonemptyAttachments(this.pos, newAll) + } + + private class NonemptyAttachments(override val pos: Pos, override val all: Set[Any]) extends Attachments { + type Pos = self.Pos + def withPos(newPos: Pos) = new NonemptyAttachments(newPos, all) + } +} diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index 97d0a8d98a..3e38691d85 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -7,7 +7,7 @@ abstract class Universe extends scala.reflect.api.Universe { trait AttachableApi { /** ... */ - def attachments: scala.reflect.api.Attachments { type Pos = Position } + def attachments: Attachments { type Pos = Position } /** ... */ def updateAttachment[T: ClassTag](attachment: T): AttachableApi.this.type -- cgit v1.2.3 From cfae88959153996c25ba1a93f2456e3e4912194c Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:28:16 +0200 Subject: introduces api.JavaMirrors This trait carries mirror-related changes of the API that happen when api.Universe transforms into api.JavaUniverse. From a coding standpoint this is a mere rehashing of the code, but from a documentation standpoint this provides additional insights into what's going on in reflection. --- src/reflect/scala/reflect/api/JavaMirrors.scala | 16 ++++++++++++++++ src/reflect/scala/reflect/api/JavaUniverse.scala | 13 +------------ 2 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 src/reflect/scala/reflect/api/JavaMirrors.scala diff --git a/src/reflect/scala/reflect/api/JavaMirrors.scala b/src/reflect/scala/reflect/api/JavaMirrors.scala new file mode 100644 index 0000000000..cb0fa0f650 --- /dev/null +++ b/src/reflect/scala/reflect/api/JavaMirrors.scala @@ -0,0 +1,16 @@ +package scala.reflect +package api + +trait JavaMirrors { self: JavaUniverse => + + type RuntimeClass = java.lang.Class[_] + + override type Mirror >: Null <: JavaMirror + + trait JavaMirror extends scala.reflect.api.Mirror[self.type] with RuntimeMirror { + val classLoader: ClassLoader + override def toString = s"JavaMirror with ${runtime.ReflectionUtils.show(classLoader)}" + } + + def runtimeMirror(cl: ClassLoader): Mirror +} diff --git a/src/reflect/scala/reflect/api/JavaUniverse.scala b/src/reflect/scala/reflect/api/JavaUniverse.scala index cc703e833d..1a8a02776b 100644 --- a/src/reflect/scala/reflect/api/JavaUniverse.scala +++ b/src/reflect/scala/reflect/api/JavaUniverse.scala @@ -1,18 +1,7 @@ package scala.reflect package api -trait JavaUniverse extends Universe with Mirrors { self => - - type RuntimeClass = java.lang.Class[_] - - override type Mirror >: Null <: JavaMirror - - trait JavaMirror extends scala.reflect.api.Mirror[self.type] with RuntimeMirror { - val classLoader: ClassLoader - override def toString = s"JavaMirror with ${runtime.ReflectionUtils.show(classLoader)}" - } - - def runtimeMirror(cl: ClassLoader): Mirror +trait JavaUniverse extends Universe with JavaMirrors { self => override def typeTagToManifest[T: ClassTag](mirror0: Any, tag: Universe # TypeTag[T]): Manifest[T] = { // SI-6239: make this conversion more precise -- cgit v1.2.3 From 112e922acdce5d2b1a102be95c211abcb5c0b59d Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 3 Oct 2012 23:31:28 +0200 Subject: upgrades showRaw Fixes the stuff that was irritating, when I was preparing examples for reflection documentation. Has zero impact at stability of scalac, because showRaw isn't used anywhere in the compiler unless invoked explicitly. --- src/reflect/scala/reflect/internal/Printers.scala | 47 ++++++++++++++--------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index fb165ab50f..fd5a7cf88b 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -534,17 +534,16 @@ trait Printers extends api.Printers { self: SymbolTable => depth += 1 args foreach { + case expr: Expr[_] => + print("Expr") + if (printTypes) print(expr.staticType) + print("(") + print(expr.tree) + print(")") case EmptyTree => print("EmptyTree") case emptyValDef: AnyRef if emptyValDef eq self.emptyValDef => print("emptyValDef") - case Literal(Constant(value)) => - def print(s: String) = this.print("Literal(Constant(" + s + "))") - value match { - case s: String => print("\"" + s + "\"") - case null => print(null) - case _ => print(value.toString) - } case tree: Tree => val hasSymbol = tree.hasSymbol && tree.symbol != NoSymbol val isError = hasSymbol && tree.symbol.name.toString == nme.ERROR.toString @@ -568,6 +567,12 @@ trait Printers extends api.Printers { self: SymbolTable => } else { print(name) } + case Constant(s: String) => + print("Constant(\"" + s + "\")") + case Constant(null) => + print("Constant(null)") + case Constant(value) => + print("Constant(" + value + ")") case arg => print(arg) }, @@ -582,14 +587,18 @@ trait Printers extends api.Printers { self: SymbolTable => if (printIds) print("#", sym.id) if (printKinds) print("#", sym.abbreviatedKindString) if (printMirrors) print("%M", footnotes.put[scala.reflect.api.Mirror[_]](mirrorThatLoaded(sym))) - case NoType => - print("NoType") - case NoPrefix => - print("NoPrefix") + case tag: TypeTag[_] => + print("TypeTag(", tag.tpe, ")") + case tag: WeakTypeTag[_] => + print("WeakTypeTag(", tag.tpe, ")") case tpe: Type => val defer = printTypesInFootnotes && !printingFootnotes if (defer) print("[", footnotes.put(tpe), "]") - else printProduct(tpe.asInstanceOf[Product]) + else tpe match { + case NoType => print("NoType") + case NoPrefix => print("NoPrefix") + case _ => printProduct(tpe.asInstanceOf[Product]) + } case mods: Modifiers => print("Modifiers(") if (mods.flags != NoFlags || mods.privateWithin != tpnme.EMPTY || mods.annotations.nonEmpty) print(show(mods.flags)) @@ -598,6 +607,9 @@ trait Printers extends api.Printers { self: SymbolTable => print(")") case name: Name => print(show(name)) + case scope: Scope => + print("Scope") + printIterable(scope.toList) case list: List[_] => print("List") printIterable(list) @@ -645,16 +657,15 @@ trait Printers extends api.Printers { self: SymbolTable => } def show(name: Name): String = name match { + case tpnme.WILDCARD => "tpnme.WILDCARD" case tpnme.EMPTY => "tpnme.EMPTY" - case tpnme.ROOT => "tpnme.ROOT" + case tpnme.ERROR => "tpnme.ERROR" case tpnme.PACKAGE => "tpnme.PACKAGE" - case tpnme.EMPTY_PACKAGE_NAME => "tpnme.EMPTY_PACKAGE_NAME" - case tpnme.WILDCARD => "tpnme.WILDCARD" + case tpnme.WILDCARD_STAR => "tpnme.WILDCARD_STAR" + case nme.WILDCARD => "nme.WILDCARD" case nme.EMPTY => "nme.EMPTY" - case nme.ROOT => "nme.ROOT" + case nme.ERROR => "tpnme.ERROR" case nme.PACKAGE => "nme.PACKAGE" - case nme.EMPTY_PACKAGE_NAME => "nme.EMPTY_PACKAGE_NAME" - case nme.WILDCARD => "nme.WILDCARD" case nme.CONSTRUCTOR => "nme.CONSTRUCTOR" case nme.ROOTPKG => "nme.ROOTPKG" case _ => -- cgit v1.2.3 From 1b2ac4e618fd3e95efdeb965b0deebc2c5f78580 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 7 Oct 2012 15:16:31 +0200 Subject: SI-6483 Prohibit super[T] references in value classes. This seems the safest course of action for 2.10.0. --- .../scala/tools/nsc/typechecker/Typers.scala | 3 +++ test/files/neg/t6483.check | 9 ++++++++ test/files/neg/t6483.scala | 24 ++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 test/files/neg/t6483.check create mode 100644 test/files/neg/t6483.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 5a9920c9e3..f82786da35 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1420,6 +1420,9 @@ trait Typers extends Modes with Adaptations with Tags { case x: ValDef if x.mods.isLazy => //see https://issues.scala-lang.org/browse/SI-6358 implRestriction(tree, "lazy val") + case Select(sup @ Super(qual, mix), selector) if selector != nme.CONSTRUCTOR && qual.symbol == clazz && mix != tpnme.EMPTY => + //see https://issues.scala-lang.org/browse/SI-6483 + implRestriction(sup, "qualified super reference") case _ => } super.traverse(tree) diff --git a/test/files/neg/t6483.check b/test/files/neg/t6483.check new file mode 100644 index 0000000000..66e3507107 --- /dev/null +++ b/test/files/neg/t6483.check @@ -0,0 +1,9 @@ +t6483.scala:7: error: implementation restriction: qualified super reference is not allowed in value class +This restriction is planned to be removed in subsequent releases. + override def foo = super[T].foo // error + ^ +t6483.scala:20: error: implementation restriction: nested class is not allowed in value class +This restriction is planned to be removed in subsequent releases. + class Inner extends T { + ^ +two errors found diff --git a/test/files/neg/t6483.scala b/test/files/neg/t6483.scala new file mode 100644 index 0000000000..bd99f68fa4 --- /dev/null +++ b/test/files/neg/t6483.scala @@ -0,0 +1,24 @@ +trait T extends Any { + def foo = 1 + type X +} + +class C1(val a: Any) extends AnyVal with T { + override def foo = super[T].foo // error +} + +class C2(val a: Int) extends AnyVal with T { + override def foo = super.foo + a // okay +} + +class C3(val a: Int) extends AnyVal with T { + override def foo = C3.super.foo + a // okay +} + +class C4(val a: Int) extends AnyVal with T { + def foo { + class Inner extends T { + override def foo = super[T].foo + a // no (direct) error, other than that a nested class is currently illegal. + } + } +} -- cgit v1.2.3 From 0bf9daaac7ab46a3e9dd113565b0073eed95be59 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Mon, 8 Oct 2012 06:30:21 +0200 Subject: SI-6485 stops creating extmethods for macros Macros don't correspond to bytecode-level methods, therefore there's no need to undergo any transformations past typer. --- src/reflect/scala/reflect/internal/Symbols.scala | 2 +- test/files/pos/t6485a/Macros_1.scala | 5 +++++ test/files/pos/t6485a/Test_2.scala | 5 +++++ test/files/pos/t6485b/Test.scala | 10 ++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 test/files/pos/t6485a/Macros_1.scala create mode 100644 test/files/pos/t6485a/Test_2.scala create mode 100644 test/files/pos/t6485b/Test.scala diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index c95678fa67..a6f156f947 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -654,7 +654,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => info.firstParent.typeSymbol == AnyValClass && !isPrimitiveValueClass final def isMethodWithExtension = - isMethod && owner.isDerivedValueClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR) + isMethod && owner.isDerivedValueClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR) && !isTermMacro final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME) final def isDefinedInPackage = effectiveOwner.isPackageClass diff --git a/test/files/pos/t6485a/Macros_1.scala b/test/files/pos/t6485a/Macros_1.scala new file mode 100644 index 0000000000..85c2d5dbdb --- /dev/null +++ b/test/files/pos/t6485a/Macros_1.scala @@ -0,0 +1,5 @@ +import scala.reflect.macros.Context + +object Macros { + def crash(c: Context): c.Expr[Unit] = c.universe.reify(()) +} \ No newline at end of file diff --git a/test/files/pos/t6485a/Test_2.scala b/test/files/pos/t6485a/Test_2.scala new file mode 100644 index 0000000000..54e260ac74 --- /dev/null +++ b/test/files/pos/t6485a/Test_2.scala @@ -0,0 +1,5 @@ +import scala.language.experimental.macros + +final class Ops[T](val x: T) extends AnyVal { + def f = macro Macros.crash +} diff --git a/test/files/pos/t6485b/Test.scala b/test/files/pos/t6485b/Test.scala new file mode 100644 index 0000000000..382df1c453 --- /dev/null +++ b/test/files/pos/t6485b/Test.scala @@ -0,0 +1,10 @@ +import scala.language.experimental.macros +import scala.reflect.macros.Context + +final class Ops[T](val x: T) extends AnyVal { + def f = macro Macros.crash +} + +object Macros { + def crash(c: Context): c.Expr[Unit] = c.universe.reify(()) +} \ No newline at end of file -- cgit v1.2.3 From 49dcb8ff33483949cecce671a2d87676cefa457f Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Mon, 8 Oct 2012 16:10:34 +0200 Subject: removes strongly-typed Constant.value wrappers These are surely not necessary. Thanks Vlad! --- src/reflect/scala/reflect/api/Constants.scala | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/reflect/scala/reflect/api/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala index 0bb64b3b12..2f201d033d 100644 --- a/src/reflect/scala/reflect/api/Constants.scala +++ b/src/reflect/scala/reflect/api/Constants.scala @@ -37,17 +37,5 @@ trait Constants { abstract class ConstantApi { val value: Any def tpe: Type - - def booleanValue: Boolean - def byteValue: Byte - def shortValue: Short - def charValue: Char - def intValue: Int - def longValue: Long - def floatValue: Float - def doubleValue: Double - def stringValue: String - def typeValue: Type - def symbolValue: Symbol } } -- cgit v1.2.3 From bf0e26c04577690bc15dd08eeb706ba0f6fa4cf4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 9 Oct 2012 19:06:26 +0200 Subject: Proposed fix for SI-6490. Issues a "companions must be in same file" error only if both class and module exist. This can certainly do no harm. I believe it should adress SI-6490, but, lacking a test case, I don't have evidence for that. --- src/compiler/scala/tools/nsc/typechecker/Namers.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 1b2225f5f2..a37dc77d44 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -377,6 +377,8 @@ trait Namers extends MethodSynthesis { && (clazz.sourceFile ne null) && (module.sourceFile ne null) && !(module isCoDefinedWith clazz) + && module.exists + && clazz.exists ) if (fails) { context.unit.error(tree.pos, ( -- cgit v1.2.3 From 7a6905dc158a7a543ba3f4ddeeffe538580958d3 Mon Sep 17 00:00:00 2001 From: Grzegorz Kossakowski Date: Tue, 9 Oct 2012 15:45:35 -0700 Subject: SI-6440: Revert change to `TraversableLike.filterNot` Commit df9f470f14262b9b1002f022c2620d8c38835805 introduced a change to `TraversableLike.filterNot` which broke Stream implementation that does override `filter` implementation but does not override `filterNot` implementation. This shows clearly that reusing code for strict and non-strict collections is very problematic. Added a test-case covering this problem. Closes SI-6440. Review by @retronym. --- src/library/scala/collection/TraversableLike.scala | 7 +------ test/files/run/t6440.check | 1 + test/files/run/t6440.scala | 7 +++++++ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 test/files/run/t6440.check create mode 100644 test/files/run/t6440.scala diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index ce0b130b86..7849f1c544 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -271,12 +271,7 @@ trait TraversableLike[+A, +Repr] extends Any * @return a new $coll consisting of all elements of this $coll that do not satisfy the given * predicate `p`. The order of the elements is preserved. */ - def filterNot(p: A => Boolean): Repr = { - val b = newBuilder - for (x <- this) - if (!p(x)) b += x - b.result - } + def filterNot(p: A => Boolean): Repr = filter(!p(_)) def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = { val b = bf(repr) diff --git a/test/files/run/t6440.check b/test/files/run/t6440.check new file mode 100644 index 0000000000..b5684daee4 --- /dev/null +++ b/test/files/run/t6440.check @@ -0,0 +1 @@ +Stream((), ?) diff --git a/test/files/run/t6440.scala b/test/files/run/t6440.scala new file mode 100644 index 0000000000..2b690f31e1 --- /dev/null +++ b/test/files/run/t6440.scala @@ -0,0 +1,7 @@ +object Test { + + def main(args: Array[String]): Unit = { + println(Stream.continually(()).filterNot(_ => false).take(2)) + } + +} -- cgit v1.2.3 From 4c7127d9acb1e0bae6f14a6b40019a535d057112 Mon Sep 17 00:00:00 2001 From: Mirco Dotta Date: Wed, 10 Oct 2012 09:29:30 +0200 Subject: Deprecated instrumentation API The instrumentation logic needed by the Scala IDE Worksheet is currently part of the Scala project, but it doesn't need to be. I already have a PR ready for completely removing the instrumentation logic, but I considered it too risky at this point for 2.10.0 release (an oversight can lead to the impossibility of running the worksheet with Scala 2.10.0). For the moment, I believe it's better to deprecate the whole instrumentation API in 2.10.0, and the PR for removing the instrumentation logic will target 2.10.1 or 2.11.0. Besides deprecating the instrumentation API, this commit also raised visibility of `interruptsEnabled` member in `Global`. This change alone is sufficient for moving the instrumentation logic outside of the compiler, and it is needed because the Presentation Compiler thread should never be interrupted while instrumenting a source. This commit is related to SI-6458 --- src/compiler/scala/tools/nsc/interactive/CompilerControl.scala | 2 ++ src/compiler/scala/tools/nsc/interactive/Global.scala | 3 ++- src/compiler/scala/tools/nsc/interactive/REPL.scala | 3 +++ src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala | 1 + src/compiler/scala/tools/nsc/scratchpad/Mixer.scala | 1 + src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala | 1 + src/library/scala/runtime/WorksheetSupport.scala | 1 + 7 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index ae38a082ca..9af90eb204 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -221,6 +221,7 @@ trait CompilerControl { self: Global => * everything is brought up to date in a regular type checker run. * @param response The response. */ + @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") def askInstrumented(source: SourceFile, line: Int, response: Response[(String, Array[Char])]) = postWorkItem(new AskInstrumentedItem(source, line, response)) @@ -388,6 +389,7 @@ trait CompilerControl { self: Global => response raise new MissingResponse } + @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") case class AskInstrumentedItem(val source: SourceFile, line: Int, response: Response[(String, Array[Char])]) extends WorkItem { def apply() = self.getInstrumented(source, line, response) override def toString = "getInstrumented "+source diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 5514983d98..01889f4f98 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -205,7 +205,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") protected[interactive] var minRunId = 1 - private var interruptsEnabled = true + private[interactive] var interruptsEnabled = true private val NoResponse: Response[_] = new Response[Any] @@ -1041,6 +1041,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } } + @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") def getInstrumented(source: SourceFile, line: Int, response: Response[(String, Array[Char])]) = try { interruptsEnabled = false diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala index afac5828e5..be837b32f3 100644 --- a/src/compiler/scala/tools/nsc/interactive/REPL.scala +++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala @@ -92,6 +92,7 @@ object REPL { val completeResult = new Response[List[comp.Member]] val typedResult = new Response[comp.Tree] val structureResult = new Response[comp.Tree] + @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") val instrumentedResult = new Response[(String, Array[Char])] def makePos(file: String, off1: String, off2: String) = { @@ -124,6 +125,7 @@ object REPL { * @param iContents An Array[Char] containing the instrumented source * @return The name of the instrumented source file */ + @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") def writeInstrumented(iFullName: String, suffix: String, iContents: Array[Char]): String = { val iSimpleName = iFullName drop ((iFullName lastIndexOf '.') + 1) val iSourceName = iSimpleName + suffix @@ -142,6 +144,7 @@ object REPL { * and outputs in the right column, or None if the presentation compiler * does not respond to askInstrumented. */ + @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") def instrument(arguments: List[String], line: Int): Option[(String, String)] = { val source = toSourceFile(arguments.head) // strip right hand side comment column and any trailing spaces from all lines diff --git a/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala b/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala index 7d332d9f7f..7f0265bf4f 100644 --- a/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala +++ b/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala @@ -6,6 +6,7 @@ import scala.collection.mutable.ArrayBuffer import scala.reflect.internal.Chars.{isLineBreakChar, isWhitespace} import ast.parser.Tokens._ +@deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") trait ScratchPadMaker { self: Global => import definitions._ diff --git a/src/compiler/scala/tools/nsc/scratchpad/Mixer.scala b/src/compiler/scala/tools/nsc/scratchpad/Mixer.scala index f7ad39bd95..10e9982594 100644 --- a/src/compiler/scala/tools/nsc/scratchpad/Mixer.scala +++ b/src/compiler/scala/tools/nsc/scratchpad/Mixer.scala @@ -7,6 +7,7 @@ import java.lang.reflect.InvocationTargetException import scala.reflect.runtime.ReflectionUtils._ import scala.collection.mutable.ArrayBuffer +@deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") class Mixer { protected val stdSeparator = "//> " diff --git a/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala b/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala index 5eeab53fca..01dccd7521 100644 --- a/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala +++ b/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala @@ -5,6 +5,7 @@ import java.io.Writer import scala.reflect.internal.util.SourceFile import scala.reflect.internal.Chars._ +@deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") object SourceInserter { def stripRight(cs: Array[Char]): Array[Char] = { val lines = diff --git a/src/library/scala/runtime/WorksheetSupport.scala b/src/library/scala/runtime/WorksheetSupport.scala index a003bba034..016a0d04e0 100644 --- a/src/library/scala/runtime/WorksheetSupport.scala +++ b/src/library/scala/runtime/WorksheetSupport.scala @@ -4,6 +4,7 @@ import scala.runtime.ScalaRunTime.stringOf /** A utility object that's needed by the code that executes a worksheet. */ +@deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0") object WorksheetSupport { /** The offset in the source which should be printed */ -- cgit v1.2.3 From 19ea47b3425f973c1ca92890cb8ee561b0ecab3d Mon Sep 17 00:00:00 2001 From: Iulian Dragos Date: Wed, 10 Oct 2012 11:28:00 +0200 Subject: Fixed SI-6505. Respond to ask calls by immediate failure even after compiler shutdown. When the compiler is asked to shutdown, it may still have items on the working queue, and more can be added by clients in other thread that don't *know* the compiler is down yet. These requests were never serviced, leading to deadlocks or timeouts. review by @odersky, @hubertp --- .../tools/nsc/interactive/CompilerControl.scala | 11 ++++++++ .../scala/tools/nsc/util/InterruptReq.scala | 5 +++- test/files/presentation/forgotten-ask.scala | 33 ++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 test/files/presentation/forgotten-ask.scala diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index ae38a082ca..9b96608b69 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -13,6 +13,7 @@ import scala.tools.nsc.util.FailedInterrupt import scala.tools.nsc.util.EmptyAction import scala.tools.nsc.util.WorkScheduler import scala.reflect.internal.util.{SourceFile, Position} +import scala.tools.nsc.util.InterruptReq /** Interface of interactive compiler to a client such as an IDE * The model the presentation compiler consists of the following parts: @@ -413,6 +414,16 @@ trait CompilerControl { self: Global => override def doQuickly[A](op: () => A): A = { throw new FailedInterrupt(new Exception("Posted a work item to a compiler that's shutting down")) } + + override def askDoQuickly[A](op: () => A): InterruptReq { type R = A } = { + val ir = new InterruptReq { + type R = A + val todo = () => throw new MissingResponse + } + ir.execute() + ir + } + } } diff --git a/src/compiler/scala/tools/nsc/util/InterruptReq.scala b/src/compiler/scala/tools/nsc/util/InterruptReq.scala index 816d16f767..b1b81d0952 100644 --- a/src/compiler/scala/tools/nsc/util/InterruptReq.scala +++ b/src/compiler/scala/tools/nsc/util/InterruptReq.scala @@ -47,7 +47,10 @@ abstract class InterruptReq { } def onComplete(k: Continuation) = synchronized { - waiting = k :: waiting + if (result.isDefined) + k(result.get) + else + waiting = k :: waiting } } diff --git a/test/files/presentation/forgotten-ask.scala b/test/files/presentation/forgotten-ask.scala new file mode 100644 index 0000000000..358dd75e98 --- /dev/null +++ b/test/files/presentation/forgotten-ask.scala @@ -0,0 +1,33 @@ +import scala.tools.nsc.interactive._ +import tests._ + +/** Test that no ask calls are left unanswered after a compiler has shut down. */ +object Test extends InteractiveTest { + import compiler._ + + def askItem(): Response[Unit] = { + compiler.askForResponse { () => + Thread.sleep(100) + } + } + + final val Timeout = 5000 //ms + + override def main(args: Array[String]) { + val item1 = askItem() + + compiler.askShutdown() + + Thread.sleep(1000) // wait a bit, the compiler is shutting down + val item2 = askItem() + + item1.get(Timeout) match { + case None => println("TIMEOUT") + case _ => + } + item2.get(Timeout) match { + case None => println("TIMEOUT") + case _ => + } + } +} \ No newline at end of file -- cgit v1.2.3 From bc25fc53ade2131a2717b3101a01abbbfcbdf646 Mon Sep 17 00:00:00 2001 From: Heather Miller Date: Wed, 10 Oct 2012 11:59:54 +0200 Subject: SI-6099 - Scaladoc for scala.concurrent incomplete This is a rebase and resubmission of @phaller's pull https://github.com/scala/scala/pull/1485 With the reviewers' comments additionally addressed --- build.xml | 2 +- src/library/scala/concurrent/Awaitable.scala | 55 +++++++++++++--------- src/library/scala/concurrent/package.scala | 70 ++++++++++++++-------------- 3 files changed, 70 insertions(+), 57 deletions(-) diff --git a/build.xml b/build.xml index 9109da5276..c9027e0985 100644 --- a/build.xml +++ b/build.xml @@ -2337,7 +2337,7 @@ DOCUMENTATION docfooter="epfl" docsourceurl="${scaladoc.url}€{FILE_PATH}.scala#L1" docUncompilable="${src.dir}/library-aux" - skipPackages="scala.reflect.macros.internal:scala.reflect.internal:scala.reflect.io" + skipPackages="scala.reflect.macros.internal:scala.reflect.internal:scala.reflect.io:scala.concurrent.impl" sourcepath="${src.dir}" classpathref="pack.classpath" addparams="${scalac.args.all}" diff --git a/src/library/scala/concurrent/Awaitable.scala b/src/library/scala/concurrent/Awaitable.scala index 3bd7617bce..c0c688bf42 100644 --- a/src/library/scala/concurrent/Awaitable.scala +++ b/src/library/scala/concurrent/Awaitable.scala @@ -14,36 +14,47 @@ import scala.concurrent.duration.Duration +/** + * An object that may eventually be completed with a result value of type `T` which may be + * awaited using blocking methods. + * + * The [[Await]] object provides methods that allow accessing the result of an `Awaitable` + * by blocking the current thread until the `Awaitable` has been completed or a timeout has + * occurred. + */ trait Awaitable[+T] { + /** - * Await the "resolved" state of this Awaitable. - * This method should not be called directly. - * - * @param atMost - * maximum wait time, which may be negative (no waiting is done), - * [[Duration.Inf]] for unbounded waiting, or a finite positive - * duration - * @return the Awaitable itself - * @throws InterruptedException if the wait call was interrupted - * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready - * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]] + * Await the "completed" state of this `Awaitable`. + * + * '''''This method should not be called directly; use [[Await.ready]] instead.''''' + * + * @param atMost + * maximum wait time, which may be negative (no waiting is done), + * [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive + * duration + * @return this `Awaitable` + * @throws InterruptedException if the current thread is interrupted while waiting + * @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready + * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]] */ @throws(classOf[TimeoutException]) @throws(classOf[InterruptedException]) def ready(atMost: Duration)(implicit permit: CanAwait): this.type /** - * Await and return the result of this Awaitable, which is either of type T or a thrown exception (any Throwable). - * This method should not be called directly. - * - * @param atMost - * maximum wait time, which may be negative (no waiting is done), - * [[Duration.Inf]] for unbounded waiting, or a finite positive - * duration - * @return the value if the Awaitable was successful within the specific maximum wait time - * @throws InterruptedException if the wait call was interrupted - * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready - * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]] + * Await and return the result (of type `T`) of this `Awaitable`. + * + * '''''This method should not be called directly; use [[Await.result]] instead.''''' + * + * @param atMost + * maximum wait time, which may be negative (no waiting is done), + * [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive + * duration + * @return the result value if the `Awaitable` is completed within the specific maximum wait time + * @throws InterruptedException if the current thread is interrupted while waiting + * @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready + * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]] */ @throws(classOf[Exception]) def result(atMost: Duration)(implicit permit: CanAwait): T diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala index e683732e41..c0d46df883 100644 --- a/src/library/scala/concurrent/package.scala +++ b/src/library/scala/concurrent/package.scala @@ -23,7 +23,7 @@ package object concurrent { * The result becomes available once the asynchronous computation is completed. * * @tparam T the type of the result - * @param body the asychronous computation + * @param body the asynchronous computation * @param execctx the execution context on which the future is run * @return the `Future` holding the result of the computation */ @@ -37,17 +37,15 @@ package object concurrent { */ def promise[T]()(implicit execctx: ExecutionContext): Promise[T] = Promise[T]() - /** Used to designate a piece of code which potentially blocks, allowing the BlockContext to adjust the runtime's behavior. + /** Used to designate a piece of code which potentially blocks, allowing the current [[BlockContext]] to adjust + * the runtime's behavior. * Properly marking blocking code may improve performance or avoid deadlocks. * - * If you have an `Awaitable` then you should use Await.result instead of `blocking`. + * Blocking on an [[Awaitable]] should be done using [[Await.result]] instead of `blocking`. * * @param body A piece of code which contains potentially blocking or long running calls. - * - * Calling this method may throw the following exceptions: - * - CancellationException - if the computation was cancelled - * - InterruptedException - in the case that a wait within the blockable object was interrupted - * - TimeoutException - in the case that the blockable object timed out + * @throws `CancellationException` if the computation was cancelled + * @throws `InterruptedException` in the case that a wait within the blocking `body` was interrupted */ @throws(classOf[Exception]) def blocking[T](body: =>T): T = BlockContext.current.blockOn(body)(scala.concurrent.AwaitPermission) @@ -67,19 +65,21 @@ package concurrent { */ object Await { /** - * Await the "resolved" state of this Awaitable. - * Invokes ready() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`. - * - * @param awaitable - * the `Awaitable` on which `ready` is to be called - * @param atMost - * maximum wait time, which may be negative (no waiting is done), - * [[Duration.Inf]] for unbounded waiting, or a finite positive - * duration - * @return the awaitable itself - * @throws InterruptedException if the wait call was interrupted - * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready - * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]] + * Await the "completed" state of an `Awaitable`. + * + * Although this method is blocking, the internal use of [[scala.concurrent.blocking blocking]] ensures that + * the underlying [[ExecutionContext]] is prepared to properly manage the blocking. + * + * @param awaitable + * the `Awaitable` to be awaited + * @param atMost + * maximum wait time, which may be negative (no waiting is done), + * [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive + * duration + * @return the `awaitable` + * @throws InterruptedException if the current thread is interrupted while waiting + * @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready + * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]] */ @throws(classOf[TimeoutException]) @throws(classOf[InterruptedException]) @@ -87,19 +87,21 @@ package concurrent { blocking(awaitable.ready(atMost)(AwaitPermission)) /** - * Await and return the result of this Awaitable, which is either of type T or a thrown exception (any Throwable). - * Invokes result() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`. - * - * @param awaitable - * the `Awaitable` on which `result` is to be called - * @param atMost - * maximum wait time, which may be negative (no waiting is done), - * [[Duration.Inf]] for unbounded waiting, or a finite positive - * duration - * @return the value if the Awaitable was successful within the specific maximum wait time - * @throws InterruptedException if the wait call was interrupted - * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready - * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]] + * Await and return the result (of type `T`) of an `Awaitable`. + * + * Although this method is blocking, the internal use of [[scala.concurrent.blocking blocking]] ensures that + * the underlying [[ExecutionContext]] to properly detect blocking and ensure that there are no deadlocks. + * + * @param awaitable + * the `Awaitable` to be awaited + * @param atMost + * maximum wait time, which may be negative (no waiting is done), + * [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive + * duration + * @return the result value if `awaitable` is completed within the specific maximum wait time + * @throws InterruptedException if the current thread is interrupted while waiting + * @throws TimeoutException if after waiting for the specified time `awaitable` is still not ready + * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]] */ @throws(classOf[Exception]) def result[T](awaitable: Awaitable[T], atMost: Duration): T = -- cgit v1.2.3 From 68b798e3ec9ae9441d19bd06a040c869c494f159 Mon Sep 17 00:00:00 2001 From: Heather Miller Date: Wed, 10 Oct 2012 15:55:43 +0200 Subject: SI-6453 Documentation links for @switch are broken --- src/library/scala/annotation/switch.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/library/scala/annotation/switch.scala b/src/library/scala/annotation/switch.scala index a867783455..20056bc03c 100644 --- a/src/library/scala/annotation/switch.scala +++ b/src/library/scala/annotation/switch.scala @@ -9,8 +9,7 @@ package scala.annotation /** An annotation to be applied to a match expression. If present, * the compiler will verify that the match has been compiled to a - * [[http://docs.oracle.com/javase/specs/jvms/se5.0/html/Instructions2.doc14.html tableswitch]] - * or [[http://docs.oracle.com/javase/specs/jvms/se5.0/html/Instructions2.doc8.html#lookupswitch lookupswitch]] + * [[http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html#jvms-3.10 tableswitch or lookupswitch]] * and issue an error if it instead compiles into a series of conditional expressions. * Example usage: {{{ -- cgit v1.2.3 From ee7f1e8a82fcb81d5ff2b017daf52fc929ce9444 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 10 Oct 2012 10:57:14 -0700 Subject: Fix for SI-6499, regression in type inference. I can't do any better than a reproduced comment: For some reason which is still a bit fuzzy, we must let Nothing through as a lower bound despite the fact that Nothing is always a lower bound. My current supposition is that the side-effecting type constraint accumulation mechanism depends on these subtype tests being performed to make forward progress when there are mutally recursive type vars. See pos/t6367 and pos/t6499 for the competing test cases. --- src/reflect/scala/reflect/internal/Types.scala | 36 +++++++++++++++++++++----- test/files/pos/t6499.scala | 3 +++ 2 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 test/files/pos/t6499.scala diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 0e8665ee84..ab33c29153 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3922,7 +3922,17 @@ trait Types extends api.Types { self: SymbolTable => def avoidWiden: Boolean = avoidWidening def addLoBound(tp: Type, isNumericBound: Boolean = false) { - if (!lobounds.contains(tp)) { + // For some reason which is still a bit fuzzy, we must let Nothing through as + // a lower bound despite the fact that Nothing is always a lower bound. My current + // supposition is that the side-effecting type constraint accumulation mechanism + // depends on these subtype tests being performed to make forward progress when + // there are mutally recursive type vars. + // See pos/t6367 and pos/t6499 for the competing test cases. + val mustConsider = tp.typeSymbol match { + case NothingClass => true + case _ => !(lobounds contains tp) + } + if (mustConsider) { if (isNumericBound && isNumericValueType(tp)) { if (numlo == NoType || isNumericSubType(numlo, tp)) numlo = tp @@ -3942,7 +3952,13 @@ trait Types extends api.Types { self: SymbolTable => } def addHiBound(tp: Type, isNumericBound: Boolean = false) { - if (!hibounds.contains(tp)) { + // My current test case only demonstrates the need to let Nothing through as + // a lower bound, but I suspect the situation is symmetrical. + val mustConsider = tp.typeSymbol match { + case AnyClass => true + case _ => !(hibounds contains tp) + } + if (mustConsider) { checkWidening(tp) if (isNumericBound && isNumericValueType(tp)) { if (numhi == NoType || isNumericSubType(tp, numhi)) @@ -6316,21 +6332,26 @@ trait Types extends api.Types { self: SymbolTable => }) if (!cyclic) { if (up) { - if (bound.typeSymbol != AnyClass) + if (bound.typeSymbol != AnyClass) { + log(s"$tvar addHiBound $bound.instantiateTypeParams($tparams, $tvars)") tvar addHiBound bound.instantiateTypeParams(tparams, tvars) + } for (tparam2 <- tparams) tparam2.info.bounds.lo.dealias match { case TypeRef(_, `tparam`, _) => + log(s"$tvar addHiBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)") tvar addHiBound tparam2.tpeHK.instantiateTypeParams(tparams, tvars) case _ => } } else { if (bound.typeSymbol != NothingClass && bound.typeSymbol != tparam) { + log(s"$tvar addLoBound $bound.instantiateTypeParams($tparams, $tvars)") tvar addLoBound bound.instantiateTypeParams(tparams, tvars) } for (tparam2 <- tparams) tparam2.info.bounds.hi.dealias match { case TypeRef(_, `tparam`, _) => + log(s"$tvar addLoBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)") tvar addLoBound tparam2.tpeHK.instantiateTypeParams(tparams, tvars) case _ => } @@ -6339,14 +6360,15 @@ trait Types extends api.Types { self: SymbolTable => tvar.constr.inst = NoType // necessary because hibounds/lobounds may contain tvar //println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen))) - - tvar setInst ( + val newInst = ( if (up) { if (depth != AnyDepth) glb(tvar.constr.hiBounds, depth) else glb(tvar.constr.hiBounds) } else { if (depth != AnyDepth) lub(tvar.constr.loBounds, depth) else lub(tvar.constr.loBounds) - }) - + } + ) + log(s"$tvar setInst $newInst") + tvar setInst newInst //Console.println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen))+" = "+tvar.constr.inst)//@MDEBUG } } diff --git a/test/files/pos/t6499.scala b/test/files/pos/t6499.scala new file mode 100644 index 0000000000..db376572ee --- /dev/null +++ b/test/files/pos/t6499.scala @@ -0,0 +1,3 @@ +object Test { + Map(): Map[_, Int] with Map[_, Int] +} -- cgit v1.2.3 From c6df7ddd0657ace307eaf6d6bf436cbb24e93df4 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Mon, 8 Oct 2012 15:41:20 +0200 Subject: SI-6487 Scaladoc can link to inner classes --- src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala | 7 ++----- test/scaladoc/resources/links.scala | 11 ++++++++++- test/scaladoc/run/links.scala | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala index 7ab73cceff..09020ae24a 100644 --- a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala +++ b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala @@ -120,10 +120,7 @@ trait MemberLookup { private object OnlyTerm extends SearchStrategy private def lookupInRootPackage(pos: Position, members: List[String]) = - if (members.length == 1) - lookupInTemplate(pos, members, EmptyPackage) ::: lookupInTemplate(pos, members, RootPackage) - else - lookupInTemplate(pos, members, RootPackage) + lookupInTemplate(pos, members, EmptyPackage) ::: lookupInTemplate(pos, members, RootPackage) private def createLinks(syms: List[(Symbol, Symbol)]): List[LinkTo] = syms.flatMap { case (sym, owner) => @@ -153,7 +150,7 @@ trait MemberLookup { case tplName::rest => def completeSearch(syms: List[Symbol]) = - syms filter {sym => sym.isPackage || sym.isClass || sym.isModule} flatMap (lookupInTemplate(pos, rest, _)) + syms flatMap (lookupInTemplate(pos, rest, _)) completeSearch(lookupInTemplate(pos, tplName, container, OnlyTerm)) match { case Nil => completeSearch(lookupInTemplate(pos, tplName, container, OnlyType)) diff --git a/test/scaladoc/resources/links.scala b/test/scaladoc/resources/links.scala index 09a52a4334..0986b4ea90 100644 --- a/test/scaladoc/resources/links.scala +++ b/test/scaladoc/resources/links.scala @@ -3,6 +3,7 @@ // SI-4497 "Links in ScalaDoc - Spec and implementation unsufficient" // SI-4224 "Wiki-links should support method targets" // SI-3695 "support non-fully-qualified type links in scaladoc comments" +// SI-6487 "Scaladoc can't link to inner classes" package scala.test.scaladoc.links { import language.higherKinds class C @@ -54,9 +55,17 @@ package scala.test.scaladoc.links { * - [[localMethod object TEST -> localMethod]] (should use the current template to resolve link instead of inTpl, that's the package) * - [[#localMethod object TEST -> localMethod]] (should exercise Java-style links to empty members) * - [[ImOutside class ImOutside (check correct lookup in EmptyPackage)]] + * - [[ImOutside.Inner#foo class ImOutside#class Inner#method foo (check correct lookup in EmptyPackage)]] + * - [[ImOutside.T#foo class ImOutside#type T#method foo (check correct interaction between @template and links)]] */ object TEST { def localMethod = 3 } } -class ImOutside \ No newline at end of file +trait ImOutside { + /** @template */ + type T <: Inner + class Inner { + def foo: Any + } +} diff --git a/test/scaladoc/run/links.scala b/test/scaladoc/run/links.scala index de359539cf..0f3e749dea 100644 --- a/test/scaladoc/run/links.scala +++ b/test/scaladoc/run/links.scala @@ -22,7 +22,7 @@ object Test extends ScaladocModelTest { val memberLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToMember]) val templateLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToTpl]) - assert(memberLinks == 15, memberLinks + " == 15 (the member links in object TEST)") + assert(memberLinks == 17, memberLinks + " == 17 (the member links in object TEST)") assert(templateLinks == 5, templateLinks + " == 5 (the template links in object TEST)") } } \ No newline at end of file -- cgit v1.2.3 From 950687520907199e756680baed898c4d75cee1e8 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Tue, 9 Oct 2012 20:42:20 +0200 Subject: SI-6495 Scaladoc will pick up group from owner --- .../scala/tools/nsc/doc/model/ModelFactory.scala | 29 ++++--- test/scaladoc/run/groups.scala | 94 ++++++++++++---------- 2 files changed, 71 insertions(+), 52 deletions(-) diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 48624ec28f..3b1f0587a1 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -31,6 +31,12 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { import definitions.{ ObjectClass, NothingClass, AnyClass, AnyValClass, AnyRefClass } import rootMirror.{ RootPackage, RootClass, EmptyPackage } + // Defaults for member grouping, that may be overridden by the template + val defaultGroup = "Ungrouped" + val defaultGroupName = "Ungrouped" + val defaultGroupDesc = None + val defaultGroupPriority = 1000 + def templatesCount = docTemplatesCache.count(_._2.isDocTemplate) - droppedPackages.size private var _modelFinished = false @@ -121,7 +127,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { } if (inTpl != null) thisFactory.comment(sym, thisTpl, inTpl) else None } - def group = if (comment.isDefined) comment.get.group.getOrElse("No Group") else "No Group" + def group = if (comment.isDefined) comment.get.group.getOrElse(defaultGroup) else defaultGroup override def inTemplate = inTpl override def toRoot: List[MemberImpl] = this :: inTpl.toRoot def inDefinitionTemplates = this match { @@ -493,16 +499,21 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { if (entity != default) return entity } // query linearization - for (tpl <- linearizationTemplates.collect{ case dtpl: DocTemplateImpl if dtpl!=this => dtpl}) { - val entity = tpl.groupSearch(extractor, default) - if (entity != default) return entity - } - default + if (!sym.isPackage) + for (tpl <- linearizationTemplates.collect{ case dtpl: DocTemplateImpl if dtpl!=this => dtpl}) { + val entity = tpl.groupSearch(extractor, default) + if (entity != default) return entity + } + // query inTpl, going up the ownerChain + if (inTpl != null) + inTpl.groupSearch(extractor, default) + else + default } - def groupDescription(group: String): Option[Body] = groupSearch(_.groupDesc.get(group), None) - def groupPriority(group: String): Int = groupSearch(_.groupPrio.get(group) match { case Some(prio) => prio; case _ => 0 }, 0) - def groupName(group: String): String = groupSearch(_.groupNames.get(group) match { case Some(name) => name; case _ => group }, group) + def groupDescription(group: String): Option[Body] = groupSearch(_.groupDesc.get(group), if (group == defaultGroup) defaultGroupDesc else None) + def groupPriority(group: String): Int = groupSearch(_.groupPrio.get(group) match { case Some(prio) => prio; case _ => 0 }, if (group == defaultGroup) defaultGroupPriority else 0) + def groupName(group: String): String = groupSearch(_.groupNames.get(group) match { case Some(name) => name; case _ => group }, if (group == defaultGroup) defaultGroupName else group) } abstract class PackageImpl(sym: Symbol, inTpl: PackageImpl) extends DocTemplateImpl(sym, inTpl) with Package { diff --git a/test/scaladoc/run/groups.scala b/test/scaladoc/run/groups.scala index 05324c2ec9..c9e4a8679b 100644 --- a/test/scaladoc/run/groups.scala +++ b/test/scaladoc/run/groups.scala @@ -4,49 +4,54 @@ import scala.tools.partest.ScaladocModelTest object Test extends ScaladocModelTest { override def code = """ - package test.scaladoc.groups { - - /** - * The trait A - * @groupdesc A Group A is the group that contains functions starting with f - * For example: - * {{{ - * this is an example - * }}} - * @groupdesc B Group B is the group that contains functions starting with b - * @groupname B Group B has a nice new name and a high priority - * @groupprio B -10 - * @group Traits - * @note This is a note - */ - trait A { - /** foo description - * @group A */ - def foo = 1 - - /** bar description - * @group B */ - def bar = 2 - } - - /** The trait B - * @group Traits - * @groupdesc C Group C is introduced by B - */ - trait B { - /** baz descriptopn - * @group C */ - def baz = 3 - } - - /** The class C which inherits from both A and B - * @group Classes - * @groupdesc B Look ma, I'm overriding group descriptions!!! - * @groupname B And names - */ - class C extends A with B { - /** Oh noes, I lost my group -- or did I?!? */ - override def baz = 4 + package test.scaladoc { + + /** @groupname Z From owner chain */ + package object `groups` + + package groups { + /** + * The trait A + * @groupdesc A Group A is the group that contains functions starting with f + * For example: + * {{{ + * this is an example + * }}} + * @groupdesc B Group B is the group that contains functions starting with b + * @groupname B Group B has a nice new name and a high priority + * @groupprio B -10 + * @group Traits + * @note This is a note + */ + trait A { + /** foo description + * @group A */ + def foo = 1 + + /** bar description + * @group B */ + def bar = 2 + } + + /** The trait B + * @group Traits + * @groupdesc C Group C is introduced by B + */ + trait B { + /** baz descriptopn + * @group C */ + def baz = 3 + } + + /** The class C which inherits from both A and B + * @group Classes + * @groupdesc B Look ma, I'm overriding group descriptions!!! + * @groupname B And names + */ + class C extends A with B { + /** Oh noes, I lost my group -- or did I?!? */ + override def baz = 4 + } } } """ @@ -101,10 +106,12 @@ object Test extends ScaladocModelTest { checkGroupDesc(A, "B", "Group B is the group that contains functions starting with b") checkGroupName(A, "B", "Group B has a nice new name and a high priority") checkGroupPrio(A, "B", -10) + checkGroupName(A, "Z", "From owner chain") checkGroupDesc(B, "C", "Group C is introduced by B") checkGroupName(B, "C", "C") checkGroupPrio(B, "C", 0) + checkGroupName(B, "Z", "From owner chain") checkGroupDesc(C, "A", "Group A is the group that contains functions starting with f") checkGroupName(C, "A", "A") @@ -115,5 +122,6 @@ object Test extends ScaladocModelTest { checkGroupDesc(C, "C", "Group C is introduced by B") checkGroupName(C, "C", "C") checkGroupPrio(C, "C", 0) + checkGroupName(C, "Z", "From owner chain") } } \ No newline at end of file -- cgit v1.2.3 From e3a2d0bc4b1931aa311da0305d12ae7ec00d5e2d Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Wed, 10 Oct 2012 09:27:02 +0200 Subject: SI-6501 Scaladoc will correctly link to @templated members --- src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala | 13 +++++++------ test/scaladoc/resources/links.scala | 3 +++ test/scaladoc/run/links.scala | 5 ++++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala index 09020ae24a..1c783a7d2c 100644 --- a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala +++ b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala @@ -124,12 +124,13 @@ trait MemberLookup { private def createLinks(syms: List[(Symbol, Symbol)]): List[LinkTo] = syms.flatMap { case (sym, owner) => - if (sym.isClass || sym.isModule || sym.isTrait || sym.isPackage) - findTemplateMaybe(sym) map (LinkToTpl(_)) - else - findTemplateMaybe(owner) flatMap { inTpl => - inTpl.members find (_.asInstanceOf[EntityImpl].sym == sym) map (LinkToMember(_, inTpl)) - } + findTemplateMaybe(sym) match { + case Some(tpl) => LinkToTpl(tpl) :: Nil + case None => + findTemplateMaybe(owner) flatMap { inTpl => + inTpl.members find (_.asInstanceOf[EntityImpl].sym == sym) map (LinkToMember(_, inTpl)) + } + } } private def lookupInTemplate(pos: Position, members: List[String], container: Symbol): List[(Symbol, Symbol)] = { diff --git a/test/scaladoc/resources/links.scala b/test/scaladoc/resources/links.scala index 0986b4ea90..bd69665357 100644 --- a/test/scaladoc/resources/links.scala +++ b/test/scaladoc/resources/links.scala @@ -4,6 +4,8 @@ // SI-4224 "Wiki-links should support method targets" // SI-3695 "support non-fully-qualified type links in scaladoc comments" // SI-6487 "Scaladoc can't link to inner classes" +// SI-6495 "Scaladoc won't pick up group name, priority and description from owner chain" +// SI-6501 "Scaladoc won't link to a @template type T as a template but as a member" package scala.test.scaladoc.links { import language.higherKinds class C @@ -56,6 +58,7 @@ package scala.test.scaladoc.links { * - [[#localMethod object TEST -> localMethod]] (should exercise Java-style links to empty members) * - [[ImOutside class ImOutside (check correct lookup in EmptyPackage)]] * - [[ImOutside.Inner#foo class ImOutside#class Inner#method foo (check correct lookup in EmptyPackage)]] + * - [[ImOutside.T class ImOutside#type T (check correct linking to templates)]] * - [[ImOutside.T#foo class ImOutside#type T#method foo (check correct interaction between @template and links)]] */ object TEST { diff --git a/test/scaladoc/run/links.scala b/test/scaladoc/run/links.scala index 0f3e749dea..0c67857e1c 100644 --- a/test/scaladoc/run/links.scala +++ b/test/scaladoc/run/links.scala @@ -5,6 +5,9 @@ import scala.tools.partest.ScaladocModelTest // SI-4497 "Links in ScalaDoc - Spec and implementation unsufficient" // SI-4224 "Wiki-links should support method targets" // SI-3695 "support non-fully-qualified type links in scaladoc comments" +// SI-6487 "Scaladoc can't link to inner classes" +// SI-6495 "Scaladoc won't pick up group name, priority and description from owner chain" +// SI-6501 "Scaladoc won't link to a @template type T as a template but as a member" object Test extends ScaladocModelTest { override def resourceFile = "links.scala" @@ -23,6 +26,6 @@ object Test extends ScaladocModelTest { val memberLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToMember]) val templateLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToTpl]) assert(memberLinks == 17, memberLinks + " == 17 (the member links in object TEST)") - assert(templateLinks == 5, templateLinks + " == 5 (the template links in object TEST)") + assert(templateLinks == 6, templateLinks + " == 6 (the template links in object TEST)") } } \ No newline at end of file -- cgit v1.2.3 From 2280b8e3d5472be2df69bb0531486c25cf10edc4 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Thu, 11 Oct 2012 03:04:23 +0200 Subject: SI-6155 Scaladoc @template diagrms --- .../scala/tools/nsc/doc/model/ModelFactory.scala | 3 ++- test/scaladoc/resources/SI-6511.scala | 24 ++++++++++++++++++++++ test/scaladoc/run/SI-6511.check | 1 + test/scaladoc/run/SI-6511.scala | 22 ++++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 test/scaladoc/resources/SI-6511.scala create mode 100644 test/scaladoc/run/SI-6511.check create mode 100644 test/scaladoc/run/SI-6511.scala diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 3b1f0587a1..32e113bbb0 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -292,7 +292,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { val tps = (this match { case a: AliasType => sym.tpe.dealias.parents case a: AbstractType => sym.info.bounds match { - case TypeBounds(lo, hi) => List(hi) + case TypeBounds(lo, RefinedType(parents, decls)) => parents + case TypeBounds(lo, hi) => hi :: Nil case _ => Nil } case _ => sym.tpe.parents diff --git a/test/scaladoc/resources/SI-6511.scala b/test/scaladoc/resources/SI-6511.scala new file mode 100644 index 0000000000..1f153caeb0 --- /dev/null +++ b/test/scaladoc/resources/SI-6511.scala @@ -0,0 +1,24 @@ +package test.scaladoc.template.diagrams + +/** @contentDiagram hideNodes "*Api" */ +trait X { + /** @template */ + type Symbol >: Null <: SymbolApi + + /** @template */ + type TypeSymbol >: Null <: Symbol with TypeSymbolApi + + /** @template */ + type TermSymbol >: Null <: Symbol with TermSymbolApi + + /** @template */ + type MethodSymbol >: Null <: TermSymbol with MethodSymbolApi + + trait SymbolApi { this: Symbol => def x: Int} + trait TermSymbolApi extends SymbolApi { this: TermSymbol => def y: Int} + trait TypeSymbolApi extends SymbolApi { this: TypeSymbol => def z: Int} + trait MethodSymbolApi extends TermSymbolApi { this: MethodSymbol => def t: Int } +} + +/** @contentDiagram hideNodes "*Api" */ +trait Y extends X diff --git a/test/scaladoc/run/SI-6511.check b/test/scaladoc/run/SI-6511.check new file mode 100644 index 0000000000..3925a0d464 --- /dev/null +++ b/test/scaladoc/run/SI-6511.check @@ -0,0 +1 @@ +Done. \ No newline at end of file diff --git a/test/scaladoc/run/SI-6511.scala b/test/scaladoc/run/SI-6511.scala new file mode 100644 index 0000000000..cc950a98d6 --- /dev/null +++ b/test/scaladoc/run/SI-6511.scala @@ -0,0 +1,22 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + + override def resourceFile: String = "SI-6511.scala" + + // no need for special settings + def scaladocSettings = "-diagrams" + + def testModel(rootPackage: Package) = { + // get the quick access implicit defs in scope (_package(s), _class(es), _trait(s), object(s) _method(s), _value(s)) + import access._ + + val main = rootPackage._package("test")._package("scaladoc")._package("template")._package("diagrams") + val X = main._trait("X") + val Y = main._trait("Y") + + testDiagram(X, X.contentDiagram, nodes = 4, edges = 3) + testDiagram(Y, Y.contentDiagram, nodes = 4, edges = 3) + } +} \ No newline at end of file -- cgit v1.2.3 From 2edf78f3a05112961ed6ad56452e9b5dc150fc3c Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Thu, 11 Oct 2012 03:16:17 +0200 Subject: SI-6509 Correct @template owners --- src/compiler/scala/tools/nsc/doc/DocFactory.scala | 2 +- .../scala/tools/nsc/doc/model/ModelFactory.scala | 9 ++++--- test/scaladoc/resources/SI-6509.scala | 24 +++++++++++++++++ test/scaladoc/run/SI-6509.check | 1 + test/scaladoc/run/SI-6509.scala | 30 ++++++++++++++++++++++ 5 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 test/scaladoc/resources/SI-6509.scala create mode 100644 test/scaladoc/run/SI-6509.check create mode 100644 test/scaladoc/run/SI-6509.scala diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala index cd0c242f22..02b69034ef 100644 --- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala @@ -86,7 +86,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor with model.comment.CommentFactory with model.TreeFactory with model.MemberLookup { - override def templateShouldDocument(sym: compiler.Symbol, inTpl: TemplateImpl) = + override def templateShouldDocument(sym: compiler.Symbol, inTpl: DocTemplateImpl) = extraTemplatesToDocument(sym) || super.templateShouldDocument(sym, inTpl) } ) diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 32e113bbb0..73b4341e95 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -748,7 +748,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { } else { // no class inheritance at this point - assert(inOriginalOwner(bSym, inTpl) || bSym.isAbstractType || bSym.isAliasType, bSym + " in " + inTpl) + assert(inOriginalOwner(bSym, inTpl), bSym + " in " + inTpl) Some(createDocTemplate(bSym, inTpl)) } } @@ -845,7 +845,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { Some(new MemberTemplateImpl(bSym, inTpl) with AliasImpl with AliasType { override def isAliasType = true }) - else if (!modelFinished && (bSym.isPackage || bSym.isAliasType || bSym.isAbstractType || templateShouldDocument(bSym, inTpl))) + else if (!modelFinished && (bSym.isPackage || templateShouldDocument(bSym, inTpl))) modelCreation.createTemplate(bSym, inTpl) else None @@ -1052,8 +1052,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def inOriginalOwner(aSym: Symbol, inTpl: TemplateImpl): Boolean = normalizeTemplate(aSym.owner) == normalizeTemplate(inTpl.sym) - def templateShouldDocument(aSym: Symbol, inTpl: TemplateImpl): Boolean = - (aSym.isTrait || aSym.isClass || aSym.isModule) && + def templateShouldDocument(aSym: Symbol, inTpl: DocTemplateImpl): Boolean = + (aSym.isTrait || aSym.isClass || aSym.isModule || typeShouldDocument(aSym, inTpl)) && localShouldDocument(aSym) && !isEmptyJavaObject(aSym) && // either it's inside the original owner or we can document it later: @@ -1093,6 +1093,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { // whether or not to create a page for an {abstract,alias} type def typeShouldDocument(bSym: Symbol, inTpl: DocTemplateImpl) = (settings.docExpandAllTypes.value && (bSym.sourceFile != null)) || + (bSym.isAliasType || bSym.isAbstractType) && { val rawComment = global.expandedDocComment(bSym, inTpl.sym) rawComment.contains("@template") || rawComment.contains("@documentable") } diff --git a/test/scaladoc/resources/SI-6509.scala b/test/scaladoc/resources/SI-6509.scala new file mode 100644 index 0000000000..540ba243bd --- /dev/null +++ b/test/scaladoc/resources/SI-6509.scala @@ -0,0 +1,24 @@ +package test.scaladoc.template.owners + +trait X { + /** @template */ + type Symbol >: Null <: SymbolApi + + /** @template */ + type TypeSymbol >: Null <: Symbol with TypeSymbolApi + + /** @template */ + type TermSymbol >: Null <: Symbol with TermSymbolApi + + /** @template */ + type MethodSymbol >: Null <: TermSymbol with MethodSymbolApi + + trait SymbolApi { this: Symbol => def x: Int} + trait TermSymbolApi extends SymbolApi { this: TermSymbol => def y: Int} + trait TypeSymbolApi extends SymbolApi { this: TypeSymbol => def z: Int} + trait MethodSymbolApi extends TermSymbolApi { this: MethodSymbol => def t: Int } +} + +trait Y extends X +trait Z extends Y +trait T extends Z diff --git a/test/scaladoc/run/SI-6509.check b/test/scaladoc/run/SI-6509.check new file mode 100644 index 0000000000..3925a0d464 --- /dev/null +++ b/test/scaladoc/run/SI-6509.check @@ -0,0 +1 @@ +Done. \ No newline at end of file diff --git a/test/scaladoc/run/SI-6509.scala b/test/scaladoc/run/SI-6509.scala new file mode 100644 index 0000000000..3857949d14 --- /dev/null +++ b/test/scaladoc/run/SI-6509.scala @@ -0,0 +1,30 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + + override def resourceFile: String = "SI-6509.scala" + + // no need for special settings + def scaladocSettings = "" + + def testModel(rootPackage: Package) = { + // get the quick access implicit defs in scope (_package(s), _class(es), _trait(s), object(s) _method(s), _value(s)) + import access._ + + val main = rootPackage._package("test")._package("scaladoc")._package("template")._package("owners") + val X = main._trait("X") + val Y = main._trait("Y") + val Z = main._trait("Z") + val T = main._trait("T") + + def checkTemplateOwner(d: DocTemplateEntity) = + for (mbr <- List("Symbol", "TypeSymbol", "TermSymbol", "MethodSymbol")) { + val tpl = d._absTypeTpl(mbr).inTemplate + assert(tpl == X, tpl + " == X") + } + + for (tpl <- List(X, Y, Z, T)) + checkTemplateOwner(tpl) + } +} \ No newline at end of file -- cgit v1.2.3 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(-) 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 From 92dc8f81130b26475b0540a2226c340caac4c9ac Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Mon, 8 Oct 2012 17:44:27 +0200 Subject: reflection docs improvements and moves to doc page --- .../scala/reflect/macros/runtime/Typers.scala | 3 + src/reflect/scala/reflect/api/JavaMirrors.scala | 8 +- src/reflect/scala/reflect/api/Names.scala | 35 ++-- src/reflect/scala/reflect/api/Positions.scala | 5 +- src/reflect/scala/reflect/api/package.scala | 206 +-------------------- 5 files changed, 23 insertions(+), 234 deletions(-) diff --git a/src/compiler/scala/reflect/macros/runtime/Typers.scala b/src/compiler/scala/reflect/macros/runtime/Typers.scala index be70181126..f9add91b9a 100644 --- a/src/compiler/scala/reflect/macros/runtime/Typers.scala +++ b/src/compiler/scala/reflect/macros/runtime/Typers.scala @@ -8,6 +8,9 @@ trait Typers { def openImplicits: List[(Type, Tree)] = callsiteTyper.context.openImplicits + /** + * @see [[scala.tools.reflect.Toolbox.typeCheck]] + */ def typeCheck(tree: Tree, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = { macroLogVerbose("typechecking %s with expected type %s, implicit views = %s, macros = %s".format(tree, pt, !withImplicitViewsDisabled, !withMacrosDisabled)) val context = callsiteTyper.context diff --git a/src/reflect/scala/reflect/api/JavaMirrors.scala b/src/reflect/scala/reflect/api/JavaMirrors.scala index e1219b2dde..e51047a7fe 100644 --- a/src/reflect/scala/reflect/api/JavaMirrors.scala +++ b/src/reflect/scala/reflect/api/JavaMirrors.scala @@ -3,11 +3,9 @@ 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. + * This refinement equips mirrors with reflection capabilities for the JVM. `JavaMirror` can + * convert Scala reflection artifacts (symbols and types) into Java reflection artifacts (classes) + * and vice versa. It can also perform reflective invocations (getting/settings field values, calling methods, etc). */ trait JavaMirrors { self: JavaUniverse => diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index c1de49a475..dccdd6868b 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -1,33 +1,20 @@ package scala.reflect package api -/** 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. - * - * 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. - * +/** This trait defines Names (a Scala reflection concept) and operations on them. + * + * Names are simple wrappers for strings. [[scala.reflect.api.Names#Name Name]] has two subtypes [[scala.reflect.api.Names#TermName TermName]] and [[scala.reflect.api.Names#TypeName TypeName]] which + * distinguish names of terms (like objects or members) and types. A term and a type of the + * same name can co-exist in an object. + * + * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]]. + * === 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. + * To search for the `map` method (which is a term) declared in the `List` class, + * use `typeOf[List[_]].member(newTermName("map"))`. To search for a type member, use + * newTypeName instead. * - * 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 { /** An implicit conversion from String to TermName. diff --git a/src/reflect/scala/reflect/api/Positions.scala b/src/reflect/scala/reflect/api/Positions.scala index a47dc00f3d..bbb1fe45c4 100644 --- a/src/reflect/scala/reflect/api/Positions.scala +++ b/src/reflect/scala/reflect/api/Positions.scala @@ -1,10 +1,9 @@ package scala.reflect package api -/** 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. +/** This trait defines the concept of positions and operations on them. * - * The main documentation entry about positions is located at [[scala.reflect.api.Position]]. + * @see [[scala.reflect.api.Position]] */ trait Positions { self: Universe => diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala index d3eef59228..a11a269523 100644 --- a/src/reflect/scala/reflect/api/package.scala +++ b/src/reflect/scala/reflect/api/package.scala @@ -2,211 +2,13 @@ package scala.reflect import scala.reflect.api.{Universe => ApiUniverse} -/** The Scala reflection API. +/** The Scala reflection API (located at scala-reflect.jar). * - * === 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 === + * Using Scala reflection requires understanding of a couple of basic concepts like Symbols, Types, Mirror and Universes. + * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]]. * * 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?]] + * in binary- and source-incompatible manner in 2.10.1. This also means that the implementation has known issues */ package object api { -- cgit v1.2.3 From 0c619f18ec275c25af65f4c7bdba4b73cb60855d Mon Sep 17 00:00:00 2001 From: ingoem Date: Mon, 8 Oct 2012 18:38:37 +0200 Subject: Rearranged some reflection docs, moving things to the guide --- src/reflect/scala/reflect/api/Annotations.scala | 97 ++------- src/reflect/scala/reflect/api/Exprs.scala | 27 +-- src/reflect/scala/reflect/api/Importers.scala | 23 +-- src/reflect/scala/reflect/api/JavaUniverse.scala | 2 +- src/reflect/scala/reflect/api/Mirror.scala | 15 +- src/reflect/scala/reflect/api/Mirrors.scala | 6 +- src/reflect/scala/reflect/api/Scopes.scala | 7 +- src/reflect/scala/reflect/api/Symbols.scala | 11 +- src/reflect/scala/reflect/api/TagInterop.scala | 2 +- src/reflect/scala/reflect/api/Types.scala | 80 ++----- 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 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] - * }}} + * 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 -- cgit v1.2.3 From 69693d90ac043feb1bff7adb26db0b2fd73a0640 Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Mon, 8 Oct 2012 19:14:52 +0200 Subject: simplified reflection docs for trees --- src/reflect/scala/reflect/api/Trees.scala | 244 ++++-------------------------- 1 file changed, 28 insertions(+), 216 deletions(-) diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 9d574adf69..03d62c3bb9 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -5,222 +5,28 @@ package scala.reflect package api -/** 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. +/** This trait defines the node types used in Scala abstract syntax trees (AST) and operations on them. + * + * All tree node types are sub types of [[scala.reflect.api#Tree Tree]]. + * + * Trees are immutable, except for three fields + * [[Trees#TreeApi.pos pos]], [[Trees#TreeApi.symbol symbol]], and [[Trees#TreeApi.tpe tpe]], which are assigned when a tree is typechecked + * to attribute it with the information gathered by the typechecker. + * + * [[scala.reflect.api.Universe#reify reify]] can be used to get the tree for a given Scala expression. + * + * [[scala.reflect.api.Universe#showRaw showRaw]] can be used to get a readable representation of a tree. * - * 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`. + * === Examples === + * `Literal(Constant(5))` creates an AST representing a literal 5 in Scala source code. + * + * `Apply(Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("print")), List(Literal(Constant("Hello World"))))` + * creates an AST representing `print("Hello World")`. + * + * `import scala.reflect.runtime.universe.{reify,showRaw}` + * `print( showRaw( reify{5}.tree ) )` // prints Literal(Constant(5)) * - * 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(()))) - * }}} + * @see [[http://docs.scala-lang.org/overviews/reflection/symbols-trees-types.html#trees]]. */ trait Trees { self: Universe => @@ -260,6 +66,11 @@ trait Trees { self: Universe => * * Upon creation most trees have their `tpe` set to `null`. * Types are typically assigned to trees during typechecking. + * Some node factory methods set `tpe` immediately after creation. + * + * When the typechecker encounters a tree with a non-null tpe, + * it will assume it to be correct and not check it again. This means one has + * to be careful not to erase the `tpe` field of subtrees. */ def tpe: Type @@ -1725,7 +1536,7 @@ trait Trees { self: Universe => val qual: TypeName } - /** Designator . */ + /** A member selection . */ type Select >: Null <: RefTree with SelectApi /** A tag that preserves the identity of the `Select` abstract type from erasure. @@ -1755,7 +1566,8 @@ trait Trees { self: Universe => val name: Name } - /** Identifier */ + /** A reference to identifier `name`. + */ type Ident >: Null <: RefTree with IdentApi /** A tag that preserves the identity of the `Ident` abstract type from erasure. -- cgit v1.2.3 From b9e3d94604e20791317d9c7b1aa939e0bff6c945 Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Mon, 8 Oct 2012 19:34:45 +0200 Subject: removed docs for internal TypeCreator and TreeCreator --- src/reflect/scala/reflect/api/TreeCreator.scala | 20 ++------------------ src/reflect/scala/reflect/api/TypeCreator.scala | 22 +++------------------- 2 files changed, 5 insertions(+), 37 deletions(-) diff --git a/src/reflect/scala/reflect/api/TreeCreator.scala b/src/reflect/scala/reflect/api/TreeCreator.scala index a8e8ae1b58..c668fe0b4d 100644 --- a/src/reflect/scala/reflect/api/TreeCreator.scala +++ b/src/reflect/scala/reflect/api/TreeCreator.scala @@ -1,25 +1,9 @@ package scala.reflect package api -/** A mirror-aware factory for trees. +/** This is an internal implementation class. * - * In the reflection API, artifacts are specific to universes and - * symbolic references used in artifacts (e.g. `scala.Int`) are resolved by mirrors. - * - * Therefore to build a tree one needs to know a universe that the tree is going to be bound to - * and a mirror that is going to resolve symbolic references (e.g. to determine that `scala.Int` - * points to a core class `Int` from scala-library.jar). - * - * `TreeCreator` implements this notion by providing a standalone tree factory. - * - * This is immediately useful for reification. When the compiler reifies an expression, - * the end result needs to make sense in any mirror. That's because the compiler knows - * the universe it's reifying an expression into (specified by the target of the `reify` call), - * but it cannot know in advance the mirror to instantiate the result in (e.g. on JVM - * it doesn't know what classloader use to resolve symbolic names in the reifee). - * - * Due to a typechecker restriction (no eta-expansion for dependent method types), - * `TreeCreator` can't have a functional type, so it's implemented as class with an apply method. + * @see [[http://docs.scala-lang.org/overviews/reflection/architecture.html]]. */ abstract class TreeCreator { def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Tree diff --git a/src/reflect/scala/reflect/api/TypeCreator.scala b/src/reflect/scala/reflect/api/TypeCreator.scala index 2b3ef4320b..16585cd23f 100644 --- a/src/reflect/scala/reflect/api/TypeCreator.scala +++ b/src/reflect/scala/reflect/api/TypeCreator.scala @@ -1,25 +1,9 @@ package scala.reflect package api -/** A mirror-aware factory for types. - * - * In the reflection API, artifacts are specific to universes and - * symbolic references used in artifacts (e.g. `scala.Int`) are resolved by mirrors. - * - * Therefore to build a type one needs to know a universe that the type is going to be bound to - * and a mirror that is going to resolve symbolic references (e.g. to determine that `scala.Int` - * points to a core class `Int` from scala-library.jar). - * - * `TypeCreator` implements this notion by providing a standalone type factory. - * - * This is immediately useful for type tags. When the compiler creates a type tag, - * the end result needs to make sense in any mirror. That's because the compiler knows - * the universe it's creating a type tag for (since `TypeTag` is path-dependent on a universe), - * but it cannot know in advance the mirror to instantiate the result in (e.g. on JVM - * it doesn't know what classloader use to resolve symbolic names in the type tag). - * - * Due to a typechecker restriction (no eta-expansion for dependent method types), - * `TypeCreator` can't have a functional type, so it's implemented as class with an apply method. +/** This is an internal implementation class. + * + * @see [[http://docs.scala-lang.org/overviews/reflection/architecture.html]]. */ abstract class TypeCreator { def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type -- cgit v1.2.3 From e8525254314627bd145d2093f0a1a0f3ca6a8067 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Wed, 10 Oct 2012 09:59:12 +0200 Subject: scala.reflect.api.Constants documentation --- src/reflect/scala/reflect/api/Constants.scala | 193 +++++++++++++++----------- src/reflect/scala/reflect/api/package.scala | 13 ++ 2 files changed, 124 insertions(+), 82 deletions(-) diff --git a/src/reflect/scala/reflect/api/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala index 1f303877de..8c532bd4dd 100644 --- a/src/reflect/scala/reflect/api/Constants.scala +++ b/src/reflect/scala/reflect/api/Constants.scala @@ -6,114 +6,143 @@ package scala.reflect package api -/** 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. - * - * 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 - * } - * }}} +/** + * This trait is the [[scala.reflect.api.Universe reflection API]] component that mirrors constant irreducible expressions + * such as `true`, `0` and `classOf[List]`. Constant values appear in the program abstract syntax tree and in annotation parameters + * wrapped in [[Constant `Constant`]] case classes. */ trait Constants { self: Universe => - /** The type of compile-time constants. + /** + * This "virtual" case class represents the reflection interface for literal expressions which can not be further + * broken down or evaluated, such as "true", "0", "classOf[List]". Such values become parts of the Scala abstract + * syntax tree representing the program. The constants + * correspond to section 6.24 "Constant Expressions" of the + * [[http://www.scala-lang.org/docu/files/ScalaReference.pdf Scala language specification]]. + * + * 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). + * + * Constants can be matched against and can be constructed directly, as if they were case classes: + * {{{ + * assert(Constant(true).value == true) + * Constant(true) match { + * case Constant(s: String) => println("A string: " + s) + * case Constant(b: Boolean) => println("A boolean value: " + b) + * case Constant(x) => println("Something else: " + x) + * } + * }}} + * + * `Constant` instances can wrap certain kinds of these expressions: + * 1. Literals of primitive value classes ([[scala.Byte `Byte`]], [[scala.Short `Short`]], [[scala.Int `Int`]], [[scala.Long `Long`]], [[scala.Float `Float`]], [[scala.Double `Double`]], [[scala.Char `Char`]], [[scala.Boolean `Boolean`]] and [[scala.Unit `Unit`]]) - represented directly as the corresponding type + * 1. String literals - represented as instances of the `String`. + * 1. References to classes, typically constructed with [[scala.Predef#classOf]] - represented as [[scala.reflect.api.Types#Type types]]. + * 1. References to enumeration values - represented as [[scala.reflect.api.Symbols#Symbol symbols]]. + * + * 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 [[scala.reflect.api.Mirrors#RuntimeMirror#runtimeClass `runtimeClass`]] method of a + * mirror such as [[scala.reflect.api.Mirrors#RuntimeMirror `RuntimeMirror`]] (the simplest way to get such a mirror is using + * [[scala.reflect.runtime#currentMirror `scala.reflect.runtime.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]]). + * + * Usage example: + * {{{ + * 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)) match { + * // Constant is always wrapped into a Literal or LiteralArgument tree node + * case LiteralArgument(ct: Constant) => value + * case _ => sys.error("Not a constant") + * } + * + * val classRef = jarg("classRef").value.asInstanceOf[Type] + * // ideally one should match instead of casting + * println(showRaw(classRef)) // TypeRef(ThisType(), JavaAnnottee, List()) + * println(cm.runtimeClass(classRef)) // class JavaAnnottee + * + * val enumRef = jarg("enumRef").value.asInstanceOf[Symbol] + * // ideally one should match instead of casting + * 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 + * } + * }}} + * @template + * @group Constants */ type Constant >: Null <: AnyRef with ConstantApi /** A tag that preserves the identity of the `Constant` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ConstantTag: ClassTag[Constant] - /** The constructor/deconstructor for `Constant` instances. */ + /** The constructor/deconstructor for `Constant` instances. + * @group Extractors + */ val Constant: ConstantExtractor /** An extractor class to create and pattern match with syntax `Constant(value)` * where `value` is the Scala value of the constant. + * @group Extractors */ abstract class ConstantExtractor { + /** A factory method that produces [[Constant `Constant`]] instances. + * + * Notice that not any value can be passed to a constant: it must be either a primitive, a `String`, a + * [[scala.reflect.api.Types#Type type]] or a [[scala.reflect.api.Symbols#Symbol symbol]]. + * See [[Constant the `Constant` class]] for more information. + */ def apply(value: Any): Constant + /** An extractor that enables writing pattern matches against the [[Constant `Constant`]] class. */ 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. + /** The API of [[Constant]] instances. + * @group API */ abstract class ConstantApi { - /** Payload of the constant. */ + /** Payload of the constant, that can be accessed directly or pattern matched against. */ val value: Any - /** Scala type that describes the constant. */ + /** Scala type that describes the constant. It is generated automatically based on the type of the value. */ def tpe: Type } } diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala index a11a269523..ba098cb3d5 100644 --- a/src/reflect/scala/reflect/api/package.scala +++ b/src/reflect/scala/reflect/api/package.scala @@ -9,6 +9,19 @@ import scala.reflect.api.{Universe => ApiUniverse} * * 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 + * + * @groupprio API 9 + * @groupprio Extractors 10 + * @groupprio Tags 11 + * @groupdesc API The methods available for each reflection entity, without the implementation. Since the + * reflection entities are abstract types that are later overridden, their API counterparts + * guarantee a minimum set of methods implemented in both runtime reflection and macros. + * @groupdesc Extractors Extractors provide the machinery necessary to allow pattern matching and construction of + * reflection entities that is similar to case classes, although the entities are only abstract + * types that are later overridden. + * @groupdesc Tags Implicit values that provide [[scala.reflect.ClassTag `ClassTags`]] for the reflection + * classes. These are abstract in the interface but are later filled in to provide ClassTags + * for the either the runtime reflection or macros entities, depending on the use. */ package object api { -- cgit v1.2.3 From f96f4bf36db31c2783ead455697b6e6e8256f810 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Wed, 10 Oct 2012 11:45:01 +0200 Subject: scala.reflect.api.StandardNames documentation --- src/reflect/scala/reflect/api/StandardNames.scala | 34 ++++++++++++++++------- src/reflect/scala/reflect/api/Universe.scala | 2 ++ src/reflect/scala/reflect/api/package.scala | 2 +- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/reflect/scala/reflect/api/StandardNames.scala b/src/reflect/scala/reflect/api/StandardNames.scala index 8029450ca0..203bcdbdc4 100644 --- a/src/reflect/scala/reflect/api/StandardNames.scala +++ b/src/reflect/scala/reflect/api/StandardNames.scala @@ -10,24 +10,34 @@ 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. -/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines standard names. +/** This trait is the [[scala.reflect.api.Universe reflection API]] component that defines standard [[Names names used in reflection and macros]]. * * 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]]) + * These standard names can be referred to using [[nme `nme`]] for term names and [[tpnme `tpnme`]] for type names + * + * @see [[Names]] + * + * The API for names in Scala reflection. + * @groupname StandardNames Standard Names */ trait StandardNames { self: Universe => - /** A value containing all standard term names. */ + /** A value containing all [[TermNamesApi standard term names]]. + * @group StandardNames + */ val nme: TermNamesApi - /** A value containing all standard type names. */ + /** A value containing all [[TypeNamesApi standard type names]]. + * @group StandardNames + */ val tpnme: TypeNamesApi - /** Defines standard names, common for term and type names. */ + /** Defines standard names, common for term and type names: These can be accessed via the [[nme]] and [[tpnme]] members. + * @group API + */ trait NamesApi { /** An abstract type that represents the exact flavor of the name. */ type NameType >: Null <: Name @@ -39,8 +49,8 @@ trait StandardNames { /** 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. + * for `privateWithin` in [[Trees#Modifiers]], for [[Trees#This]], + * for [[Trees#Super]], etc. */ val EMPTY: NameType @@ -55,7 +65,9 @@ trait StandardNames { val PACKAGE: NameType } - /** Defines standard term names. */ + /** Defines standard term names that can be accessed via the [[nme]] member. + * @group API + */ trait TermNamesApi extends NamesApi { /** @inheritdoc */ type NameType = TermName @@ -78,7 +90,9 @@ trait StandardNames { val LOCAL_SUFFIX_STRING: String } - /** Defines standard type names. */ + /** Defines standard type names that can be accessed via the [[tpnme]] member. + * @group API + */ trait TypeNamesApi extends NamesApi { /** @inheritdoc */ type NameType = TypeName diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index 207dc98a91..5bc5a7359b 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -70,6 +70,8 @@ package api * 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`. + * + * @groupprio default 5 */ abstract class Universe extends Symbols with Types diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala index ba098cb3d5..db78a20fb5 100644 --- a/src/reflect/scala/reflect/api/package.scala +++ b/src/reflect/scala/reflect/api/package.scala @@ -4,7 +4,7 @@ import scala.reflect.api.{Universe => ApiUniverse} /** The Scala reflection API (located at scala-reflect.jar). * - * Using Scala reflection requires understanding of a couple of basic concepts like Symbols, Types, Mirror and Universes. + * Using Scala reflection requires understanding of a couple of basic concepts like [[Symbols Symbols]], [[Types Types]], [[Mirror Mirrors]] and [[Universe Universes]]. * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]]. * * 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 -- cgit v1.2.3 From a6d61e2ef8e62b802af606da34002e9b9e9e9b31 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Wed, 10 Oct 2012 13:21:28 +0200 Subject: scala.reflect.api.Position documentation --- src/reflect/scala/reflect/api/Position.scala | 105 ++++++++++++--------------- src/reflect/scala/reflect/api/Universe.scala | 2 - src/reflect/scala/reflect/api/package.scala | 4 +- 3 files changed, 50 insertions(+), 61 deletions(-) diff --git a/src/reflect/scala/reflect/api/Position.scala b/src/reflect/scala/reflect/api/Position.scala index 9a6c166845..d94df00875 100644 --- a/src/reflect/scala/reflect/api/Position.scala +++ b/src/reflect/scala/reflect/api/Position.scala @@ -3,55 +3,21 @@ package api import scala.reflect.macros.Attachments -/** Position instances represent positions of ASTs and symbols. +/** Position tracks the origin of [[Symbols#Symbol symbols]] and [[Trees#Tree tree nodes]]. They are commonly used when + * displaying warnings and errors, to indicate the incorrect point in the program. * - * === Position in runtime reflection === + * A position indicates the [[source source file]] and an [[point offset]]. A position may be + * undefined, which means it's pointing to the [[Positions#NoPosition]] element. * - * Except for [[scala.reflect.api.Positions#NoPosition], every position refers to a source file (`source`) - * and to an offset in the sourcefile (its `point`). + * Please note that this trait may be refactored in future versions of the Scala reflection API. * - * === Positions in compile-time reflection === + * @see [[http://docs.scala-lang.org/overviews/reflection/names-exprs-scopes-more.html]] * - * 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. + * The compiler adds more information to positions, such a ranges in the source file and defines different types of + * positions depending on how a symbol or tree node was generated. The guide fully describes compiler-generated positions. * - * - 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, - * `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)`. - * 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). - * - * 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. + * @groupname Common Commonly used methods + * @groupname default Compiler-specific methods */ trait Position extends Attachments { @@ -63,11 +29,14 @@ trait Position extends Attachments { * The return type is [[scala.reflect.io.AbstractFile]], which belongs to an experimental part of Scala reflection. * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined * and exposed as a part of scala.reflect.api. + * + * @group Common */ def source: scala.reflect.internal.util.SourceFile /** Is this position neither a NoPosition nor a FakePosition? * If isDefined is true, offset and source are both defined. + * @group Common */ def isDefined: Boolean @@ -78,36 +47,46 @@ trait Position extends Attachments { def isTransparent: Boolean /** Is this position a non-transparent range position? */ - def isOpaqueRange: Boolean + def isOpaqueRange: Boolean - /** if opaque range, make this position transparent */ + /** If opaque range, make this position transparent. */ def makeTransparent: Pos - /** The start of the position's range, error if not a range position */ + /** The start of the position's range, error if not a range position. */ def start: Int - /** The start of the position's range, or point if not a range position */ + /** The start of the position's range, or point if not a range position. */ def startOrPoint: Int - /** The point (where the ^ is) of the position */ + /** The point (where the ^ is) of the position, which is easiest to access using the [[line]] and [[column]] values. + * The [[lineContent line content]] is also available. + * @group Common + */ def point: Int - /** The point (where the ^ is) of the position, or else `default` if undefined */ + /** The point (where the ^ is) of the position, or else `default` if undefined. + * @group Common + */ def pointOrElse(default: Int): Int - /** The end of the position's range, error if not a range position */ + /** The end of the position's range, error if not a range position. + */ def end: Int - /** The end of the position's range, or point if not a range position */ + /** The end of the position's range, or point if not a range position. + */ def endOrPoint: Int - /** The same position with a different start value (if a range) */ + /** The same position with a different start value (if a range). + */ def withStart(off: Int): Pos - /** The same position with a different end value (if a range) */ + /** The same position with a different end value (if a range). + */ def withEnd(off: Int): Pos - /** The same position with a different point value (if a range or offset) */ + /** The same position with a different point value (if a range or offset). + */ def withPoint(off: Int): Pos /** If this is a range, the union with the other range, with the point of this position. @@ -130,7 +109,7 @@ trait Position extends Attachments { */ def focusEnd: Pos - /** Does this position include the given position `pos`. + /** Does this position include the given position `pos`? * This holds if `this` is a range position and its range [start..end] * is the same or covers the range of the given position, which may or may not be a range position. */ @@ -163,14 +142,26 @@ trait Position extends Attachments { */ def sameRange(pos: Pos): Boolean + /** The position indicates a [[column `column`]] and the `line` in the source file. + * @group Common + */ def line: Int + /** The position indicates a `column` and the [[line `line`]] in the source file. + * @group Common + */ def column: Int - /** Convert this to a position around `point` that spans a single source line */ + /** Convert this to a position around `point` that spans a single source line + */ def toSingleLine: Pos + /** The content of the line this Position refers to. + * @group Common + */ def lineContent: String + /** Show a textual representation of the position. + */ def show: String } diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index 5bc5a7359b..207dc98a91 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -70,8 +70,6 @@ package api * 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`. - * - * @groupprio default 5 */ abstract class Universe extends Symbols with Types diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala index db78a20fb5..449b7d5ce1 100644 --- a/src/reflect/scala/reflect/api/package.scala +++ b/src/reflect/scala/reflect/api/package.scala @@ -14,8 +14,8 @@ import scala.reflect.api.{Universe => ApiUniverse} * @groupprio Extractors 10 * @groupprio Tags 11 * @groupdesc API The methods available for each reflection entity, without the implementation. Since the - * reflection entities are abstract types that are later overridden, their API counterparts - * guarantee a minimum set of methods implemented in both runtime reflection and macros. + * reflection entities are later overridden by runtime reflection and macros, their API + * counterparts guarantee a minimum set of methods that are implemented. * @groupdesc Extractors Extractors provide the machinery necessary to allow pattern matching and construction of * reflection entities that is similar to case classes, although the entities are only abstract * types that are later overridden. -- cgit v1.2.3 From f73b7fed37c12e09a278bf0913ed8a01503d5b5d Mon Sep 17 00:00:00 2001 From: ingoem Date: Tue, 9 Oct 2012 19:21:17 +0200 Subject: Symbols docs cleanup, mostly moved to guide --- src/reflect/scala/reflect/api/Symbols.scala | 230 ++++------------------------ 1 file changed, 32 insertions(+), 198 deletions(-) diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index 063e12f49c..edb81695f7 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -3,205 +3,19 @@ package api /** 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 are used to establish bindings between a name and the entity it refers to, such as a class or a method. + * Anything you define and can give a name to in Scala has a symbol. * - * === Symbols from a compile-time perspective === + * Certain types of tree nodes, such as [[scala.reflect.api.Trees#Ident Ident]] (references to identifiers) and + * [[scala.reflect.api.Trees#Select Select]] (references to members) expose method [[Trees.SymTreeApi.symbol]] + * to obtain the symbol that represents their declaration. * - * 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. + * See the [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for more details and + * intricacies about symbols. * - * 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?]]. + * @define SYM_ACCESSORS Class [[Symbol]] defines `isXXX` test methods such as `isPublic` or `isFinal`, `params` and + * `returnType` methods for method symbols, `baseClasses` for class symbols and so on. Some of these methods don't + * make sense for certain subclasses of `Symbol` and return `NoSymbol`, `Nil` or other empty values. */ trait Symbols { self: Universe => @@ -278,6 +92,8 @@ trait Symbols { self: Universe => /** The API of symbols. * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * + * $SYM_ACCESSORS */ trait SymbolApi { this: Symbol => @@ -430,8 +246,12 @@ trait Symbols { self: Universe => def typeSignatureIn(site: Type): Type /** The type signature of this symbol. - * Note if the symbol is a member of a class, one almost always is interested - * in `typeSignatureIn` with a site type instead. + * + * This 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`. */ def typeSignature: Type @@ -579,6 +399,8 @@ trait Symbols { self: Universe => /** The API of term symbols. * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * + * $SYM_ACCESSORS */ trait TermSymbolApi extends SymbolApi { this: TermSymbol => /** Term symbols have their names of type `TermName`. @@ -662,6 +484,8 @@ trait Symbols { self: Universe => /** The API of type symbols. * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * + * $SYM_ACCESSORS */ trait TypeSymbolApi extends SymbolApi { this: TypeSymbol => /** Type symbols have their names of type `TypeName`. @@ -729,6 +553,8 @@ trait Symbols { self: Universe => /** The API of method symbols. * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * + * $SYM_ACCESSORS */ trait MethodSymbolApi extends TermSymbolApi { this: MethodSymbol => final override def isMethod = true @@ -766,6 +592,8 @@ trait Symbols { self: Universe => /** The API of module symbols. * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * + * $SYM_ACCESSORS */ trait ModuleSymbolApi extends TermSymbolApi { this: ModuleSymbol => /** The class implicitly associated with the object definition. @@ -781,6 +609,8 @@ trait Symbols { self: Universe => /** The API of class symbols. * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * + * $SYM_ACCESSORS */ trait ClassSymbolApi extends TypeSymbolApi { this: ClassSymbol => final override def isClass = true @@ -849,6 +679,8 @@ trait Symbols { self: Universe => /** The API of free term symbols. * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * + * $SYM_ACCESSORS */ trait FreeTermSymbolApi extends TermSymbolApi { this: FreeTermSymbol => final override def isFreeTerm = true @@ -863,6 +695,8 @@ trait Symbols { self: Universe => /** The API of free type symbols. * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * + * $SYM_ACCESSORS */ trait FreeTypeSymbolApi extends TypeSymbolApi { this: FreeTypeSymbol => final override def isFreeType = true -- cgit v1.2.3 From ad75e88936c0da7e883da449ca986f3c19acfb68 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Wed, 10 Oct 2012 15:03:14 +0200 Subject: scala.reflect.api.Symbols documentation Oh those pretty groups, u gotta luv'em... --- src/reflect/scala/reflect/api/Symbols.scala | 380 ++++++++++++++++++++++++---- 1 file changed, 330 insertions(+), 50 deletions(-) diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index edb81695f7..05d2ea40cf 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -4,96 +4,158 @@ package api /** This trait defines symbols and operations on them. * * Symbols are used to establish bindings between a name and the entity it refers to, such as a class or a method. - * Anything you define and can give a name to in Scala has a symbol. + * Anything you define and can give a name to in Scala has an associated symbol. * - * Certain types of tree nodes, such as [[scala.reflect.api.Trees#Ident Ident]] (references to identifiers) and - * [[scala.reflect.api.Trees#Select Select]] (references to members) expose method [[Trees.SymTreeApi.symbol]] - * to obtain the symbol that represents their declaration. + * Certain types of tree nodes, such as [[Trees#Ident Ident]] (references to identifiers) and + * [[Trees#Select Select]] (references to members) expose method [[Trees.SymTreeApi.symbol `symbol`]] + * to obtain the symbol that represents their declaration. During the typechecking phase, the compiler looks up the + * symbol based on the name and scope and sets the [[Trees.SymTreeApi.symbol `symbol` field]] of tree nodes. * - * See the [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for more details and - * intricacies about symbols. + * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]] * - * @define SYM_ACCESSORS Class [[Symbol]] defines `isXXX` test methods such as `isPublic` or `isFinal`, `params` and - * `returnType` methods for method symbols, `baseClasses` for class symbols and so on. Some of these methods don't - * make sense for certain subclasses of `Symbol` and return `NoSymbol`, `Nil` or other empty values. + * The Reflection Guide provides more details on symbol usage and attached intricacies. + * + * @define SYMACCESSORS Class [[Symbol]] defines `isXXX` test methods such as `isPublic` or `isFinal`, `params` and + * `returnType` methods for method symbols, `baseClasses` for class symbols and so on. Some of these methods don't + * make sense for certain subclasses of `Symbol` and return `NoSymbol`, `Nil` or other empty values. */ trait Symbols { self: Universe => - /** The type of symbols representing declarations */ + /** The type of symbols representing declarations. + * @group Symbols + * @template + */ type Symbol >: Null <: SymbolApi /** A tag that preserves the identity of the `Symbol` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val SymbolTag: ClassTag[Symbol] /** The type of type symbols representing type, class, and trait declarations, - * as well as type parameters + * as well as type parameters. + * @group Symbols + * @template */ type TypeSymbol >: Null <: Symbol with TypeSymbolApi /** A tag that preserves the identity of the `TypeSymbol` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TypeSymbolTag: ClassTag[TypeSymbol] /** The type of term symbols representing val, var, def, and object declarations as * well as packages and value parameters. + * @group Symbols + * @template */ type TermSymbol >: Null <: Symbol with TermSymbolApi /** A tag that preserves the identity of the `TermSymbol` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TermSymbolTag: ClassTag[TermSymbol] - /** The type of method symbols representing def declarations */ + /** The type of method symbols representing def declarations. + * @group Symbols + * @template + */ type MethodSymbol >: Null <: TermSymbol with MethodSymbolApi /** A tag that preserves the identity of the `MethodSymbol` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val MethodSymbolTag: ClassTag[MethodSymbol] - /** The type of module symbols representing object declarations */ + /** The type of module symbols representing object declarations. + * @group Symbols + * @template + */ type ModuleSymbol >: Null <: TermSymbol with ModuleSymbolApi /** A tag that preserves the identity of the `ModuleSymbol` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ModuleSymbolTag: ClassTag[ModuleSymbol] - /** The type of class symbols representing class and trait definitions */ + /** The type of class symbols representing class and trait definitions. + * @group Symbols + * @template + */ type ClassSymbol >: Null <: TypeSymbol with ClassSymbolApi /** A tag that preserves the identity of the `ClassSymbol` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ClassSymbolTag: ClassTag[ClassSymbol] - /** The type of free terms introduced by reification */ + /** The type of free terms introduced by reification. + * @group Symbols + * @template + */ type FreeTermSymbol >: Null <: TermSymbol with FreeTermSymbolApi /** A tag that preserves the identity of the `FreeTermSymbol` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val FreeTermSymbolTag: ClassTag[FreeTermSymbol] - /** The type of free types introduced by reification */ + /** The type of free types introduced by reification. + * @group Symbols + * @template + */ type FreeTypeSymbol >: Null <: TypeSymbol with FreeTypeSymbolApi /** A tag that preserves the identity of the `FreeTypeSymbol` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val FreeTypeSymbolTag: ClassTag[FreeTypeSymbol] - /** A special "missing" symbol */ + /** A special "missing" symbol. Commonly used in the API to denote a default or empty value. + * @group Symbols + * @template + */ val NoSymbol: Symbol /** The API of symbols. - * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. - * - * $SYM_ACCESSORS + * The main source of information about symbols is the [[Symbols]] page. + * + * $SYMACCESSORS + * @group API + * @groupname Basics Symbol Basic Information + * @groupprio Basics 0 + * @groupname Tests Symbol Type Tests + * @groupprio Tests 1 + * @groupname Conversions Symbol Conversions + * @groupprio Conversions 2 + * @groupname Constructors New Symbol Constructors + * @groupprio Constructors 3 + * @groupdesc Constructors These methods construct new symbols owned by the current symbol. + * @groupname Helpers Iteration Helpers + * @groupprio Helpers 4 + * @groupdesc Helpers These methods enable collections-like operations on symbols. + * @groupname Type TypeSymbol Members + * @groupprio Type -1 + * @groupname FreeType FreeType Symbol Members + * @groupprio FreeType -2 + * @groupname Term TermSymbol Members + * @groupprio Term -1 + * @groupname FreeTerm FreeType Symbol Members + * @groupprio FreeTerm -2 + * @groupname Class Class Symbol Members + * @groupprio Class -2 + * @groupname Method Method Symbol Members + * @groupprio Method -2 + * @groupname Module Module Symbol Members + * @groupprio Module -2 */ trait SymbolApi { this: Symbol => @@ -105,6 +167,8 @@ trait Symbols { self: Universe => * and the Scala root object [[scala.reflect.api.Mirror.RootPackage]] is `NoSymbol`. * Every other symbol has a chain of owners that ends in * [[scala.reflect.api.Mirror.RootClass]]. + * + * @group Basics */ def owner: Symbol @@ -113,15 +177,18 @@ trait Symbols { self: Universe => * * Type name namespaces do not intersect with term name namespaces. * This fact is reflected in different types for names of `TermSymbol` and `TypeSymbol`. + * @group Basics */ type NameType >: Null <: Name /** The name of the symbol as a member of the `Name` type. + * @group Basics */ def name: Name /** The encoded full path name of this symbol, where outer names and inner names * are separated by periods. + * @group Basics */ def fullName: String @@ -129,11 +196,15 @@ trait Symbols { self: Universe => * Note that every symbol is either a term or a type. * So for every symbol `sym` (except for `NoSymbol`), * either `sym.isTerm` is true or `sym.isType` is true. + * + * @group Tests */ def isType: Boolean = false /** This symbol cast to a TypeSymbol. * @throws ScalaReflectionException if `isType` is false. + * + * @group Conversions */ def asType: TypeSymbol = throw new ScalaReflectionException(s"$this is not a type") @@ -141,21 +212,29 @@ trait Symbols { self: Universe => * Note that every symbol is either a term or a type. * So for every symbol `sym` (except for `NoSymbol`), * either `sym.isTerm` is true or `sym.isTerm` is true. + * + * @group Tests */ def isTerm: Boolean = false /** This symbol cast to a TermSymbol. * @throws ScalaReflectionException if `isTerm` is false. + * + * @group Conversions */ def asTerm: TermSymbol = throw new ScalaReflectionException(s"$this is not a term") /** Does this symbol represent the definition of a method? * If yes, `isTerm` is also guaranteed to be true. + * + * @group Tests */ def isMethod: Boolean = false /** This symbol cast to a MethodSymbol. * @throws ScalaReflectionException if `isMethod` is false. + * + * @group Conversions */ def asMethod: MethodSymbol = { def overloadedMsg = @@ -166,60 +245,86 @@ trait Symbols { self: Universe => throw new ScalaReflectionException(s"$this $msg") } - /** Used to provide a better error message for `asMethod` */ + /** Used to provide a better error message for `asMethod` + * + * @group Tests + */ protected def isOverloadedMethod = false /** Does this symbol represent the definition of a module (i.e. it * results from an object definition?). * If yes, `isTerm` is also guaranteed to be true. + * + * @group Tests */ def isModule: Boolean = false /** This symbol cast to a ModuleSymbol defined by an object definition. * @throws ScalaReflectionException if `isModule` is false. + * + * @group Conversions */ def asModule: ModuleSymbol = throw new ScalaReflectionException(s"$this is not a module") /** Does this symbol represent the definition of a class or trait? * If yes, `isType` is also guaranteed to be true. + * + * @group Tests */ def isClass: Boolean = false /** Does this symbol represent the definition of a class implicitly associated * with an object definition (module class in scala compiler parlance). * If yes, `isType` is also guaranteed to be true. + * + * @group Tests */ def isModuleClass: Boolean = false /** This symbol cast to a ClassSymbol representing a class or trait. * @throws ScalaReflectionException if `isClass` is false. + * + * @group Conversions */ def asClass: ClassSymbol = throw new ScalaReflectionException(s"$this is not a class") /** Does this symbol represent a free term captured by reification? * If yes, `isTerm` is also guaranteed to be true. + * + * @group Tests */ def isFreeTerm: Boolean = false /** This symbol cast to a free term symbol. * @throws ScalaReflectionException if `isFreeTerm` is false. + * + * @group Conversions */ def asFreeTerm: FreeTermSymbol = throw new ScalaReflectionException(s"$this is not a free term") /** Does this symbol represent a free type captured by reification? * If yes, `isType` is also guaranteed to be true. + * + * @group Tests */ def isFreeType: Boolean = false /** This symbol cast to a free type symbol. * @throws ScalaReflectionException if `isFreeType` is false. + * + * @group Conversions */ def asFreeType: FreeTypeSymbol = throw new ScalaReflectionException(s"$this is not a free type") + /** @group Constructors */ def newTermSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TermSymbol + /** @group Constructors */ def newModuleAndClassSymbol(name: Name, pos: Position = NoPosition, flags: FlagSet = NoFlags): (ModuleSymbol, ClassSymbol) + /** @group Constructors */ def newMethodSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): MethodSymbol + /** @group Constructors */ def newTypeSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TypeSymbol + /** @group Constructors */ def newClassSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): ClassSymbol /** Source file if this symbol is created during this compilation run, @@ -228,34 +333,47 @@ trait Symbols { self: Universe => * The return type is [[scala.reflect.io.AbstractFile]], which belongs to an experimental part of Scala reflection. * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined * and exposed as a part of scala.reflect.api. + * + * @group Basics */ def associatedFile: scala.reflect.io.AbstractFile /** A list of annotations attached to this Symbol. + * + * @group Basics */ def annotations: List[Annotation] /** For a class: the module or case class factory with the same name in the same package. * For a module: the class with the same name in the same package. * For all others: NoSymbol + * + * @group Basics */ def companionSymbol: Symbol /** The type signature of this symbol seen as a member of given type `site`. + * + * @group Basics */ def typeSignatureIn(site: Type): Type /** The type signature of this symbol. * - * This method always returns signatures in the most generic way possible, even if the underlying symbol is obtained from an + * This 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`. + * + * @group Basics */ def typeSignature: Type - /** Returns all symbols overriden by this symbol. */ + /** Returns all symbols overriden by this symbol. + * + * @group Basics + */ def allOverriddenSymbols: List[Symbol] /******************* tests *******************/ @@ -263,11 +381,15 @@ trait Symbols { self: Universe => /** Does this symbol represent a synthetic (i.e. a compiler-generated) entity? * Examples of synthetic entities are accessors for vals and vars * or mixin constructors in trait implementation classes. + * + * @group Tests */ def isSynthetic: Boolean /** Does this symbol represent an implementation artifact that isn't meant for public use? - * Examples of such artifacts are erasure bridges and $outer fields. + * Examples of such artifacts are erasure bridges and outer fields. + * + * @group Tests */ def isImplementationArtifact: Boolean @@ -277,20 +399,28 @@ trait Symbols { self: Universe => * Local symbols can only be accessed from the same object instance. * * If yes, `privateWithin` might tell more about this symbol's visibility scope. + * + * @group Tests */ def isLocal: Boolean /** Does this symbol represent a private declaration or definition? * If yes, `privateWithin` might tell more about this symbol's visibility scope. + * + * @group Tests */ def isPrivate: Boolean /** Does this symbol represent a protected declaration or definition? * If yes, `privateWithin` might tell more about this symbol's visibility scope. + * + * @group Tests */ def isProtected: Boolean /** Does this symbol represent a public declaration or definition? + * + * @group Tests */ def isPublic: Boolean @@ -318,20 +448,28 @@ trait Symbols { self: Universe => * java package: !isPrivate && !isProtected && (privateWithin == enclosingPackage) * java protected: isProtected && (privateWithin == enclosingPackage) * java public: !isPrivate && !isProtected && (privateWithin == NoSymbol) + * + * @group Tests */ def privateWithin: Symbol /** Does this symbol represent the definition of a package? * If yes, `isTerm` is also guaranteed to be true. + * + * @group Tests */ def isPackage: Boolean /** Does this symbol represent a package class? * If yes, `isClass` is also guaranteed to be true. + * + * @group Tests */ def isPackageClass: Boolean /** Does this symbol or its underlying type represent a typechecking error? + * + * @group Tests */ def isErroneous : Boolean @@ -339,44 +477,64 @@ trait Symbols { self: Universe => * Q: When exactly is a sym marked as STATIC? * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep. * http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6 + * + * @group Tests */ def isStatic: Boolean /** Is this symbol final? + * + * @group Tests */ def isFinal: Boolean /** Is this symbol overriding something? + * + * @group Tests */ def isOverride: Boolean /** Is this symbol labelled as "abstract override"? + * + * @group Tests */ def isAbstractOverride: Boolean /** Is this symbol a macro? + * + * @group Tests */ def isMacro: Boolean /** Is this symbol a parameter (either a method parameter or a type parameter)? + * + * @group Tests */ def isParameter: Boolean /** Is this symbol a specialized type parameter or a generated specialized member? + * + * @group Tests */ def isSpecialized: Boolean /** Is this symbol defined by Java? + * + * @group Tests */ def isJava: Boolean /** Does this symbol represent an implicit value, definition, class or parameter? + * + * @group Tests */ def isImplicit: Boolean /******************* helpers *******************/ /** Provides an alternate if symbol is a NoSymbol. + * + * @group Helpers */ def orElse(alt: => Symbol): Symbol @@ -384,23 +542,30 @@ trait Symbols { self: Universe => * 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. + * + * @group Helpers */ def filter(cond: Symbol => Boolean): Symbol /** If this is a NoSymbol, returns NoSymbol, otherwise * returns the result of applying `f` to this symbol. + * + * @group Helpers */ def map(f: Symbol => Symbol): Symbol /** Does the same as `filter`, but crashes if there are multiple matches. + * + * @group Helpers */ def suchThat(cond: Symbol => Boolean): Symbol } /** The API of term symbols. - * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * The main source of information about symbols is the [[Symbols]] page. * - * $SYM_ACCESSORS + * $SYMACCESSORS + * @group API */ trait TermSymbolApi extends SymbolApi { this: TermSymbol => /** Term symbols have their names of type `TermName`. @@ -411,81 +576,116 @@ trait Symbols { self: Universe => final override def asTerm = this /** Is this symbol introduced as `val`? + * + * @group Term */ def isVal: Boolean - /** Does this symbol denote a stable value? */ + /** Does this symbol denote a stable value? + * + * @group Term + */ def isStable: Boolean /** Is this symbol introduced as `var`? + * + * @group Term */ def isVar: Boolean /** Does this symbol represent a getter or a setter? + * + * @group Term */ def isAccessor: Boolean /** Does this symbol represent a getter of a field? * If yes, `isMethod` is also guaranteed to be true. + * + * @group Term */ def isGetter: Boolean /** Does this symbol represent a setter of a field? * If yes, `isMethod` is also guaranteed to be true. + * + * @group Term */ def isSetter: Boolean /** Does this symbol represent an overloaded method? * If yes, `isMethod` is false, and the list of the enclosed alternatives can be found out via `alternatives`. + * + * @group Term */ def isOverloaded : Boolean /** Does this symbol represent a lazy value? + * + * @group Term */ def isLazy: Boolean - /** The overloaded alternatives of this symbol */ + /** The overloaded alternatives of this symbol + * + * @group Term + */ def alternatives: List[Symbol] /** Used to provide a better error message for `asMethod` */ override protected def isOverloadedMethod = alternatives exists (_.isMethod) /** Backing field for an accessor method, NoSymbol for all other term symbols. + * + * @group Term */ def accessed: Symbol /** Getter method for a backing field of a val or a val, NoSymbol for all other term symbols. + * + * @group Term */ def getter: Symbol /** Setter method for a backing field of a val or a val, NoSymbol for all other term symbols. + * + * @group Term */ def setter: Symbol /** Does this symbol represent a field of a class * that was generated from a parameter of that class? + * + * @group Term */ def isParamAccessor: Boolean /** Does this symbol represent a field of a case class * that corresponds to a parameter in the first parameter list of the * primary constructor of that class? + * + * @group Term */ def isCaseAccessor: Boolean /** Does this symbol represent a parameter with a default value? + * + * @group Term */ def isParamWithDefault: Boolean /** Does this symbol represent a by-name parameter? + * + * @group Term */ def isByNameParam: Boolean } /** The API of type symbols. - * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * The main source of information about symbols is the [[Symbols]] page. * - * $SYM_ACCESSORS + * $SYMACCESSORS + * @group API */ trait TypeSymbolApi extends SymbolApi { this: TypeSymbol => /** Type symbols have their names of type `TypeName`. @@ -498,11 +698,15 @@ trait Symbols { self: Universe => * * Example: Given a class declaration `class C[T] { ... } `, that generates a symbol * `C`. Then `C.toType` is the type `C[T]`, but `C.toTypeConstructor` is `C`. + * + * @group Type */ def toTypeConstructor: Type /** A type reference that refers to this type symbol seen * as a member of given type `site`. + * + * @group Type */ def toTypeIn(site: Type): Type @@ -516,45 +720,63 @@ trait Symbols { self: Universe => * By contrast, `C.typeSignature` would be a type signature of form * `PolyType(ClassInfoType(...))` that describes type parameters, value * parameters, parent types, and members of `C`. - */ + * + * @group Type + */ def toType: Type final override def isType = true final override def asType = this /** Is the type parameter represented by this symbol contravariant? + * + * @group Type */ def isContravariant : Boolean /** Is the type parameter represented by this symbol contravariant? + * + * @group Type */ def isCovariant : Boolean /** Does this symbol represent the definition of a skolem? * Skolems are used during typechecking to represent type parameters viewed from inside their scopes. + * + * @group Type */ def isSkolem : Boolean /** Does this symbol represent the definition of a type alias? + * + * @group Type */ def isAliasType : Boolean /** Does this symbol represent the definition of an abstract type? + * + * @group Type */ def isAbstractType : Boolean /** Does this symbol represent an existentially bound type? + * + * @group Type */ def isExistential : Boolean - /** For a polymorphic type, its type parameters, the empty list for all other types */ + /** For a polymorphic type, its type parameters, the empty list for all other types + * + * @group Type + */ def typeParams: List[Symbol] } /** The API of method symbols. - * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * The main source of information about symbols is the [[Symbols]] page. * - * $SYM_ACCESSORS + * $SYMACCESSORS + * @group API */ trait MethodSymbolApi extends TermSymbolApi { this: MethodSymbol => final override def isMethod = true @@ -564,13 +786,21 @@ trait Symbols { self: Universe => * * If `owner` is a class, then this is a vanilla JVM constructor. * If `owner` is a trait, then this is a mixin constructor. + * + * @group Method */ def isConstructor: Boolean - /** Does this symbol denote the primary constructor of its enclosing class? */ + /** Does this symbol denote the primary constructor of its enclosing class? + * + * @group Method + */ def isPrimaryConstructor: Boolean - /** For a polymorphic method, its type parameters, the empty list for all other methods */ + /** For a polymorphic method, its type parameters, the empty list for all other methods + * + * @group Method + */ def typeParams: List[Symbol] /** All parameter lists of the method. @@ -579,26 +809,36 @@ trait Symbols { self: Universe => * Can be used to distinguish nullary methods and methods with empty parameter lists. * For a nullary method, returns the empty list (i.e. `List()`). * For a method with an empty parameter list, returns a list that contains the empty list (i.e. `List(List())`). + * + * @group Method */ def paramss: List[List[Symbol]] /** Does this method support variable length argument lists? + * + * @group Method */ def isVarargs: Boolean - /** The return type of the method */ + /** The return type of the method + * + * @group Method + */ def returnType: Type } /** The API of module symbols. - * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * The main source of information about symbols is the [[Symbols]] page. * - * $SYM_ACCESSORS + * $SYMACCESSORS + * @group API */ 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 * by inspecting its `selfType.termSymbol`. + * + * @group Module */ def moduleClass: Symbol // needed for tree traversals // when this becomes `moduleClass: ClassSymbol`, it will be the happiest day in my life @@ -608,9 +848,10 @@ trait Symbols { self: Universe => } /** The API of class symbols. - * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * The main source of information about symbols is the [[Symbols]] page. * - * $SYM_ACCESSORS + * $SYMACCESSORS + * @group API */ trait ClassSymbolApi extends TypeSymbolApi { this: ClassSymbol => final override def isClass = true @@ -619,90 +860,129 @@ trait Symbols { self: Universe => /** Does this symbol represent the definition of a primitive class? * Namely, is it one of [[scala.Double]], [[scala.Float]], [[scala.Long]], [[scala.Int]], [[scala.Char]], * [[scala.Short]], [[scala.Byte]], [[scala.Unit]] or [[scala.Boolean]]? + * + * @group Class */ def isPrimitive: Boolean /** Does this symbol represent the definition of a numeric value class? * Namely, is it one of [[scala.Double]], [[scala.Float]], [[scala.Long]], [[scala.Int]], [[scala.Char]], * [[scala.Short]], [[scala.Byte]], [[scala.Unit]] or [[scala.Boolean]]? + * + * @group Class */ def isNumeric: Boolean /** Does this symbol represent the definition of a custom value class? * Namely, is AnyVal among its parent classes? + * + * @group Class */ def isDerivedValueClass: Boolean /** Does this symbol represent a trait? + * + * @group Class */ def isTrait: Boolean /** Does this symbol represent an abstract class? + * + * @group Class */ def isAbstractClass: Boolean /** Does this symbol represent a case class? + * + * @group Class */ def isCaseClass: Boolean /** Does this symbol represent a sealed class? + * + * @group Class */ def isSealed: Boolean /** If this is a sealed class, its known direct subclasses. * Otherwise, the empty set. + * + * @group Class */ def knownDirectSubclasses: Set[Symbol] /** The list of all base classes of this type (including its own typeSymbol) * in reverse linearization order, starting with the class itself and ending * in class Any. + * + * @group Class */ def baseClasses: List[Symbol] /** The module corresponding to this module class, * or NoSymbol if this symbol is not a module class. + * + * @group Class */ def module: Symbol /** If this symbol is a class or trait, its self type, otherwise the type * of the symbol itself. + * + * @group Class */ def selfType: Type - /** The type `C.this`, where `C` is the current class */ + /** The type `C.this`, where `C` is the current class + * + * @group Class + */ def thisPrefix: Type - /** For a polymorphic class/trait, its type parameters, the empty list for all other classes/trait */ + /** For a polymorphic class/trait, its type parameters, the empty list for all other classes/trait + * + * @group Class + */ def typeParams: List[Symbol] } /** The API of free term symbols. - * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * The main source of information about symbols is the [[Symbols]] page. * - * $SYM_ACCESSORS + * $SYMACCESSORS + * @group API */ trait FreeTermSymbolApi extends TermSymbolApi { this: FreeTermSymbol => final override def isFreeTerm = true final override def asFreeTerm = this - /** The place where this symbol has been spawned */ + /** The place where this symbol has been spawned + * + * @group FreeTerm + */ def origin: String - /** The valus this symbol refers to */ + /** The valus this symbol refers to + * + * @group FreeTerm + */ def value: Any } /** The API of free type symbols. - * The main source of information about symbols is the [[scala.reflect.api.Symbols]] page. + * The main source of information about symbols is the [[Symbols]] page. * - * $SYM_ACCESSORS + * $SYMACCESSORS + * @group API */ trait FreeTypeSymbolApi extends TypeSymbolApi { this: FreeTypeSymbol => final override def isFreeType = true final override def asFreeType = this - /** The place where this symbol has been spawned */ + /** The place where this symbol has been spawned + * + * @group FreeType + */ def origin: String } } -- cgit v1.2.3 From 7f7abfd62e08d569c7b88ec663a9955aa6fa272e Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 10 Oct 2012 18:24:11 +0200 Subject: fixes a typo --- src/reflect/scala/reflect/api/Symbols.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index 05d2ea40cf..c69d2e1fc2 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -148,7 +148,7 @@ trait Symbols { self: Universe => * @groupprio FreeType -2 * @groupname Term TermSymbol Members * @groupprio Term -1 - * @groupname FreeTerm FreeType Symbol Members + * @groupname FreeTerm FreeTerm Symbol Members * @groupprio FreeTerm -2 * @groupname Class Class Symbol Members * @groupprio Class -2 -- cgit v1.2.3 From 706091cadbfd3d3d89df4acc68ea910679005ec8 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Wed, 10 Oct 2012 21:29:20 +0200 Subject: Grouping for reflection and macros and warning cleanup --- src/reflect/scala/reflect/api/Annotations.scala | 74 +- src/reflect/scala/reflect/api/BuildUtils.scala | 3 + src/reflect/scala/reflect/api/Exprs.scala | 6 +- src/reflect/scala/reflect/api/FlagSets.scala | 20 +- src/reflect/scala/reflect/api/Importers.scala | 19 +- src/reflect/scala/reflect/api/JavaMirrors.scala | 11 +- src/reflect/scala/reflect/api/JavaUniverse.scala | 5 +- src/reflect/scala/reflect/api/Mirror.scala | 27 +- src/reflect/scala/reflect/api/Mirrors.scala | 18 +- src/reflect/scala/reflect/api/Names.scala | 31 +- src/reflect/scala/reflect/api/Positions.scala | 9 +- src/reflect/scala/reflect/api/Printers.scala | 16 +- src/reflect/scala/reflect/api/Scopes.scala | 24 +- .../scala/reflect/api/StandardDefinitions.scala | 12 +- src/reflect/scala/reflect/api/TagInterop.scala | 2 + src/reflect/scala/reflect/api/Trees.scala | 758 +++++++++++++++++---- src/reflect/scala/reflect/api/TypeTags.scala | 17 +- src/reflect/scala/reflect/api/Types.scala | 192 +++++- src/reflect/scala/reflect/api/Universe.scala | 8 +- src/reflect/scala/reflect/macros/Context.scala | 2 +- src/reflect/scala/reflect/macros/Evals.scala | 2 +- src/reflect/scala/reflect/macros/Parsers.scala | 2 +- src/reflect/scala/reflect/macros/Universe.scala | 37 +- src/reflect/scala/reflect/macros/package.scala | 2 +- 24 files changed, 1046 insertions(+), 251 deletions(-) diff --git a/src/reflect/scala/reflect/api/Annotations.scala b/src/reflect/scala/reflect/api/Annotations.scala index 10d1e5df7a..a828b254fe 100644 --- a/src/reflect/scala/reflect/api/Annotations.scala +++ b/src/reflect/scala/reflect/api/Annotations.scala @@ -3,45 +3,50 @@ package api import scala.collection.immutable.ListMap -/** This trait provides annotation support for the reflection API. +/** This trait provides annotation support for the reflection API. * * 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. - * 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 + * 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. + * 1. ''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 + * 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: + * [[scala.reflect.api.Annotations#JavaArgument]]. Instances of `JavaArgument` represent different kinds of Java annotation arguments: * - literals (primitive and string constants), - * - arrays and + * - arrays and * - nested annotations. */ trait Annotations { self: Universe => - /** Information about an annotation. */ + /** Information about an annotation. + * @template + * @group Annotations + */ type Annotation >: Null <: AnyRef with AnnotationApi /** A tag that preserves the identity of the `Annotation` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val AnnotationTag: ClassTag[Annotation] - /** The constructor/deconstructor for `Annotation` instances. */ + /** The constructor/deconstructor for `Annotation` instances. + * @group Extractors + */ val Annotation: AnnotationExtractor /** 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. - */ + * @group Extractors + */ 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])] @@ -49,6 +54,7 @@ trait Annotations { self: Universe => /** The API of `Annotation` instances. * The main source of information about annotations is the [[scala.reflect.api.Annotations]] page. + * @group API */ trait AnnotationApi { /** The type of the annotation. */ @@ -65,27 +71,38 @@ trait Annotations { self: Universe => def javaArgs: ListMap[Name, JavaArgument] } - /** A Java annotation argument */ + /** A Java annotation argument + * @template + * @group Annotations + */ 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. + * @group Tags */ implicit val JavaArgumentTag: ClassTag[JavaArgument] - /** A literal argument to a Java annotation as `"Use X instead"` in `@Deprecated("Use X instead")`*/ + /** A literal argument to a Java annotation as `"Use X instead"` in `@Deprecated("Use X instead")` + * @template + * @group Annotations + */ type LiteralArgument >: Null <: AnyRef with JavaArgument with LiteralArgumentApi /** A tag that preserves the identity of the `LiteralArgument` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val LiteralArgumentTag: ClassTag[LiteralArgument] - /** The constructor/deconstructor for `LiteralArgument` instances. */ + /** The constructor/deconstructor for `LiteralArgument` instances. + * @group Extractors + */ val LiteralArgument: LiteralArgumentExtractor /** An extractor class to create and pattern match with syntax `LiteralArgument(value)` * where `value` is the constant argument. + * @group Extractors */ abstract class LiteralArgumentExtractor { def apply(value: Constant): LiteralArgument @@ -94,6 +111,7 @@ trait Annotations { self: Universe => /** The API of `LiteralArgument` instances. * The main source of information about annotations is the [[scala.reflect.api.Annotations]] page. + * @group API */ trait LiteralArgumentApi { /** The underlying compile-time constant value. */ @@ -101,19 +119,25 @@ trait Annotations { self: Universe => } /** An array argument to a Java annotation as in `@Target(value={TYPE,FIELD,METHOD,PARAMETER})` + * @template + * @group Annotations */ type ArrayArgument >: Null <: AnyRef with JavaArgument with ArrayArgumentApi /** A tag that preserves the identity of the `ArrayArgument` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ArrayArgumentTag: ClassTag[ArrayArgument] - /** The constructor/deconstructor for `ArrayArgument` instances. */ + /** The constructor/deconstructor for `ArrayArgument` instances. + * @group Extractors + */ val ArrayArgument: ArrayArgumentExtractor /** An extractor class to create and pattern match with syntax `ArrayArgument(args)` * where `args` is the argument array. + * @group Extractors */ abstract class ArrayArgumentExtractor { def apply(args: Array[JavaArgument]): ArrayArgument @@ -122,6 +146,7 @@ trait Annotations { self: Universe => /** API of `ArrayArgument` instances. * The main source of information about annotations is the [[scala.reflect.api.Annotations]] page. + * @group API */ trait ArrayArgumentApi { /** The underlying array of Java annotation arguments. */ @@ -129,19 +154,25 @@ trait Annotations { self: Universe => } /** A nested annotation argument to a Java annotation as `@Nested` in `@Outer(@Nested)`. + * @template + * @group Annotations */ type NestedArgument >: Null <: AnyRef with JavaArgument with NestedArgumentApi /** A tag that preserves the identity of the `NestedArgument` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val NestedArgumentTag: ClassTag[NestedArgument] - /** The constructor/deconstructor for `NestedArgument` instances. */ + /** The constructor/deconstructor for `NestedArgument` instances. + * @group Extractors + */ val NestedArgument: NestedArgumentExtractor /** An extractor class to create and pattern match with syntax `NestedArgument(annotation)` * where `annotation` is the nested annotation. + * @group Extractors */ abstract class NestedArgumentExtractor { def apply(annotation: Annotation): NestedArgument @@ -150,6 +181,7 @@ trait Annotations { self: Universe => /** API of `NestedArgument` instances. * The main source of information about annotations is the [[scala.reflect.api.Annotations]] page. + * @group API */ trait NestedArgumentApi { /** The underlying nested annotation. */ diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index b0de7f8d5a..0c8e81a220 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -3,15 +3,18 @@ package api /** * This is an internal implementation class. + * @groupname TreeBuilders Tree Building */ private[reflect] trait BuildUtils { self: Universe => + /** @group TreeBuilders */ val build: BuildApi // this API abstracts away the functionality necessary for reification // it's too gimmicky and unstructured to be exposed directly in the universe // but we need it in a publicly available place for reification to work + /** @group TreeBuilders */ abstract class BuildApi { /** Selects type symbol with given simple name `name` from the defined members of `owner`. */ diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala index 9b2cba1391..788fc889a8 100644 --- a/src/reflect/scala/reflect/api/Exprs.scala +++ b/src/reflect/scala/reflect/api/Exprs.scala @@ -19,17 +19,18 @@ import scala.reflect.runtime.{universe => ru} * * `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. + * Manual creation, however, is very rarely needed when working with runtime reflection. * * `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]]. + * [[scala.reflect.runtime#universe]], the default mirror is typically [[scala.reflect.runtime#currentMirror]]. */ trait Exprs { self: Universe => /** 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. + * @group Expressions */ trait Expr[+T] extends Equals with Serializable { /** @@ -123,6 +124,7 @@ trait Exprs { self: Universe => * 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. + * @group Expressions */ 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 bb570bebbe..701442b632 100644 --- a/src/reflect/scala/reflect/api/FlagSets.scala +++ b/src/reflect/scala/reflect/api/FlagSets.scala @@ -32,26 +32,35 @@ import scala.language.implicitConversions */ trait FlagSets { self: Universe => - /** An abstract type representing sets of flags (like private, final, etc.) that apply to definition trees and symbols */ + /** An abstract type representing sets of flags (like private, final, etc.) that apply to definition trees and symbols + * @template + * @group Flags + */ type FlagSet /** A tag that preserves the identity of the `FlagSet` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ 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. + * @group Flags */ 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. */ + /** The API of `FlagSet` instances. + * @group Flags + */ implicit def addFlagOps(left: FlagSet): FlagOps - /** A module that contains all possible values that can constitute flag sets. */ + /** A module that contains all possible values that can constitute flag sets. + * @group Flags + */ val Flag: FlagValues // Q: I have a pretty flag. Can I put it here? @@ -61,6 +70,7 @@ trait FlagSets { self: Universe => /** All possible values that can constitute flag sets. * The main source of information about flag sets is the [[scala.reflect.api.FlagSets]] page. + * @group Flags */ trait FlagValues { @@ -140,6 +150,8 @@ trait FlagSets { self: Universe => val DEFAULTINIT: FlagSet } - /** The empty set of flags */ + /** The empty set of flags + * @group Flags + */ val NoFlags: FlagSet } diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala index f25f5a95e2..fde8794348 100644 --- a/src/reflect/scala/reflect/api/Importers.scala +++ b/src/reflect/scala/reflect/api/Importers.scala @@ -1,16 +1,16 @@ package scala.reflect package api -/** This trait provides support for importers, a facility to migrate reflection artifacts between universes. +/** This trait provides support for importers, a facility to migrate reflection artifacts between universes. * - * 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 + * 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, 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 + * 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 @@ -65,11 +65,14 @@ package api */ trait Importers { self: Universe => - /** Creates an importer that moves reflection artifacts between universes. */ + /** Creates an importer that moves reflection artifacts between universes. + * @group Importers + */ 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. + * @group Importers */ trait Importer { /** The source universe of reflection artifacts that will be processed. diff --git a/src/reflect/scala/reflect/api/JavaMirrors.scala b/src/reflect/scala/reflect/api/JavaMirrors.scala index e51047a7fe..9bc888b884 100644 --- a/src/reflect/scala/reflect/api/JavaMirrors.scala +++ b/src/reflect/scala/reflect/api/JavaMirrors.scala @@ -6,13 +6,18 @@ package api * This refinement equips mirrors with reflection capabilities for the JVM. `JavaMirror` can * convert Scala reflection artifacts (symbols and types) into Java reflection artifacts (classes) * and vice versa. It can also perform reflective invocations (getting/settings field values, calling methods, etc). + * @groupname JavaMirrors Java Mirrors */ trait JavaMirrors { self: JavaUniverse => - /** In runtime reflection universes, runtime representation of a class is [[java.lang.Class]]. */ + /** In runtime reflection universes, runtime representation of a class is `java.lang.Class`. + * @group JavaMirrors + */ type RuntimeClass = java.lang.Class[_] - /** In runtime reflection universes, mirrors are JavaMirrors. */ + /** In runtime reflection universes, mirrors are JavaMirrors. + * @group JavaMirrors + */ override type Mirror >: Null <: JavaMirror /** A refinement of [[scala.reflect.api.Mirror]] for runtime reflection using JVM classloaders. @@ -22,6 +27,7 @@ trait JavaMirrors { self: JavaUniverse => * 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. + * @group JavaMirrors */ trait JavaMirror extends scala.reflect.api.Mirror[self.type] with RuntimeMirror { val classLoader: ClassLoader @@ -30,6 +36,7 @@ trait JavaMirrors { self: JavaUniverse => /** 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. + * @group JavaMirrors */ def runtimeMirror(cl: ClassLoader): Mirror } diff --git a/src/reflect/scala/reflect/api/JavaUniverse.scala b/src/reflect/scala/reflect/api/JavaUniverse.scala index b899d1f6d7..0283a75177 100644 --- a/src/reflect/scala/reflect/api/JavaUniverse.scala +++ b/src/reflect/scala/reflect/api/JavaUniverse.scala @@ -6,10 +6,12 @@ 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 the [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for details on how to use runtime reflection. + * See the [[http://docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for details on how to use runtime reflection. + * @groupname JavaUniverse Java Mirrors */ trait JavaUniverse extends Universe with JavaMirrors { self => + /* @group JavaUniverse */ override def typeTagToManifest[T: ClassTag](mirror0: Any, tag: Universe # TypeTag[T]): Manifest[T] = { // SI-6239: make this conversion more precise val mirror = mirror0.asInstanceOf[Mirror] @@ -17,6 +19,7 @@ trait JavaUniverse extends Universe with JavaMirrors { self => Manifest.classType(runtimeClass).asInstanceOf[Manifest[T]] } + /* @group JavaUniverse */ override def manifestToTypeTag[T](mirror0: Any, manifest: Manifest[T]): Universe # TypeTag[T] = TypeTag(mirror0.asInstanceOf[Mirror], new TypeCreator { def apply[U <: Universe with Singleton](mirror: scala.reflect.api.Mirror[U]): U # Type = { diff --git a/src/reflect/scala/reflect/api/Mirror.scala b/src/reflect/scala/reflect/api/Mirror.scala index ae2c48fa14..60ba087933 100644 --- a/src/reflect/scala/reflect/api/Mirror.scala +++ b/src/reflect/scala/reflect/api/Mirror.scala @@ -4,30 +4,40 @@ package api /** * The base class for all mirrors. * - * See the [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for a description of mirrors + * See the [[http://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 + * 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. */ abstract class Mirror[U <: Universe with Singleton] { - /** The universe this mirror belongs to. */ + /** The universe this mirror belongs to. + * @group Mirror + */ val universe: U - /** The class symbol of the `_root_` package */ + /** The class symbol of the `_root_` package + * @group Mirror + */ def RootClass: U#ClassSymbol - /** The module symbol of the `_root_` package */ + /** The module symbol of the `_root_` package + * @group Mirror + */ def RootPackage: U#ModuleSymbol - /** The module class symbol of the default (unnamed) package */ + /** The module class symbol of the default (unnamed) package + * @group Mirror + */ def EmptyPackageClass: U#ClassSymbol - /** The module symbol of the default (unnamed) package */ + /** The module symbol of the default (unnamed) package + * @group Mirror + */ def EmptyPackage: U#ModuleSymbol /** The symbol corresponding to the globally accessible class with the @@ -71,6 +81,7 @@ abstract class Mirror[U <: Universe with Singleton] { * * In the example above, to load a symbol that corresponds to the class B declared in the object foo, * use staticModule("foo") to load the module symbol and then navigate typeSignature.members of its moduleClass. + * @group Mirror */ def staticClass(fullName: String): U#ClassSymbol @@ -97,11 +108,13 @@ abstract class Mirror[U <: Universe with Singleton] { * * In the example above, to load a symbol that corresponds to the object B declared in the object foo, * use staticModule("foo") to load the module symbol and then navigate typeSignature.members of its moduleClass. + * @group Mirror */ def staticModule(fullName: String): U#ModuleSymbol /** The symbol corresponding to a package with the * given fully qualified name `fullName`. + * @group Mirror */ def staticPackage(fullName: String): U#ModuleSymbol } diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala index 1e742f4145..bebc9488dd 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -1,9 +1,9 @@ package scala.reflect package api -/** This trait provides support for Mirrors in the 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 + * See the [[http://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 => @@ -12,15 +12,19 @@ trait Mirrors { self: Universe => * * This abstract type conforms the base interface for all mirrors defined in [[scala.reflect.api.Mirror]] * and is gradually refined in specific universes (e.g. `Mirror` of a [[scala.reflect.api.JavaUniverse]] is capable of reflection). + * @group Mirrors */ type Mirror >: Null <: scala.reflect.api.Mirror[self.type] /** The root mirror of this universe. This mirror contains standard Scala classes and types such as `Any`, `AnyRef`, `AnyVal`, * `Nothing`, `Null`, and all classes loaded from scala-library, which are shared across all mirrors within the enclosing universe. + * @group Mirrors */ val rootMirror: Mirror - /** Abstracts the runtime representation of a class on the underlying platform. */ + /** Abstracts the runtime representation of a class on the underlying platform. + * @group Mirrors + */ type RuntimeClass >: Null // todo. an improvement might be having mirrors reproduce the structure of the reflection domain @@ -29,6 +33,7 @@ trait Mirrors { self: Universe => /** A mirror that reflects a runtime value. * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection. + * @group Mirrors */ trait InstanceMirror { @@ -105,6 +110,7 @@ trait Mirrors { self: Universe => /** A mirror that reflects a field. * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection. + * @group Mirrors */ trait FieldMirror { @@ -149,6 +155,7 @@ trait Mirrors { self: Universe => /** A mirror that reflects a method. * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection. + * @group Mirrors */ trait MethodMirror { @@ -169,6 +176,7 @@ trait Mirrors { self: Universe => /** 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. + * @group Mirrors */ trait TemplateMirror { @@ -187,6 +195,7 @@ trait Mirrors { self: Universe => /** 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. + * @group Mirrors */ trait ModuleMirror extends TemplateMirror { @@ -202,6 +211,7 @@ trait Mirrors { self: Universe => /** 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. + * @group Mirrors */ trait ClassMirror extends TemplateMirror { @@ -223,6 +233,7 @@ trait Mirrors { self: Universe => /** A mirror that reflects instances and static classes. * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection. + * @group Mirrors */ trait ReflectiveMirror extends scala.reflect.api.Mirror[Mirrors.this.type] { @@ -260,6 +271,7 @@ trait Mirrors { self: 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. + * @group Mirrors */ trait RuntimeMirror extends ReflectiveMirror { self => diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index dccdd6868b..7b66906499 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -2,11 +2,11 @@ package scala.reflect package api /** This trait defines Names (a Scala reflection concept) and operations on them. - * + * * Names are simple wrappers for strings. [[scala.reflect.api.Names#Name Name]] has two subtypes [[scala.reflect.api.Names#TermName TermName]] and [[scala.reflect.api.Names#TypeName TypeName]] which * distinguish names of terms (like objects or members) and types. A term and a type of the - * same name can co-exist in an object. - * + * same name can co-exist in an object. + * * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]]. * === Examples === @@ -19,39 +19,52 @@ package api trait Names { /** An implicit conversion from String to TermName. * Enables an alternative notation `"map": TermName` as opposed to `newTermName("map")`. + * @group Names */ implicit def stringToTermName(s: String): TermName = newTermName(s) /** An implicit conversion from String to TypeName. * Enables an alternative notation `"List": TypeName` as opposed to `newTypeName("List")`. + * @group Names */ implicit def stringToTypeName(s: String): TypeName = newTypeName(s) - /** The abstract type of names. */ + /** The abstract type of names. + * @group 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. + * @group Tags */ implicit val NameTag: ClassTag[Name] - /** The abstract type of names representing terms. */ + /** The abstract type of names representing terms. + * @group Names + */ 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. + * @group Tags */ - implicit val TypeNameTag: ClassTag[TypeName] +implicit val TypeNameTag: ClassTag[TypeName] - /** The abstract type of names representing types. */ + /** The abstract type of names representing types. + * @group Names + */ type TermName >: Null <: Name /** A tag that preserves the identity of the `TermName` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TermNameTag: ClassTag[TermName] - /** The API of Name instances. */ + /** The API of Name instances. + * @group API + */ abstract class NameApi { /** Checks wether the name is a a term name */ def isTermName: Boolean @@ -85,10 +98,12 @@ trait Names { } /** Create a new term name. + * @group Names */ def newTermName(s: String): TermName /** Creates a new type name. + * @group Names */ def newTypeName(s: String): TypeName } diff --git a/src/reflect/scala/reflect/api/Positions.scala b/src/reflect/scala/reflect/api/Positions.scala index bbb1fe45c4..ec1cf21c75 100644 --- a/src/reflect/scala/reflect/api/Positions.scala +++ b/src/reflect/scala/reflect/api/Positions.scala @@ -10,18 +10,23 @@ trait Positions { /** Defines a universe-specific notion of positions. * The main documentation entry about positions is located at [[scala.reflect.api.Position]]. + * @group Positions */ type Position >: Null <: scala.reflect.api.Position { type Pos = Position } /** A tag that preserves the identity of the `Position` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val PositionTag: ClassTag[Position] - /** A special "missing" position. */ + /** A special "missing" position. + * @group Positions + */ val NoPosition: Position /** Assigns a given position to all position-less nodes of a given AST. + * @group Positions */ def atPos[T <: Tree](pos: Position)(tree: T): T @@ -29,6 +34,7 @@ trait Positions { * The point of the wrapping position is the point of the default position. * If some of the trees are ranges, returns a range position enclosing all ranges * Otherwise returns default position. + * @group Positions */ def wrappingPos(default: Position, trees: List[Tree]): Position @@ -36,6 +42,7 @@ trait Positions { * The point of the wrapping position is the point of the first trees' position. * If all some the trees are non-synthetic, returns a range position enclosing the non-synthetic trees * Otherwise returns a synthetic offset position to point. + * @group Positions */ def wrappingPos(trees: List[Tree]): Position } diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala index 831c4ae331..b7157af153 100644 --- a/src/reflect/scala/reflect/api/Printers.scala +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -131,6 +131,7 @@ import java.io.{ PrintWriter, StringWriter } */ trait Printers { self: Universe => + /** @group Printers */ protected trait TreePrinter { def print(args: Any*) protected var printTypes = false @@ -147,13 +148,16 @@ trait Printers { self: Universe => def withoutMirrors: this.type = { printMirrors = false; this } } + /** @group Printers */ case class BooleanFlag(val value: Option[Boolean]) + /** @group Printers */ object BooleanFlag { import scala.language.implicitConversions implicit def booleanToBooleanFlag(value: Boolean): BooleanFlag = BooleanFlag(Some(value)) implicit def optionToBooleanFlag(value: Option[Boolean]): BooleanFlag = BooleanFlag(value) } + /** @group Printers */ protected def render(what: Any, mkPrinter: PrintWriter => TreePrinter, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None): String = { val buffer = new StringWriter() val writer = new PrintWriter(buffer) @@ -167,41 +171,51 @@ trait Printers { self: Universe => buffer.toString } - /** By default trees are printed with `show` */ + /** By default trees are printed with `show` + * @group Printers + */ override protected def treeToString(tree: Tree) = show(tree) /** Renders a prettified representation of a reflection artifact. * Typically it looks very close to the Scala code it represents. + * @group Printers */ def show(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None): String = render(any, newTreePrinter(_), printTypes, printIds, printKinds, printMirrors) /** Hook to define what `show(...)` means. + * @group Printers */ protected def newTreePrinter(out: PrintWriter): TreePrinter /** Renders internal structure of a reflection artifact. + * @group Printers */ def showRaw(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None): String = render(any, newRawTreePrinter(_), printTypes, printIds, printKinds, printMirrors) /** Hook to define what `showRaw(...)` means. + * @group Printers */ protected def newRawTreePrinter(out: PrintWriter): TreePrinter /** Renders a prettified representation of a name. + * @group Printers */ def show(name: Name): String /** Renders internal structure of a name. + * @group Printers */ def showRaw(name: Name): String = name.toString /** Renders a prettified representation of a flag set. + * @group Printers */ def show(flags: FlagSet): String /** Renders internal structure of a flag set. + * @group Printers */ def showRaw(flags: FlagSet): String = flags.toString } diff --git a/src/reflect/scala/reflect/api/Scopes.scala b/src/reflect/scala/reflect/api/Scopes.scala index ec9aba6567..80683c8e76 100644 --- a/src/reflect/scala/reflect/api/Scopes.scala +++ b/src/reflect/scala/reflect/api/Scopes.scala @@ -17,24 +17,37 @@ package api */ trait Scopes { self: Universe => - /** The base type of all scopes. */ + /** The base type of all scopes. + * @template + * @group Scopes + */ type Scope >: Null <: ScopeApi - /** The API that all scopes support */ + /** The API that all scopes support + * @group API + */ trait ScopeApi extends Iterable[Symbol] /** A tag that preserves the identity of the `Scope` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ScopeTag: ClassTag[Scope] - /** Create a new scope with the given initial elements. */ + /** Create a new scope with the given initial elements. + * @group Scopes + */ def newScopeWith(elems: Symbol*): Scope - /** The type of member scopes, as in class definitions, for example. */ + /** The type of member scopes, as in class definitions, for example. + * @template + * @group Scopes + */ type MemberScope >: Null <: Scope with MemberScopeApi - /** The API that all member scopes support */ + /** The API that all member scopes support + * @group API + */ trait MemberScopeApi extends ScopeApi { /** Sorts the symbols included in this scope so that: * 1) Symbols appear in the linearization order of their owners. @@ -46,6 +59,7 @@ trait Scopes { self: Universe => /** A tag that preserves the identity of the `MemberScope` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val MemberScopeTag: ClassTag[MemberScope] } \ No newline at end of file diff --git a/src/reflect/scala/reflect/api/StandardDefinitions.scala b/src/reflect/scala/reflect/api/StandardDefinitions.scala index cca9440302..e1eadde3ad 100644 --- a/src/reflect/scala/reflect/api/StandardDefinitions.scala +++ b/src/reflect/scala/reflect/api/StandardDefinitions.scala @@ -13,10 +13,14 @@ package api trait StandardDefinitions { self: Universe => - /** A value containing all standard definitions. */ + /** A value containing all standard definitions in [[DefinitionsApi]] + * @group Definitions + */ val definitions: DefinitionsApi - /** Defines standard symbols (and types via its base trait). */ + /** Defines standard symbols (and types via its base trait). + * @group API + */ trait DefinitionsApi extends StandardTypes { /** The module class symbol of package `scala`. */ def ScalaPackageClass: ClassSymbol @@ -252,7 +256,9 @@ trait StandardDefinitions { def ScalaNumericValueClasses: List[ClassSymbol] } - /** Defines standard types. */ + /** Defines standard types. + * @group Definitions + */ trait StandardTypes { /** The type of primitive type `Unit`. */ val UnitTpe: Type diff --git a/src/reflect/scala/reflect/api/TagInterop.scala b/src/reflect/scala/reflect/api/TagInterop.scala index 4653eb975f..b495c3f50c 100644 --- a/src/reflect/scala/reflect/api/TagInterop.scala +++ b/src/reflect/scala/reflect/api/TagInterop.scala @@ -16,6 +16,7 @@ trait TagInterop { self: Universe => * {{{ * typeTagToManifest(scala.reflect.runtime.currentMirror, implicitly[TypeTag[String]]) * }}} + * @group Tags */ 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.") @@ -29,6 +30,7 @@ trait TagInterop { self: Universe => * {{{ * manifestToTypeTag(scala.reflect.runtime.currentMirror, implicitly[Manifest[String]]) * }}} + * @group Tags */ def manifestToTypeTag[T](mirror: Any, manifest: Manifest[T]): Universe#TypeTag[T] = throw new UnsupportedOperationException("This universe does not support manifest -> tag conversions. Use a JavaUniverse, e.g. the scala.reflect.runtime.universe.") diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 03d62c3bb9..1142bb042f 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -6,40 +6,50 @@ package scala.reflect package api /** This trait defines the node types used in Scala abstract syntax trees (AST) and operations on them. - * - * All tree node types are sub types of [[scala.reflect.api#Tree Tree]]. - * - * Trees are immutable, except for three fields + * +* All tree node types are sub types of [[scala.reflect.api.Trees#Tree Tree]]. + * + * Trees are immutable, except for three fields * [[Trees#TreeApi.pos pos]], [[Trees#TreeApi.symbol symbol]], and [[Trees#TreeApi.tpe tpe]], which are assigned when a tree is typechecked * to attribute it with the information gathered by the typechecker. - * + * * [[scala.reflect.api.Universe#reify reify]] can be used to get the tree for a given Scala expression. - * + * * [[scala.reflect.api.Universe#showRaw showRaw]] can be used to get a readable representation of a tree. * * === Examples === * `Literal(Constant(5))` creates an AST representing a literal 5 in Scala source code. - * + * * `Apply(Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("print")), List(Literal(Constant("Hello World"))))` * creates an AST representing `print("Hello World")`. - * + * * `import scala.reflect.runtime.universe.{reify,showRaw}` - * `print( showRaw( reify{5}.tree ) )` // prints Literal(Constant(5)) + * `print( showRaw( reify{5}.tree ) )` // prints Literal(Constant(5)) * * @see [[http://docs.scala-lang.org/overviews/reflection/symbols-trees-types.html#trees]]. + * @groupname Traversal Tree Traversal and Transformation + * @groupprio Traversal 1 + * @groupprio Factories 1 + * @groupname Copying Tree Copying + * @groupprio Copying 1 */ trait Trees { self: Universe => - /** The type of Scala abstract syntax trees. */ + /** The type of Scala abstract syntax trees. + * @group Trees + * @template + */ type Tree >: Null <: TreeApi /** A tag that preserves the identity of the `Tree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TreeTag: ClassTag[Tree] /** The API that all trees support. * The main source of information about trees is the [[scala.reflect.api.Trees]] page. + * @group API */ trait TreeApi extends Product { this: Tree => /** Does this tree represent a definition? (of a method, of a class, etc) */ @@ -69,7 +79,7 @@ trait Trees { self: Universe => * Some node factory methods set `tpe` immediately after creation. * * When the typechecker encounters a tree with a non-null tpe, - * it will assume it to be correct and not check it again. This means one has + * it will assume it to be correct and not check it again. This means one has * to be careful not to erase the `tpe` field of subtrees. */ def tpe: Type @@ -163,65 +173,89 @@ trait Trees { self: Universe => override def toString: String = treeToString(this) } - /** Obtains string representation of a tree */ + /** Obtains string representation of a tree + * @group Trees + */ protected def treeToString(tree: Tree): String - /** The empty tree */ + /** The empty tree + * @group Trees + */ val EmptyTree: Tree /** A tree for a term. Not all trees representing terms are TermTrees; use isTerm * to reliably identify terms. + * @group Trees + * @template */ type TermTree >: Null <: AnyRef with Tree with TermTreeApi /** A tag that preserves the identity of the `TermTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TermTreeTag: ClassTag[TermTree] - /** The API that all term trees support */ + /** The API that all term trees support + * @group API + */ trait TermTreeApi extends TreeApi { this: TermTree => } /** A tree for a type. Not all trees representing types are TypTrees; use isType * to reliably identify types. + * @group Trees + * @template */ type TypTree >: Null <: AnyRef with Tree with TypTreeApi /** A tag that preserves the identity of the `TypTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TypTreeTag: ClassTag[TypTree] - /** The API that all typ trees support */ + /** The API that all typ trees support + * @group API + */ trait TypTreeApi extends TreeApi { this: TypTree => } /** A tree with a mutable symbol field, initialized to NoSymbol. + * @group Trees + * @template */ type SymTree >: Null <: AnyRef with Tree with SymTreeApi /** A tag that preserves the identity of the `SymTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val SymTreeTag: ClassTag[SymTree] - /** The API that all sym trees support */ + /** The API that all sym trees support + * @group API + */ trait SymTreeApi extends TreeApi { this: SymTree => /** @inheritdoc */ def symbol: Symbol } /** A tree with a name - effectively, a DefTree or RefTree. + * @group Trees + * @template */ type NameTree >: Null <: AnyRef with Tree with NameTreeApi /** A tag that preserves the identity of the `NameTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val NameTreeTag: ClassTag[NameTree] - /** The API that all name trees support */ + /** The API that all name trees support + * @group API + */ trait NameTreeApi extends TreeApi { this: NameTree => /** The underlying name. * For example, the `` part of `Ident("List": TermName)`. @@ -232,15 +266,20 @@ trait Trees { self: Universe => /** A tree which references a symbol-carrying entity. * References one, as opposed to defining one; definitions * are in DefTrees. + * @group Trees + * @template */ type RefTree >: Null <: SymTree with NameTree with RefTreeApi /** A tag that preserves the identity of the `RefTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val RefTreeTag: ClassTag[RefTree] - /** The API that all ref trees support */ + /** The API that all ref trees support + * @group API + */ trait RefTreeApi extends SymTreeApi with NameTreeApi { this: RefTree => /** The qualifier of the reference. * For example, the `` part of `Select("scala": TermName, "List": TermName)`. @@ -253,15 +292,20 @@ trait Trees { self: Universe => } /** A tree which defines a symbol-carrying entity. + * @group Trees + * @template */ type DefTree >: Null <: SymTree with NameTree with DefTreeApi /** A tag that preserves the identity of the `DefTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val DefTreeTag: ClassTag[DefTree] - /** The API that all def trees support */ + /** The API that all def trees support + * @group API + */ trait DefTreeApi extends SymTreeApi with NameTreeApi { this: DefTree => /** @inheritdoc */ def name: Name @@ -269,43 +313,56 @@ trait Trees { self: Universe => /** Common base class for all member definitions: types, classes, * objects, packages, vals and vars, defs. + * @group Trees + * @template */ type MemberDef >: Null <: DefTree with MemberDefApi /** A tag that preserves the identity of the `MemberDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val MemberDefTag: ClassTag[MemberDef] - /** The API that all member defs support */ + /** The API that all member defs support + * @group API + */ trait MemberDefApi extends DefTreeApi { this: MemberDef => /** Modifiers of the declared member. */ def mods: Modifiers } /** A packaging, such as `package pid { stats }` + * @group Trees + * @template */ type PackageDef >: Null <: MemberDef with PackageDefApi /** A tag that preserves the identity of the `PackageDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val PackageDefTag: ClassTag[PackageDef] - /** The constructor/deconstructor for `PackageDef` instances. */ + /** The constructor/deconstructor for `PackageDef` instances. + * @group Extractors + */ val PackageDef: PackageDefExtractor /** An extractor class to create and pattern match with syntax `PackageDef(pid, stats)`. * This AST node corresponds to the following Scala code: * * `package` pid { stats } + * @group Extractors */ abstract class PackageDefExtractor { def apply(pid: RefTree, stats: List[Tree]): PackageDef def unapply(packageDef: PackageDef): Option[(RefTree, List[Tree])] } - /** The API that all package defs support */ + /** The API that all package defs support + * @group API + */ trait PackageDefApi extends MemberDefApi { this: PackageDef => /** The (possibly, fully-qualified) name of the package. */ val pid: RefTree @@ -315,30 +372,40 @@ trait Trees { self: Universe => } /** A common base class for class and object definitions. + * @group Trees + * @template */ type ImplDef >: Null <: MemberDef with ImplDefApi /** A tag that preserves the identity of the `ImplDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ImplDefTag: ClassTag[ImplDef] - /** The API that all impl defs support */ + /** The API that all impl defs support + * @group API + */ trait ImplDefApi extends MemberDefApi { this: ImplDef => /** The body of the definition. */ val impl: Template } /** A class definition. + * @group Trees + * @template */ type ClassDef >: Null <: ImplDef with ClassDefApi /** A tag that preserves the identity of the `ClassDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ClassDefTag: ClassTag[ClassDef] - /** The constructor/deconstructor for `ClassDef` instances. */ + /** The constructor/deconstructor for `ClassDef` instances. + * @group Extractors + */ val ClassDef: ClassDefExtractor /** An extractor class to create and pattern match with syntax `ClassDef(mods, name, tparams, impl)`. @@ -349,13 +416,16 @@ trait Trees { self: Universe => * Where impl stands for: * * `extends` parents { defs } + * @group Extractors */ abstract class ClassDefExtractor { def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], impl: Template): ClassDef def unapply(classDef: ClassDef): Option[(Modifiers, TypeName, List[TypeDef], Template)] } - /** The API that all class defs support */ + /** The API that all class defs support + * @group API + */ trait ClassDefApi extends ImplDefApi { this: ClassDef => /** @inheritdoc */ val mods: Modifiers @@ -373,15 +443,20 @@ trait Trees { self: Universe => /** An object definition, e.g. `object Foo`. Internally, objects are * quite frequently called modules to reduce ambiguity. * Eliminated by compiler phase refcheck. + * @group Trees + * @template */ type ModuleDef >: Null <: ImplDef with ModuleDefApi /** A tag that preserves the identity of the `ModuleDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ModuleDefTag: ClassTag[ModuleDef] - /** The constructor/deconstructor for `ModuleDef` instances. */ + /** The constructor/deconstructor for `ModuleDef` instances. + * @group Extractors + */ val ModuleDef: ModuleDefExtractor /** An extractor class to create and pattern match with syntax `ModuleDef(mods, name, impl)`. @@ -392,13 +467,16 @@ trait Trees { self: Universe => * Where impl stands for: * * `extends` parents { defs } + * @group Extractors */ abstract class ModuleDefExtractor { def apply(mods: Modifiers, name: TermName, impl: Template): ModuleDef def unapply(moduleDef: ModuleDef): Option[(Modifiers, TermName, Template)] } - /** The API that all module defs support */ + /** The API that all module defs support + * @group API + */ trait ModuleDefApi extends ImplDefApi { this: ModuleDef => /** @inheritdoc */ val mods: Modifiers @@ -411,15 +489,20 @@ trait Trees { self: Universe => } /** A common base class for ValDefs and DefDefs. + * @group Trees + * @template */ type ValOrDefDef >: Null <: MemberDef with ValOrDefDefApi /** A tag that preserves the identity of the `ValOrDefDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ValOrDefDefTag: ClassTag[ValOrDefDef] - /** The API that all val defs and def defs support */ + /** The API that all val defs and def defs support + * @group API + */ trait ValOrDefDefApi extends MemberDefApi { this: ValOrDefDef => /** @inheritdoc */ def name: Name // can't be a TermName because macros can be type names. @@ -443,15 +526,20 @@ trait Trees { self: Universe => * - lazy values, e.g. "lazy val x" - the LAZY flag set in mods * - method parameters, see vparamss in [[scala.reflect.api.Trees#DefDef]] - the PARAM flag is set in mods * - explicit self-types, e.g. class A { self: Bar => } + * @group Trees + * @template */ type ValDef >: Null <: ValOrDefDef with ValDefApi /** A tag that preserves the identity of the `ValDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ValDefTag: ClassTag[ValDef] - /** The constructor/deconstructor for `ValDef` instances. */ + /** The constructor/deconstructor for `ValDef` instances. + * @group Extractors + */ val ValDef: ValDefExtractor /** An extractor class to create and pattern match with syntax `ValDef(mods, name, tpt, rhs)`. @@ -467,13 +555,16 @@ trait Trees { self: Universe => * * If the type of a value is not specified explicitly (i.e. is meant to be inferred), * this is expressed by having `tpt` set to `TypeTree()` (but not to an `EmptyTree`!). + * @group Extractors */ abstract class ValDefExtractor { def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree): ValDef def unapply(valDef: ValDef): Option[(Modifiers, TermName, Tree, Tree)] } - /** The API that all val defs support */ + /** The API that all val defs support + * @group API + */ trait ValDefApi extends ValOrDefDefApi { this: ValDef => /** @inheritdoc */ val mods: Modifiers @@ -490,15 +581,20 @@ trait Trees { self: Universe => /** A method or macro definition. * @param name The name of the method or macro. Can be a type name in case this is a type macro + * @group Trees + * @template */ type DefDef >: Null <: ValOrDefDef with DefDefApi /** A tag that preserves the identity of the `DefDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val DefDefTag: ClassTag[DefDef] - /** The constructor/deconstructor for `DefDef` instances. */ + /** The constructor/deconstructor for `DefDef` instances. + * @group Extractors + */ val DefDef: DefDefExtractor /** An extractor class to create and pattern match with syntax `DefDef(mods, name, tparams, vparamss, tpt, rhs)`. @@ -508,13 +604,16 @@ trait Trees { self: Universe => * * If the return type is not specified explicitly (i.e. is meant to be inferred), * this is expressed by having `tpt` set to `TypeTree()` (but not to an `EmptyTree`!). + * @group Extractors */ abstract class DefDefExtractor { def apply(mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef def unapply(defDef: DefDef): Option[(Modifiers, Name, List[TypeDef], List[List[ValDef]], Tree, Tree)] } - /** The API that all def defs support */ + /** The API that all def defs support + * @group API + */ trait DefDefApi extends ValOrDefDefApi { this: DefDef => /** @inheritdoc */ val mods: Modifiers @@ -537,15 +636,20 @@ trait Trees { self: Universe => /** An abstract type, a type parameter, or a type alias. * Eliminated by erasure. + * @group Trees + * @template */ type TypeDef >: Null <: MemberDef with TypeDefApi /** A tag that preserves the identity of the `TypeDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TypeDefTag: ClassTag[TypeDef] - /** The constructor/deconstructor for `TypeDef` instances. */ + /** The constructor/deconstructor for `TypeDef` instances. + * @group Extractors + */ val TypeDef: TypeDefExtractor /** An extractor class to create and pattern match with syntax `TypeDef(mods, name, tparams, rhs)`. @@ -558,13 +662,16 @@ trait Trees { self: Universe => * First usage illustrates `TypeDefs` representing type aliases and type parameters. * Second usage illustrates `TypeDefs` representing abstract types, * where lo and hi are both `TypeBoundsTrees` and `Modifier.deferred` is set in mods. + * @group Extractors */ abstract class TypeDefExtractor { def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree): TypeDef def unapply(typeDef: TypeDef): Option[(Modifiers, TypeName, List[TypeDef], Tree)] } - /** The API that all type defs support */ + /** The API that all type defs support + * @group API + */ trait TypeDefApi extends MemberDefApi { this: TypeDef => /** @inheritdoc */ val mods: Modifiers @@ -594,15 +701,20 @@ trait Trees { self: Universe => * assigned to the Idents. * * Forward jumps within a block are allowed. + * @group Trees + * @template */ type LabelDef >: Null <: DefTree with TermTree with LabelDefApi /** A tag that preserves the identity of the `LabelDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val LabelDefTag: ClassTag[LabelDef] - /** The constructor/deconstructor for `LabelDef` instances. */ + /** The constructor/deconstructor for `LabelDef` instances. + * @group Extractors + */ val LabelDef: LabelDefExtractor /** An extractor class to create and pattern match with syntax `LabelDef(name, params, rhs)`. @@ -611,18 +723,21 @@ trait Trees { self: Universe => * It is used for tailcalls and like. * For example, while/do are desugared to label defs as follows: * {{{ - * while (cond) body ==> LabelDef($L, List(), if (cond) { body; L$() } else ()) + * while (cond) body ==> LabelDef(\$L, List(), if (cond) { body; L\$() } else ()) * }}} * {{{ - * do body while (cond) ==> LabelDef($L, List(), body; if (cond) L$() else ()) + * do body while (cond) ==> LabelDef(\$L, List(), body; if (cond) L\$() else ()) * }}} + * @group Extractors */ abstract class LabelDefExtractor { def apply(name: TermName, params: List[Ident], rhs: Tree): LabelDef def unapply(labelDef: LabelDef): Option[(TermName, List[Ident], Tree)] } - /** The API that all label defs support */ + /** The API that all label defs support + * @group API + */ trait LabelDefApi extends DefTreeApi with TermTreeApi { this: LabelDef => /** @inheritdoc */ val name: TermName @@ -648,26 +763,34 @@ trait Trees { self: Universe => * @param namePos its position or -1 if undefined * @param rename the name the import is renamed to (== name if no renaming) * @param renamePos the position of the rename or -1 if undefined + * @group Trees + * @template */ type ImportSelector >: Null <: AnyRef with ImportSelectorApi /** A tag that preserves the identity of the `ImportSelector` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ImportSelectorTag: ClassTag[ImportSelector] - /** The constructor/deconstructor for `ImportSelector` instances. */ + /** The constructor/deconstructor for `ImportSelector` instances. + * @group Extractors + */ val ImportSelector: ImportSelectorExtractor /** An extractor class to create and pattern match with syntax `ImportSelector(name:, namePos, rename, renamePos)`. * This is not an AST node, it is used as a part of the `Import` node. + * @group Extractors */ abstract class ImportSelectorExtractor { def apply(name: Name, namePos: Int, rename: Name, renamePos: Int): ImportSelector def unapply(importSelector: ImportSelector): Option[(Name, Int, Name, Int)] } - /** The API that all import selectors support */ + /** The API that all import selectors support + * @group API + */ trait ImportSelectorApi { this: ImportSelector => /** The imported name. */ val name: Name @@ -692,15 +815,20 @@ trait Trees { self: Universe => * * @param expr * @param selectors + * @group Trees + * @template */ type Import >: Null <: SymTree with ImportApi /** A tag that preserves the identity of the `Import` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ImportTag: ClassTag[Import] - /** The constructor/deconstructor for `Import` instances. */ + /** The constructor/deconstructor for `Import` instances. + * @group Extractors + */ val Import: ImportExtractor /** An extractor class to create and pattern match with syntax `Import(expr, selectors)`. @@ -719,13 +847,16 @@ trait Trees { self: Universe => * * The symbol of an `Import` is an import symbol @see Symbol.newImport. * It's used primarily as a marker to check that the import has been typechecked. + * @group Extractors */ abstract class ImportExtractor { def apply(expr: Tree, selectors: List[ImportSelector]): Import def unapply(import_ : Import): Option[(Tree, List[ImportSelector])] } - /** The API that all imports support */ + /** The API that all imports support + * @group API + */ trait ImportApi extends SymTreeApi { this: Import => /** The qualifier of the import. * See the example for [[scala.reflect.api.Trees#ImportExtractor]]. @@ -742,15 +873,20 @@ trait Trees { self: Universe => * * @param parents * @param body + * @group Trees + * @template */ type Template >: Null <: SymTree with TemplateApi /** A tag that preserves the identity of the `Template` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TemplateTag: ClassTag[Template] - /** The constructor/deconstructor for `Template` instances. */ + /** The constructor/deconstructor for `Template` instances. + * @group Extractors + */ val Template: TemplateExtractor /** An extractor class to create and pattern match with syntax `Template(parents, self, body)`. @@ -770,13 +906,16 @@ trait Trees { self: Universe => * def bar // owner is local dummy * } * } + * @group Extractors */ abstract class TemplateExtractor { def apply(parents: List[Tree], self: ValDef, body: List[Tree]): Template def unapply(template: Template): Option[(List[Tree], ValDef, List[Tree])] } - /** The API that all templates support */ + /** The API that all templates support + * @group API + */ trait TemplateApi extends SymTreeApi { this: Template => /** Superclasses of the template. */ val parents: List[Tree] @@ -791,15 +930,21 @@ trait Trees { self: Universe => val body: List[Tree] } - /** Block of expressions (semicolon separated expressions) */ + /** Block of expressions (semicolon separated expressions) + * @group Trees + * @template + */ type Block >: Null <: TermTree with BlockApi /** A tag that preserves the identity of the `Block` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val BlockTag: ClassTag[Block] - /** The constructor/deconstructor for `Block` instances. */ + /** The constructor/deconstructor for `Block` instances. + * @group Extractors + */ val Block: BlockExtractor /** An extractor class to create and pattern match with syntax `Block(stats, expr)`. @@ -808,13 +953,16 @@ trait Trees { self: Universe => * { stats; expr } * * If the block is empty, the `expr` is set to `Literal(Constant(()))`. + * @group Extractors */ abstract class BlockExtractor { def apply(stats: List[Tree], expr: Tree): Block def unapply(block: Block): Option[(List[Tree], Tree)] } - /** The API that all blocks support */ + /** The API that all blocks support + * @group API + */ trait BlockApi extends TermTreeApi { this: Block => /** All, but the last, expressions in the block. * Can very well be an empty list. @@ -828,15 +976,20 @@ trait Trees { self: Universe => /** Case clause in a pattern match. * (except for occurrences in switch statements). * Eliminated by compiler phases patmat (in the new pattern matcher of 2.10) or explicitouter (in the old pre-2.10 pattern matcher) + * @group Trees + * @template */ type CaseDef >: Null <: AnyRef with Tree with CaseDefApi /** A tag that preserves the identity of the `CaseDef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val CaseDefTag: ClassTag[CaseDef] - /** The constructor/deconstructor for `CaseDef` instances. */ + /** The constructor/deconstructor for `CaseDef` instances. + * @group Extractors + */ val CaseDef: CaseDefExtractor /** An extractor class to create and pattern match with syntax `CaseDef(pat, guard, body)`. @@ -846,13 +999,16 @@ trait Trees { self: Universe => * * If the guard is not present, the `guard` is set to `EmptyTree`. * If the body is not specified, the `body` is set to `Literal(Constant())` + * @group Extractors */ abstract class CaseDefExtractor { def apply(pat: Tree, guard: Tree, body: Tree): CaseDef def unapply(caseDef: CaseDef): Option[(Tree, Tree, Tree)] } - /** The API that all case defs support */ + /** The API that all case defs support + * @group API + */ trait CaseDefApi extends TreeApi { this: CaseDef => /** The pattern of the pattern matching clause. */ val pat: Tree @@ -873,28 +1029,36 @@ trait Trees { self: Universe => * Eliminated by compiler phases Eliminated by compiler phases patmat (in the new pattern matcher of 2.10) or explicitouter (in the old pre-2.10 pattern matcher), * except for * occurrences in encoded Switch stmt (i.e. remaining Match(CaseDef(...))) + * @group Trees + * @template */ type Alternative >: Null <: TermTree with AlternativeApi /** A tag that preserves the identity of the `Alternative` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val AlternativeTag: ClassTag[Alternative] - /** The constructor/deconstructor for `Alternative` instances. */ + /** The constructor/deconstructor for `Alternative` instances. + * @group Extractors + */ val Alternative: AlternativeExtractor /** An extractor class to create and pattern match with syntax `Alternative(trees)`. * This AST node corresponds to the following Scala code: * * pat1 | ... | patn + * @group Extractors */ abstract class AlternativeExtractor { def apply(trees: List[Tree]): Alternative def unapply(alternative: Alternative): Option[List[Tree]] } - /** The API that all alternatives support */ + /** The API that all alternatives support + * @group API + */ trait AlternativeApi extends TermTreeApi { this: Alternative => /** Alternatives of the pattern matching clause. */ val trees: List[Tree] @@ -903,28 +1067,36 @@ trait Trees { self: Universe => /** Repetition of pattern. * * Eliminated by compiler phases patmat (in the new pattern matcher of 2.10) or explicitouter (in the old pre-2.10 pattern matcher). + * @group Trees + * @template */ type Star >: Null <: TermTree with StarApi /** A tag that preserves the identity of the `Star` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val StarTag: ClassTag[Star] - /** The constructor/deconstructor for `Star` instances. */ + /** The constructor/deconstructor for `Star` instances. + * @group Extractors + */ val Star: StarExtractor /** An extractor class to create and pattern match with syntax `Star(elem)`. * This AST node corresponds to the following Scala code: * * pat* + * @group Extractors */ abstract class StarExtractor { def apply(elem: Tree): Star def unapply(star: Star): Option[Tree] } - /** The API that all stars support */ + /** The API that all stars support + * @group API + */ trait StarApi extends TermTreeApi { this: Star => /** The quantified pattern. */ val elem: Tree @@ -936,28 +1108,36 @@ trait Trees { self: Universe => * * @param name * @param body + * @group Trees + * @template */ type Bind >: Null <: DefTree with BindApi /** A tag that preserves the identity of the `Bind` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val BindTag: ClassTag[Bind] - /** The constructor/deconstructor for `Bind` instances. */ + /** The constructor/deconstructor for `Bind` instances. + * @group Extractors + */ val Bind: BindExtractor /** An extractor class to create and pattern match with syntax `Bind(name, body)`. * This AST node corresponds to the following Scala code: * * pat* + * @group Extractors */ abstract class BindExtractor { def apply(name: Name, body: Tree): Bind def unapply(bind: Bind): Option[(Name, Tree)] } - /** The API that all binds support */ + /** The API that all binds support + * @group API + */ 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)`. @@ -997,27 +1177,35 @@ trait Trees { self: Universe => * }}} * * Introduced by typer. Eliminated by compiler phases patmat (in the new pattern matcher of 2.10) or explicitouter (in the old pre-2.10 pattern matcher). + * @group Trees + * @template */ type UnApply >: Null <: TermTree with UnApplyApi /** A tag that preserves the identity of the `UnApply` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val UnApplyTag: ClassTag[UnApply] - /** The constructor/deconstructor for `UnApply` instances. */ + /** The constructor/deconstructor for `UnApply` instances. + * @group Extractors + */ val UnApply: UnApplyExtractor /** An extractor class to create and pattern match with syntax `UnApply(fun, args)`. * This AST node does not have direct correspondence to Scala code, * and is introduced when typechecking pattern matches and `try` blocks. + * @group Extractors */ abstract class UnApplyExtractor { def apply(fun: Tree, args: List[Tree]): UnApply def unapply(unApply: UnApply): Option[(Tree, List[Tree])] } - /** The API that all unapplies support */ + /** The API that all unapplies support + * @group API + */ trait UnApplyApi extends TermTreeApi { this: UnApply => /** A dummy node that carries the type of unapplication. * See the example for [[scala.reflect.api.Trees#UnApplyExtractor]]. @@ -1030,15 +1218,21 @@ trait Trees { self: Universe => val args: List[Tree] } - /** Anonymous function, eliminated by compiler phase lambdalift */ + /** Anonymous function, eliminated by compiler phase lambdalift + * @group Trees + * @template + */ type Function >: Null <: TermTree with SymTree with FunctionApi /** A tag that preserves the identity of the `Function` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val FunctionTag: ClassTag[Function] - /** The constructor/deconstructor for `Function` instances. */ + /** The constructor/deconstructor for `Function` instances. + * @group Extractors + */ val Function: FunctionExtractor /** An extractor class to create and pattern match with syntax `Function(vparams, body)`. @@ -1048,13 +1242,16 @@ trait Trees { self: Universe => * * The symbol of a Function is a synthetic TermSymbol. * It is the owner of the function's parameters. + * @group Extractors */ abstract class FunctionExtractor { def apply(vparams: List[ValDef], body: Tree): Function def unapply(function: Function): Option[(List[ValDef], Tree)] } - /** The API that all functions support */ + /** The API that all functions support + * @group API + */ trait FunctionApi extends TermTreeApi with SymTreeApi { this: Function => /** The list of parameters of the function. */ @@ -1065,28 +1262,37 @@ trait Trees { self: Universe => val body: Tree } - /** Assignment */ + /** Assignment + * @group Trees + * @template + */ type Assign >: Null <: TermTree with AssignApi /** A tag that preserves the identity of the `Assign` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val AssignTag: ClassTag[Assign] - /** The constructor/deconstructor for `Assign` instances. */ + /** The constructor/deconstructor for `Assign` instances. + * @group Extractors + */ val Assign: AssignExtractor /** An extractor class to create and pattern match with syntax `Assign(lhs, rhs)`. * This AST node corresponds to the following Scala code: * * lhs = rhs + * @group Extractors */ abstract class AssignExtractor { def apply(lhs: Tree, rhs: Tree): Assign def unapply(assign: Assign): Option[(Tree, Tree)] } - /** The API that all assigns support */ + /** The API that all assigns support + * @group API + */ trait AssignApi extends TermTreeApi { this: Assign => /** The left-hand side of the assignment. */ @@ -1099,15 +1305,20 @@ trait Trees { self: Universe => /** Either an assignment or a named argument. Only appears in argument lists, * eliminated by compiler phase typecheck (doTypedApply), resurrected by reifier. + * @group Trees + * @template */ type AssignOrNamedArg >: Null <: TermTree with AssignOrNamedArgApi /** A tag that preserves the identity of the `AssignOrNamedArg` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val AssignOrNamedArgTag: ClassTag[AssignOrNamedArg] - /** The constructor/deconstructor for `AssignOrNamedArg` instances. */ + /** The constructor/deconstructor for `AssignOrNamedArg` instances. + * @group Extractors + */ val AssignOrNamedArg: AssignOrNamedArgExtractor /** An extractor class to create and pattern match with syntax `AssignOrNamedArg(lhs, rhs)`. @@ -1120,13 +1331,16 @@ trait Trees { self: Universe => * @annotation(lhs = rhs) * }}} * + * @group Extractors */ abstract class AssignOrNamedArgExtractor { def apply(lhs: Tree, rhs: Tree): AssignOrNamedArg def unapply(assignOrNamedArg: AssignOrNamedArg): Option[(Tree, Tree)] } - /** The API that all assigns support */ + /** The API that all assigns support + * @group API + */ trait AssignOrNamedArgApi extends TermTreeApi { this: AssignOrNamedArg => /** The left-hand side of the expression. */ @@ -1137,15 +1351,21 @@ trait Trees { self: Universe => val rhs: Tree } - /** Conditional expression */ + /** Conditional expression + * @group Trees + * @template + */ type If >: Null <: TermTree with IfApi /** A tag that preserves the identity of the `If` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val IfTag: ClassTag[If] - /** The constructor/deconstructor for `If` instances. */ + /** The constructor/deconstructor for `If` instances. + * @group Extractors + */ val If: IfExtractor /** An extractor class to create and pattern match with syntax `If(cond, thenp, elsep)`. @@ -1154,13 +1374,16 @@ trait Trees { self: Universe => * `if` (cond) thenp `else` elsep * * If the alternative is not present, the `elsep` is set to `Literal(Constant(()))`. + * @group Extractors */ abstract class IfExtractor { def apply(cond: Tree, thenp: Tree, elsep: Tree): If def unapply(if_ : If): Option[(Tree, Tree, Tree)] } - /** The API that all ifs support */ + /** The API that all ifs support + * @group API + */ trait IfApi extends TermTreeApi { this: If => /** The condition of the if. */ @@ -1186,15 +1409,20 @@ trait Trees { self: Universe => * or `Alternative(lit|...|lit)` * - except for an "otherwise" branch, which has pattern * `Ident(nme.WILDCARD)` + * @group Trees + * @template */ type Match >: Null <: TermTree with MatchApi /** A tag that preserves the identity of the `Match` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val MatchTag: ClassTag[Match] - /** The constructor/deconstructor for `Match` instances. */ + /** The constructor/deconstructor for `Match` instances. + * @group Extractors + */ val Match: MatchExtractor /** An extractor class to create and pattern match with syntax `Match(selector, cases)`. @@ -1203,13 +1431,16 @@ trait Trees { self: Universe => * selector `match` { cases } * * `Match` is also used in pattern matching assignments like `val (foo, bar) = baz`. + * @group Extractors */ abstract class MatchExtractor { def apply(selector: Tree, cases: List[CaseDef]): Match def unapply(match_ : Match): Option[(Tree, List[CaseDef])] } - /** The API that all matches support */ + /** The API that all matches support + * @group API + */ trait MatchApi extends TermTreeApi { this: Match => /** The scrutinee of the pattern match. */ val selector: Tree @@ -1218,15 +1449,21 @@ trait Trees { self: Universe => val cases: List[CaseDef] } - /** Return expression */ + /** Return expression + * @group Trees + * @template + */ type Return >: Null <: TermTree with SymTree with ReturnApi /** A tag that preserves the identity of the `Return` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ReturnTag: ClassTag[Return] - /** The constructor/deconstructor for `Return` instances. */ + /** The constructor/deconstructor for `Return` instances. + * @group Extractors + */ val Return: ReturnExtractor /** An extractor class to create and pattern match with syntax `Return(expr)`. @@ -1235,27 +1472,36 @@ trait Trees { self: Universe => * `return` expr * * The symbol of a Return node is the enclosing method. + * @group Extractors */ abstract class ReturnExtractor { def apply(expr: Tree): Return def unapply(return_ : Return): Option[Tree] } - /** The API that all returns support */ + /** The API that all returns support + * @group API + */ trait ReturnApi extends TermTreeApi { this: Return => /** The returned expression. */ val expr: Tree } - /** TODO comment me! */ + /** Try catch node + * @group Trees + * @template + */ type Try >: Null <: TermTree with TryApi /** A tag that preserves the identity of the `Try` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TryTag: ClassTag[Try] - /** The constructor/deconstructor for `Try` instances. */ + /** The constructor/deconstructor for `Try` instances. + * @group Extractors + */ val Try: TryExtractor /** An extractor class to create and pattern match with syntax `Try(block, catches, finalizer)`. @@ -1264,13 +1510,16 @@ trait Trees { self: Universe => * `try` block `catch` { catches } `finally` finalizer * * If the finalizer is not present, the `finalizer` is set to `EmptyTree`. + * @group Extractors */ abstract class TryExtractor { def apply(block: Tree, catches: List[CaseDef], finalizer: Tree): Try def unapply(try_ : Try): Option[(Tree, List[CaseDef], Tree)] } - /** The API that all tries support */ + /** The API that all tries support + * @group API + */ trait TryApi extends TermTreeApi { this: Try => /** The protected block. */ val block: Tree @@ -1282,43 +1531,56 @@ trait Trees { self: Universe => val finalizer: Tree } - /** Throw expression */ + /** Throw expression + * @group Trees + * @template + */ type Throw >: Null <: TermTree with ThrowApi /** A tag that preserves the identity of the `Throw` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ThrowTag: ClassTag[Throw] - /** The constructor/deconstructor for `Throw` instances. */ + /** The constructor/deconstructor for `Throw` instances. + * @group Extractors + */ val Throw: ThrowExtractor /** An extractor class to create and pattern match with syntax `Throw(expr)`. * This AST node corresponds to the following Scala code: * * `throw` expr + * @group Extractors */ abstract class ThrowExtractor { def apply(expr: Tree): Throw def unapply(throw_ : Throw): Option[Tree] } - /** The API that all tries support */ + /** The API that all tries support + * @group API + */ trait ThrowApi extends TermTreeApi { this: Throw => /** The thrown expression. */ val expr: Tree } /** Object instantiation + * @group Trees + * @template */ type New >: Null <: TermTree with NewApi /** A tag that preserves the identity of the `New` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val NewTag: ClassTag[New] /** The constructor/deconstructor for `New` instances. + * @group Extractors */ val New: NewExtractor @@ -1330,6 +1592,7 @@ trait Trees { self: Universe => * This node always occurs in the following context: * * (`new` tpt).[targs](args) + * @group Extractors */ abstract class NewExtractor { /** A user level `new`. @@ -1341,7 +1604,9 @@ trait Trees { self: Universe => def unapply(new_ : New): Option[Tree] } - /** The API that all news support */ + /** The API that all news support + * @group API + */ trait NewApi extends TermTreeApi { this: New => /** The tree that represents the type being instantiated. * See the example for [[scala.reflect.api.Trees#NewExtractor]]. @@ -1349,28 +1614,37 @@ trait Trees { self: Universe => val tpt: Tree } - /** Type annotation, eliminated by compiler phase cleanup */ + /** Type annotation, eliminated by compiler phase cleanup + * @group Trees + * @template + */ type Typed >: Null <: TermTree with TypedApi /** A tag that preserves the identity of the `Typed` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TypedTag: ClassTag[Typed] - /** The constructor/deconstructor for `Typed` instances. */ + /** The constructor/deconstructor for `Typed` instances. + * @group Extractors + */ val Typed: TypedExtractor /** An extractor class to create and pattern match with syntax `Typed(expr, tpt)`. * This AST node corresponds to the following Scala code: * * expr: tpt + * @group Extractors */ abstract class TypedExtractor { def apply(expr: Tree, tpt: Tree): Typed def unapply(typed: Typed): Option[(Tree, Tree)] } - /** The API that all typeds support */ + /** The API that all typeds support + * @group API + */ trait TypedApi extends TermTreeApi { this: Typed => /** The expression being ascribed with the type. */ val expr: Tree @@ -1380,15 +1654,20 @@ trait Trees { self: Universe => } /** Common base class for Apply and TypeApply. + * @group Trees + * @template */ type GenericApply >: Null <: TermTree with GenericApplyApi /** A tag that preserves the identity of the `GenericApply` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val GenericApplyTag: ClassTag[GenericApply] - /** The API that all applies support */ + /** The API that all applies support + * @group API + */ trait GenericApplyApi extends TermTreeApi { this: GenericApply => /** The target of the application. */ val fun: Tree @@ -1401,40 +1680,55 @@ trait Trees { self: Universe => * but I can't find that explicitly stated anywhere. Unless your last name * is odersky, you should probably treat it as true. */ - /** Explicit type application. */ + /** Explicit type application. + * @group Trees + * @template + */ type TypeApply >: Null <: GenericApply with TypeApplyApi /** A tag that preserves the identity of the `TypeApply` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TypeApplyTag: ClassTag[TypeApply] - /** The constructor/deconstructor for `TypeApply` instances. */ + /** The constructor/deconstructor for `TypeApply` instances. + * @group Extractors + */ val TypeApply: TypeApplyExtractor /** An extractor class to create and pattern match with syntax `TypeApply(fun, args)`. * This AST node corresponds to the following Scala code: * * fun[args] + * @group Extractors */ abstract class TypeApplyExtractor { def apply(fun: Tree, args: List[Tree]): TypeApply def unapply(typeApply: TypeApply): Option[(Tree, List[Tree])] } - /** The API that all type applies support */ + /** The API that all type applies support + * @group API + */ trait TypeApplyApi extends GenericApplyApi { this: TypeApply => } - /** Value application */ + /** Value application + * @group Trees + * @template + */ type Apply >: Null <: GenericApply with ApplyApi /** A tag that preserves the identity of the `Apply` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ApplyTag: ClassTag[Apply] - /** The constructor/deconstructor for `Apply` instances. */ + /** The constructor/deconstructor for `Apply` instances. + * @group Extractors + */ val Apply: ApplyExtractor /** An extractor class to create and pattern match with syntax `Apply(fun, args)`. @@ -1449,27 +1743,35 @@ trait Trees { self: Universe => * Is expressed as: * * Apply(TypeApply(fun, targs), args) + * @group Extractors */ abstract class ApplyExtractor { def apply(fun: Tree, args: List[Tree]): Apply def unapply(apply: Apply): Option[(Tree, List[Tree])] } - /** The API that all applies support */ + /** The API that all applies support + * @group API + */ trait ApplyApi extends GenericApplyApi { this: Apply => } /** Super reference, where `qual` is the corresponding `this` reference. * A super reference `C.super[M]` is represented as `Super(This(C), M)`. + * @group Trees + * @template */ type Super >: Null <: TermTree with SuperApi /** A tag that preserves the identity of the `Super` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val SuperTag: ClassTag[Super] - /** The constructor/deconstructor for `Super` instances. */ + /** The constructor/deconstructor for `Super` instances. + * @group Extractors + */ val Super: SuperExtractor /** An extractor class to create and pattern match with syntax `Super(qual, mix)`. @@ -1485,13 +1787,16 @@ trait Trees { self: Universe => * * The symbol of a Super is the class _from_ which the super reference is made. * For instance in C.super(...), it would be C. + * @group Extractors */ abstract class SuperExtractor { def apply(qual: Tree, mix: TypeName): Super def unapply(super_ : Super): Option[(Tree, TypeName)] } - /** The API that all supers support */ + /** The API that all supers support + * @group API + */ trait SuperApi extends TermTreeApi { this: Super => /** The qualifier of the `super` expression. * See the example for [[scala.reflect.api.Trees#SuperExtractor]]. @@ -1504,15 +1809,21 @@ trait Trees { self: Universe => val mix: TypeName } - /** Self reference */ + /** Self reference + * @group Trees + * @template + */ type This >: Null <: TermTree with SymTree with ThisApi /** A tag that preserves the identity of the `This` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ThisTag: ClassTag[This] - /** The constructor/deconstructor for `This` instances. */ + /** The constructor/deconstructor for `This` instances. + * @group Extractors + */ val This: ThisExtractor /** An extractor class to create and pattern match with syntax `This(qual)`. @@ -1522,13 +1833,16 @@ 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. + * @group Extractors */ abstract class ThisExtractor { def apply(qual: TypeName): This def unapply(this_ : This): Option[TypeName] } - /** The API that all thises support */ + /** The API that all thises support + * @group API + */ trait ThisApi extends TermTreeApi with SymTreeApi { this: This => /** The qualifier of the `this` expression. * For an unqualified `this` refers to the enclosing class. @@ -1536,28 +1850,37 @@ trait Trees { self: Universe => val qual: TypeName } - /** A member selection . */ + /** A member selection . + * @group Trees + * @template + */ type Select >: Null <: RefTree with SelectApi /** A tag that preserves the identity of the `Select` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val SelectTag: ClassTag[Select] - /** The constructor/deconstructor for `Select` instances. */ + /** The constructor/deconstructor for `Select` instances. + * @group Extractors + */ val Select: SelectExtractor /** An extractor class to create and pattern match with syntax `Select(qual, name)`. * This AST node corresponds to the following Scala code: * * qualifier.selector + * @group Extractors */ abstract class SelectExtractor { def apply(qualifier: Tree, name: Name): Select def unapply(select: Select): Option[(Tree, Name)] } - /** The API that all selects support */ + /** The API that all selects support + * @group API + */ trait SelectApi extends RefTreeApi { this: Select => /** @inheritdoc */ val qualifier: Tree @@ -1567,15 +1890,20 @@ trait Trees { self: Universe => } /** A reference to identifier `name`. + * @group Trees + * @template */ type Ident >: Null <: RefTree with IdentApi /** A tag that preserves the identity of the `Ident` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val IdentTag: ClassTag[Ident] - /** The constructor/deconstructor for `Ident` instances. */ + /** The constructor/deconstructor for `Ident` instances. + * @group Extractors + */ val Ident: IdentExtractor /** An extractor class to create and pattern match with syntax `Ident(qual, name)`. @@ -1585,33 +1913,42 @@ trait Trees { self: Universe => * * Type checker converts idents that refer to enclosing fields or methods to selects. * For example, name ==> this.name + * @group Extractors */ abstract class IdentExtractor { def apply(name: Name): Ident def unapply(ident: Ident): Option[Name] } - /** The API that all idents support */ + /** The API that all idents support + * @group API + */ trait IdentApi extends RefTreeApi { this: Ident => /** @inheritdoc */ val name: Name } /** Marks underlying reference to id as boxed. - * @pre id must refer to a captured variable + * + * Precondition:<\b> id must refer to a captured variable * A reference such marked will refer to the boxed entity, no dereferencing * with `.elem` is done on it. * This tree node can be emitted by macros such as reify that call referenceCapturedVariable. * It is eliminated in LambdaLift, where the boxing conversion takes place. + * @group Trees + * @template */ type ReferenceToBoxed >: Null <: TermTree with ReferenceToBoxedApi /** A tag that preserves the identity of the `ReferenceToBoxed` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ReferenceToBoxedTag: ClassTag[ReferenceToBoxed] - /** The constructor/deconstructor for `ReferenceToBoxed` instances. */ + /** The constructor/deconstructor for `ReferenceToBoxed` instances. + * @group Extractors + */ val ReferenceToBoxed: ReferenceToBoxedExtractor /** An extractor class to create and pattern match with syntax `ReferenceToBoxed(ident)`. @@ -1632,40 +1969,52 @@ trait Trees { self: Universe => * Select(Ident(x), "elem") * * If `ReferenceToBoxed` were used instead of Ident, no transformation would be performed. + * @group Extractors */ abstract class ReferenceToBoxedExtractor { def apply(ident: Ident): ReferenceToBoxed def unapply(referenceToBoxed: ReferenceToBoxed): Option[Ident] } - /** The API that all references support */ + /** The API that all references support + * @group API + */ trait ReferenceToBoxedApi extends TermTreeApi { this: ReferenceToBoxed => /** The underlying reference. */ val ident: Tree } - /** Literal */ + /** Literal + * @group Trees + * @template + */ type Literal >: Null <: TermTree with LiteralApi /** A tag that preserves the identity of the `Literal` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val LiteralTag: ClassTag[Literal] - /** The constructor/deconstructor for `Literal` instances. */ + /** The constructor/deconstructor for `Literal` instances. + * @group Extractors + */ val Literal: LiteralExtractor /** An extractor class to create and pattern match with syntax `Literal(value)`. * This AST node corresponds to the following Scala code: * * value + * @group Extractors */ abstract class LiteralExtractor { def apply(value: Constant): Literal def unapply(literal: Literal): Option[Constant] } - /** The API that all literals support */ + /** The API that all literals support + * @group API + */ trait LiteralApi extends TermTreeApi { this: Literal => /** The compile-time constant underlying the literal. */ val value: Constant @@ -1675,15 +2024,20 @@ trait Trees { self: Universe => * annotation ascriptions, annotations on definitions are stored in the Modifiers. * Eliminated by typechecker (typedAnnotated), the annotations are then stored in * an AnnotatedType. + * @group Trees + * @template */ type Annotated >: Null <: AnyRef with Tree with AnnotatedApi /** A tag that preserves the identity of the `Annotated` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val AnnotatedTag: ClassTag[Annotated] - /** The constructor/deconstructor for `Annotated` instances. */ + /** The constructor/deconstructor for `Annotated` instances. + * @group Extractors + */ val Annotated: AnnotatedExtractor /** An extractor class to create and pattern match with syntax `Annotated(annot, arg)`. @@ -1691,13 +2045,16 @@ trait Trees { self: Universe => * * arg @annot // for types * arg: @annot // for exprs + * @group Extractors */ abstract class AnnotatedExtractor { def apply(annot: Tree, arg: Tree): Annotated def unapply(annotated: Annotated): Option[(Tree, Tree)] } - /** The API that all annotateds support */ + /** The API that all annotateds support + * @group API + */ trait AnnotatedApi extends TreeApi { this: Annotated => /** The annotation. */ val annot: Tree @@ -1706,43 +2063,58 @@ trait Trees { self: Universe => val arg: Tree } - /** Singleton type, eliminated by RefCheck */ + /** Singleton type, eliminated by RefCheck + * @group Trees + * @template + */ type SingletonTypeTree >: Null <: TypTree with SingletonTypeTreeApi /** A tag that preserves the identity of the `SingletonTypeTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val SingletonTypeTreeTag: ClassTag[SingletonTypeTree] - /** The constructor/deconstructor for `SingletonTypeTree` instances. */ + /** The constructor/deconstructor for `SingletonTypeTree` instances. + * @group Extractors + */ val SingletonTypeTree: SingletonTypeTreeExtractor /** An extractor class to create and pattern match with syntax `SingletonTypeTree(ref)`. * This AST node corresponds to the following Scala code: * * ref.type + * @group Extractors */ abstract class SingletonTypeTreeExtractor { def apply(ref: Tree): SingletonTypeTree def unapply(singletonTypeTree: SingletonTypeTree): Option[Tree] } - /** The API that all singleton type trees support */ + /** The API that all singleton type trees support + * @group API + */ trait SingletonTypeTreeApi extends TypTreeApi { this: SingletonTypeTree => /** The underlying reference. */ val ref: Tree } - /** Type selection # , eliminated by RefCheck */ + /** Type selection # , eliminated by RefCheck + * @group Trees + * @template + */ // [Eugene++] don't see why we need it, when we have Select type SelectFromTypeTree >: Null <: TypTree with RefTree with SelectFromTypeTreeApi /** A tag that preserves the identity of the `SelectFromTypeTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val SelectFromTypeTreeTag: ClassTag[SelectFromTypeTree] - /** The constructor/deconstructor for `SelectFromTypeTree` instances. */ + /** The constructor/deconstructor for `SelectFromTypeTree` instances. + * @group Extractors + */ val SelectFromTypeTree: SelectFromTypeTreeExtractor /** An extractor class to create and pattern match with syntax `SelectFromTypeTree(qualifier, name)`. @@ -1751,13 +2123,16 @@ trait Trees { self: Universe => * qualifier # selector * * Note: a path-dependent type p.T is expressed as p.type # T + * @group Extractors */ abstract class SelectFromTypeTreeExtractor { def apply(qualifier: Tree, name: TypeName): SelectFromTypeTree def unapply(selectFromTypeTree: SelectFromTypeTree): Option[(Tree, TypeName)] } - /** The API that all selects from type trees support */ + /** The API that all selects from type trees support + * @group API + */ trait SelectFromTypeTreeApi extends TypTreeApi with RefTreeApi { this: SelectFromTypeTree => /** @inheritdoc */ val qualifier: Tree @@ -1766,55 +2141,73 @@ trait Trees { self: Universe => val name: TypeName } - /** Intersection type with ... with { }, eliminated by RefCheck */ + /** Intersection type with ... with { }, eliminated by RefCheck + * @group Trees + * @template + */ type CompoundTypeTree >: Null <: TypTree with CompoundTypeTreeApi /** A tag that preserves the identity of the `CompoundTypeTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val CompoundTypeTreeTag: ClassTag[CompoundTypeTree] - /** The constructor/deconstructor for `CompoundTypeTree` instances. */ + /** The constructor/deconstructor for `CompoundTypeTree` instances. + * @group Extractors + */ val CompoundTypeTree: CompoundTypeTreeExtractor /** An extractor class to create and pattern match with syntax `CompoundTypeTree(templ)`. * This AST node corresponds to the following Scala code: * * parent1 with ... with parentN { refinement } + * @group Extractors */ abstract class CompoundTypeTreeExtractor { def apply(templ: Template): CompoundTypeTree def unapply(compoundTypeTree: CompoundTypeTree): Option[Template] } - /** The API that all compound type trees support */ + /** The API that all compound type trees support + * @group API + */ 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 } - /** Applied type [ ], eliminated by RefCheck */ + /** Applied type [ ], eliminated by RefCheck + * @group Trees + * @template + */ type AppliedTypeTree >: Null <: TypTree with AppliedTypeTreeApi /** A tag that preserves the identity of the `AppliedTypeTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val AppliedTypeTreeTag: ClassTag[AppliedTypeTree] - /** The constructor/deconstructor for `AppliedTypeTree` instances. */ + /** The constructor/deconstructor for `AppliedTypeTree` instances. + * @group Extractors + */ val AppliedTypeTree: AppliedTypeTreeExtractor /** An extractor class to create and pattern match with syntax `AppliedTypeTree(tpt, args)`. * This AST node corresponds to the following Scala code: * * tpt[args] + * @group Extractors */ abstract class AppliedTypeTreeExtractor { def apply(tpt: Tree, args: List[Tree]): AppliedTypeTree def unapply(appliedTypeTree: AppliedTypeTree): Option[(Tree, List[Tree])] } - /** The API that all applied type trees support */ + /** The API that all applied type trees support + * @group API + */ trait AppliedTypeTreeApi extends TypTreeApi { this: AppliedTypeTree => /** The target of the application. */ val tpt: Tree @@ -1823,28 +2216,37 @@ trait Trees { self: Universe => val args: List[Tree] } - /** Document me! */ + /** Type bounds tree node + * @group Trees + * @template + */ type TypeBoundsTree >: Null <: TypTree with TypeBoundsTreeApi /** A tag that preserves the identity of the `TypeBoundsTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TypeBoundsTreeTag: ClassTag[TypeBoundsTree] - /** The constructor/deconstructor for `TypeBoundsTree` instances. */ + /** The constructor/deconstructor for `TypeBoundsTree` instances. + * @group Extractors + */ val TypeBoundsTree: TypeBoundsTreeExtractor /** An extractor class to create and pattern match with syntax `TypeBoundsTree(lo, hi)`. * This AST node corresponds to the following Scala code: * * >: lo <: hi + * @group Extractors */ abstract class TypeBoundsTreeExtractor { def apply(lo: Tree, hi: Tree): TypeBoundsTree def unapply(typeBoundsTree: TypeBoundsTree): Option[(Tree, Tree)] } - /** The API that all type bound trees support */ + /** The API that all type bound trees support + * @group API + */ trait TypeBoundsTreeApi extends TypTreeApi { this: TypeBoundsTree => /** The lower bound. * Is equal to `Ident()` if not specified explicitly. @@ -1857,28 +2259,37 @@ trait Trees { self: Universe => val hi: Tree } - /** TODO Document me! */ + /** Existential type tree node + * @group Trees + * @template + */ type ExistentialTypeTree >: Null <: TypTree with ExistentialTypeTreeApi /** A tag that preserves the identity of the `ExistentialTypeTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ExistentialTypeTreeTag: ClassTag[ExistentialTypeTree] - /** The constructor/deconstructor for `ExistentialTypeTree` instances. */ + /** The constructor/deconstructor for `ExistentialTypeTree` instances. + * @group Extractors + */ val ExistentialTypeTree: ExistentialTypeTreeExtractor /** An extractor class to create and pattern match with syntax `ExistentialTypeTree(tpt, whereClauses)`. * This AST node corresponds to the following Scala code: * * tpt forSome { whereClauses } + * @group Extractors */ abstract class ExistentialTypeTreeExtractor { def apply(tpt: Tree, whereClauses: List[Tree]): ExistentialTypeTree def unapply(existentialTypeTree: ExistentialTypeTree): Option[(Tree, List[Tree])] } - /** The API that all existential type trees support */ + /** The API that all existential type trees support + * @group API + */ trait ExistentialTypeTreeApi extends TypTreeApi { this: ExistentialTypeTree => /** The underlying type of the existential type. */ val tpt: Tree @@ -1888,30 +2299,39 @@ trait Trees { self: Universe => } /** A synthetic tree holding an arbitrary type. Not to be confused with - * with TypTree, the trait for trees that are only used for type trees. - * TypeTree's are inserted in several places, but most notably in - * `RefCheck`, where the arbitrary type trees are all replaced by - * TypeTree's. */ + * with TypTree, the trait for trees that are only used for type trees. + * TypeTree's are inserted in several places, but most notably in + * `RefCheck`, where the arbitrary type trees are all replaced by + * TypeTree's. + * @group Trees + * @template + */ type TypeTree >: Null <: TypTree with TypeTreeApi /** A tag that preserves the identity of the `TypeTree` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TypeTreeTag: ClassTag[TypeTree] - /** The constructor/deconstructor for `TypeTree` instances. */ + /** The constructor/deconstructor for `TypeTree` instances. + * @group Extractors + */ val TypeTree: TypeTreeExtractor /** An extractor class to create and pattern match with syntax `TypeTree()`. * This AST node does not have direct correspondence to Scala code, * and is emitted by everywhere when we want to wrap a `Type` in a `Tree`. + * @group Extractors */ abstract class TypeTreeExtractor { def apply(): TypeTree def unapply(typeTree: TypeTree): Boolean } - /** The API that all type trees support */ + /** The API that all type trees support + * @group API + */ trait TypeTreeApi extends TypTreeApi { this: TypeTree => /** The precursor of this tree. * Is equal to `EmptyTree` if this type tree doesn't have precursors. @@ -1923,149 +2343,185 @@ trait Trees { self: Universe => * val _: _ * This is used as a placeholder in the `self` parameter Template if there is * no definition of a self value of self type. + * @group Trees */ val emptyValDef: ValDef // ---------------------- factories ---------------------------------------------- /** A factory method for `ClassDef` nodes. + * @group Factories */ def ClassDef(sym: Symbol, impl: Template): ClassDef /** A factory method for `ModuleDef` nodes. + * @group Factories */ def ModuleDef(sym: Symbol, impl: Template): ModuleDef /** A factory method for `ValDef` nodes. + * @group Factories */ def ValDef(sym: Symbol, rhs: Tree): ValDef /** A factory method for `ValDef` nodes. + * @group Factories */ def ValDef(sym: Symbol): ValDef /** A factory method for `ValDef` nodes. + * @group Factories */ def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef /** A factory method for `ValDef` nodes. + * @group Factories */ def DefDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef /** A factory method for `ValDef` nodes. + * @group Factories */ def DefDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef /** A factory method for `ValDef` nodes. + * @group Factories */ def DefDef(sym: Symbol, rhs: Tree): DefDef /** A factory method for `ValDef` nodes. + * @group Factories */ def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef /** A factory method for `TypeDef` nodes. + * @group Factories */ def TypeDef(sym: Symbol, rhs: Tree): TypeDef /** A factory method for `TypeDef` nodes. + * @group Factories */ def TypeDef(sym: Symbol): TypeDef /** A factory method for `LabelDef` nodes. + * @group Factories */ def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef /** A factory method for `Block` nodes. * Flattens directly nested blocks. + * @group Factories */ def Block(stats: Tree*): Block /** A factory method for `CaseDef` nodes. + * @group Factories */ def CaseDef(pat: Tree, body: Tree): CaseDef /** A factory method for `Bind` nodes. + * @group Factories */ def Bind(sym: Symbol, body: Tree): Bind /** A factory method for `Try` nodes. + * @group Factories */ def Try(body: Tree, cases: (Tree, Tree)*): Try /** A factory method for `Throw` nodes. + * @group Factories */ def Throw(tpe: Type, args: Tree*): Throw /** Factory method for object creation `new tpt(args_1)...(args_n)` * A `New(t, as)` is expanded to: `(new t).(as)` + * @group Factories */ def New(tpt: Tree, argss: List[List[Tree]]): Tree /** 0-1 argument list new, based on a type. + * @group Factories */ def New(tpe: Type, args: Tree*): Tree /** 0-1 argument list new, based on a symbol. + * @group Factories */ def New(sym: Symbol, args: Tree*): Tree /** A factory method for `Apply` nodes. + * @group Factories */ def Apply(sym: Symbol, args: Tree*): Tree /** 0-1 argument list new, based on a type tree. + * @group Factories */ def ApplyConstructor(tpt: Tree, args: List[Tree]): Tree /** A factory method for `Super` nodes. + * @group Factories */ def Super(sym: Symbol, mix: TypeName): Tree /** A factory method for `This` nodes. + * @group Factories */ 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]. + * The string `name` argument is assumed to represent a [[scala.reflect.api.Names#TermName `TermName`]]. + * @group Factories */ def Select(qualifier: Tree, name: String): Select /** A factory method for `Select` nodes. + * @group Factories */ def Select(qualifier: Tree, sym: Symbol): Select /** A factory method for `Ident` nodes. + * @group Factories */ def Ident(name: String): Ident /** A factory method for `Ident` nodes. + * @group Factories */ def Ident(sym: Symbol): Ident /** A factory method for `TypeTree` nodes. + * @group Factories */ def TypeTree(tp: Type): TypeTree // ---------------------- copying ------------------------------------------------ /** The type of standard (lazy) tree copiers. + * @template + * @group Copying */ type TreeCopier <: TreeCopierOps /** The standard (lazy) tree copier. + * @group Copying */ val treeCopy: TreeCopier = newLazyTreeCopier /** Creates a strict tree copier. + * @group Copying */ def newStrictTreeCopier: TreeCopier /** Creates a lazy tree copier. + * @group Copying */ def newLazyTreeCopier: TreeCopier /** The API of a tree copier. + * @group API */ abstract class TreeCopierOps { /** Creates a `ClassDef` node from the given components, having a given `tree` as a prototype. @@ -2277,6 +2733,7 @@ trait Trees { self: Universe => // ---------------------- traversing and transforming ------------------------------ /** A class that implement a default tree traversal strategy: breadth-first component-wise. + * @group Traversal */ class Traverser { protected[scala] var currentOwner: Symbol = rootMirror.RootClass @@ -2315,17 +2772,20 @@ trait Trees { self: Universe => def apply[T <: Tree](tree: T): T = { traverse(tree); tree } } - /** Delegates the traversal strategy to [[scala.reflect.internal.Trees]], + /** Delegates the traversal strategy to `scala.reflect.internal.Trees`, * because pattern matching on abstract types we have here degrades performance. + * @group Traversal */ 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. + * @group Traversal */ 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. + * @group Traversal */ abstract class Transformer { /** The underlying tree copier. */ @@ -2396,25 +2856,32 @@ trait Trees { self: Universe => } } - /** Delegates the transformation strategy to [[scala.reflect.internal.Trees]], + /** Delegates the transformation strategy to `scala.reflect.internal.Trees`, * because pattern matching on abstract types we have here degrades performance. + * @group Traversal */ 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. + * @group Traversal */ protected def xtransform(transformer: Transformer, tree: Tree): Tree = throw new MatchError(tree) - /** The type of tree modifiers. */ + /** The type of tree modifiers. + * @group Traversal + */ type Modifiers >: Null <: AnyRef with ModifiersApi /** A tag that preserves the identity of the `Modifiers` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Traversal */ implicit val ModifiersTag: ClassTag[Modifiers] - /** The API that all Modifiers support */ + /** The API that all Modifiers support + * @group API + */ abstract class ModifiersApi { /** The underlying flags of the enclosing definition. * Is equal to `NoFlags` if none are specified explicitly. @@ -2440,23 +2907,32 @@ trait Trees { self: Universe => Modifiers(flags, privateWithin, f(annotations)) } - /** The constructor/deconstructor for `Modifiers` instances. */ + /** The constructor/deconstructor for `Modifiers` instances. + * @group Traversal + */ 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. + * @group Traversal */ 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. */ + /** The factory for `Modifiers` instances. + * @group Traversal + */ def Modifiers(flags: FlagSet, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List()) - /** The factory for `Modifiers` instances. */ + /** The factory for `Modifiers` instances. + * @group Traversal + */ def Modifiers(flags: FlagSet): Modifiers = Modifiers(flags, tpnme.EMPTY) - /** An empty `Modifiers` object: no flags, empty visibility annotation and no Scala annotations. */ + /** An empty `Modifiers` object: no flags, empty visibility annotation and no Scala annotations. + * @group Traversal + */ lazy val NoMods = Modifiers() } diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala index 0b1d3b8172..9d66a9e236 100644 --- a/src/reflect/scala/reflect/api/TypeTags.scala +++ b/src/reflect/scala/reflect/api/TypeTags.scala @@ -58,14 +58,14 @@ import scala.language.implicitConversions * TypeTag allows unbound type arguments for which type tags are available: * {{{ * scala> def foo3[T:TypeTag] = firstTypeArg( implicitly[TypeTag[Container[T]]] ) - * foo3: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.Type + * foo3: [T](implicit evidence\$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.Type * scala> foo3[Person] * res1: reflect.runtime.universe.Type = Person * }}} * WeakTypeTag contains concrete type arguments if available via existing tags: * {{{ * scala> def foo4[T:WeakTypeTag] = firstTypeArg( implicitly[WeakTypeTag[Container[T]]] ) - * foo4: [T](implicit evidence$1: reflect.runtime.universe.WeakTypeTag[T])reflect.runtime.universe.Type + * foo4: [T](implicit evidence\$1: reflect.runtime.universe.WeakTypeTag[T])reflect.runtime.universe.Type * scala> foo4[Person] * res1: reflect.runtime.universe.Type = Person * }}} @@ -141,6 +141,7 @@ import scala.language.implicitConversions * has been created to track the implementation of this feature. * * @see [[scala.reflect.ClassTag]], [[scala.reflect.api.Universe#TypeTag]], [[scala.reflect.api.Universe#WeakTypeTag]] + * @group TypeTags Type Tags */ trait TypeTags { self: Universe => @@ -157,6 +158,7 @@ trait TypeTags { self: Universe => * [[scala.reflect.api.Universe#TypeTag]] instead, which statically guarantees this property. * * @see [[scala.reflect.api.TypeTags]] + * @group TypeTags */ @annotation.implicitNotFound(msg = "No WeakTypeTag available for ${T}") trait WeakTypeTag[T] extends Equals with Serializable { @@ -193,6 +195,7 @@ trait TypeTags { self: Universe => /** * Type tags corresponding to primitive types and constructor/extractor for WeakTypeTags. + * @group TypeTags */ object WeakTypeTag { val Byte : WeakTypeTag[scala.Byte] = TypeTag.Byte @@ -235,6 +238,7 @@ trait TypeTags { self: Universe => def unapply[T](ttag: WeakTypeTag[T]): Option[Type] = Some(ttag.tpe) } + /* @group TypeTags */ private class WeakTypeTagImpl[T](val mirror: Mirror, val tpec: TypeCreator) extends WeakTypeTag[T] { lazy val tpe: Type = tpec(mirror) def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # WeakTypeTag[T] = { @@ -250,6 +254,7 @@ trait TypeTags { self: Universe => * unresolved type parameters or abstract types. * * @see [[scala.reflect.api.TypeTags]] + * @group TypeTags */ @annotation.implicitNotFound(msg = "No TypeTag available for ${T}") trait TypeTag[T] extends WeakTypeTag[T] with Equals with Serializable { @@ -273,6 +278,7 @@ trait TypeTags { self: Universe => /** * Type tags corresponding to primitive types and constructor/extractor for WeakTypeTags. + * @group TypeTags */ object TypeTag { val Byte: TypeTag[scala.Byte] = new PredefTypeTag[scala.Byte] (ByteTpe, _.TypeTag.Byte) @@ -314,6 +320,7 @@ trait TypeTags { self: Universe => def unapply[T](ttag: TypeTag[T]): Option[Type] = Some(ttag.tpe) } + /* @group TypeTags */ private class TypeTagImpl[T](mirror: Mirror, tpec: TypeCreator) extends WeakTypeTagImpl[T](mirror, tpec) with TypeTag[T] { override def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # TypeTag[T] = { val otherMirror1 = otherMirror.asInstanceOf[scala.reflect.api.Mirror[otherMirror.universe.type]] @@ -322,12 +329,14 @@ trait TypeTags { self: Universe => private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true) } + /* @group TypeTags */ private class PredefTypeCreator[T](copyIn: Universe => Universe#TypeTag[T]) extends TypeCreator { def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type = { copyIn(m.universe).asInstanceOf[U # TypeTag[T]].tpe } } + /* @group TypeTags */ private class PredefTypeTag[T](_tpe: Type, copyIn: Universe => Universe#TypeTag[T]) extends TypeTagImpl[T](rootMirror, new PredefTypeCreator(copyIn)) { override lazy val tpe: Type = _tpe private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true) @@ -335,22 +344,26 @@ trait TypeTags { self: Universe => /** * Shortcut for `implicitly[WeakTypeTag[T]]` + * @group TypeTags */ def weakTypeTag[T](implicit attag: WeakTypeTag[T]) = attag /** * Shortcut for `implicitly[TypeTag[T]]` + * @group TypeTags */ def typeTag[T](implicit ttag: TypeTag[T]) = ttag // big thanks to Viktor Klang for this brilliant idea! /** * Shortcut for `implicitly[WeakTypeTag[T]].tpe` + * @group TypeTags */ def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = attag.tpe /** * Shortcut for `implicitly[TypeTag[T]].tpe` + * @group TypeTags */ def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe } diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala index 164dd2c50d..f4760cf088 100644 --- a/src/reflect/scala/reflect/api/Types.scala +++ b/src/reflect/scala/reflect/api/Types.scala @@ -3,8 +3,8 @@ package api /** A trait that defines types and operations on them. * - * 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, + * 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 === @@ -12,11 +12,11 @@ package api * 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`. - * Method `typeOf` does not work for types with type parameters, such as `typeOf[List[A]]` where `A` is a type variable. + * 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]] + * `typeOf` requires spelling out a type explicitly, but there's also a way to capture types implicitly with the [[scala.reflect.api.TypeTags#TypeTag]] * 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`. @@ -28,15 +28,15 @@ package api * * Common operations on types are querying them for inner declarations or type conformance tests. * - * 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 + * 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` * - * 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 + * 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. + * 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 === @@ -52,8 +52,8 @@ package api * 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> 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 @@ -62,31 +62,39 @@ package api * res1 @ 10139edf: String = I've been called for an x typed as List[Any] * }}} * + * @groupname TypeCreators Types - Creation + * @groupname TypeOps Types - Operations */ trait Types { self: Universe => /** The type of Scala types, and also Scala type signatures. * (No difference is internally made between the two). + * @template + * @group Types */ type Type >: Null <: TypeApi /** A tag that preserves the identity of the `Type` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TypeTagg: ClassTag[Type] /** This constant is used as a special value that indicates that no meaningful type exists. + * @group Types */ val NoType: Type /** This constant is used as a special value denoting the empty prefix in a path dependent type. * For instance `x.type` is represented as `SingleType(NoPrefix, )`, where `` stands for * the symbol for `x`. + * @group Types */ val NoPrefix: Type /** The API of types. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ abstract class TypeApi { /** The term symbol associated with the type, or `NoSymbol` for types @@ -242,11 +250,14 @@ trait Types { self: Universe => * x.type * }}} * as well as [[ConstantType constant types]]. + * @template + * @group Types */ type SingletonType >: Null <: Type /** A tag that preserves the identity of the `SingletonType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val SingletonTypeTag: ClassTag[SingletonType] @@ -255,19 +266,25 @@ trait Types { self: Universe => * {{{ * C.this.type ThisType(C) * }}} + * @template + * @group Types */ type ThisType >: Null <: AnyRef with SingletonType with ThisTypeApi /** A tag that preserves the identity of the `ThisType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ThisTypeTag: ClassTag[ThisType] - /** The constructor/deconstructor for `ThisType` instances. */ + /** The constructor/deconstructor for `ThisType` instances. + * @group Extractors + */ val ThisType: ThisTypeExtractor /** An extractor class to create and pattern match with syntax `ThisType(sym)` * where `sym` is the class prefix of the this type. + * @group Extractors */ abstract class ThisTypeExtractor { /** @@ -279,6 +296,7 @@ trait Types { self: Universe => /** The API that all this types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait ThisTypeApi extends TypeApi { this: ThisType => /** The underlying class symbol. */ @@ -292,20 +310,26 @@ trait Types { self: Universe => * p.x.type SingleType(p.type, x) * x.type SingleType(NoPrefix, x) * }}} + * @template + * @group Types */ type SingleType >: Null <: AnyRef with SingletonType with SingleTypeApi /** A tag that preserves the identity of the `SingleType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val SingleTypeTag: ClassTag[SingleType] - /** The constructor/deconstructor for `SingleType` instances. */ + /** The constructor/deconstructor for `SingleType` instances. + * @group Extractors + */ val SingleType: SingleTypeExtractor /** An extractor class to create and pattern match with syntax `SingleType(pre, sym)` * Here, `pre` is the prefix of the single-type, and `sym` is the stable value symbol * referred to by the single-type. + * @group Extractors */ abstract class SingleTypeExtractor { def apply(pre: Type, sym: Symbol): Type // not SingleTypebecause of implementation details @@ -314,6 +338,7 @@ trait Types { self: Universe => /** The API that all single types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait SingleTypeApi extends TypeApi { this: SingleType => /** The type of the qualifier. */ @@ -330,18 +355,24 @@ trait Types { self: Universe => * Here, `thistpe` is the type of the corresponding this-type. For instance, * in the type arising from C.super, the `thistpe` part would be `ThisType(C)`. * `supertpe` is the type of the super class referred to by the `super`. + * @template + * @group Types */ type SuperType >: Null <: AnyRef with SingletonType with SuperTypeApi /** A tag that preserves the identity of the `SuperType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val SuperTypeTag: ClassTag[SuperType] - /** The constructor/deconstructor for `SuperType` instances. */ + /** The constructor/deconstructor for `SuperType` instances. + * @group Extractors + */ val SuperType: SuperTypeExtractor /** An extractor class to create and pattern match with syntax `SingleType(thistpe, supertpe)` + * @group Extractors */ abstract class SuperTypeExtractor { def apply(thistpe: Type, supertpe: Type): Type // not SuperTypebecause of implementation details @@ -350,6 +381,7 @@ trait Types { self: Universe => /** The API that all super types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait SuperTypeApi extends TypeApi { this: SuperType => /** The type of the qualifier. @@ -368,19 +400,25 @@ trait Types { self: Universe => * 1 ConstantType(Constant(1)) * "abc" ConstantType(Constant("abc")) * }}} + * @template + * @group Types */ type ConstantType >: Null <: AnyRef with SingletonType with ConstantTypeApi /** A tag that preserves the identity of the `ConstantType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ConstantTypeTag: ClassTag[ConstantType] - /** The constructor/deconstructor for `ConstantType` instances. */ + /** The constructor/deconstructor for `ConstantType` instances. + * @group Extractors + */ val ConstantType: ConstantTypeExtractor /** An extractor class to create and pattern match with syntax `ConstantType(constant)` * Here, `constant` is the constant value represented by the type. + * @group Extractors */ abstract class ConstantTypeExtractor { def apply(value: Constant): ConstantType @@ -389,6 +427,7 @@ trait Types { self: Universe => /** The API that all constant types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait ConstantTypeApi extends TypeApi { this: ConstantType => /** The compile-time constant underlying this type. */ @@ -405,21 +444,27 @@ trait Types { self: Universe => * p.C TypeRef(p.type, C, Nil) * C TypeRef(NoPrefix, C, Nil) * }}} + * @template + * @group Types */ type TypeRef >: Null <: AnyRef with Type with TypeRefApi /** A tag that preserves the identity of the `TypeRef` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TypeRefTag: ClassTag[TypeRef] - /** The constructor/deconstructor for `TypeRef` instances. */ + /** The constructor/deconstructor for `TypeRef` instances. + * @group Extractors + */ val TypeRef: TypeRefExtractor /** An extractor class to create and pattern match with syntax `TypeRef(pre, sym, args)` * Here, `pre` is the prefix of the type reference, `sym` is the symbol * referred to by the type reference, and `args` is a possible empty list of * type argumenrts. + * @group Extractors */ abstract class TypeRefExtractor { def apply(pre: Type, sym: Symbol, args: List[Type]): Type // not TypeRefbecause of implementation details @@ -428,6 +473,7 @@ trait Types { self: Universe => /** The API that all type refs support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait TypeRefApi extends TypeApi { this: TypeRef => /** The prefix of the type reference. @@ -445,11 +491,14 @@ trait Types { self: Universe => } /** A subtype of Type representing refined types as well as `ClassInfo` signatures. + * @template + * @group Types */ type CompoundType >: Null <: AnyRef with Type /** A tag that preserves the identity of the `CompoundType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val CompoundTypeTag: ClassTag[CompoundType] @@ -460,20 +509,26 @@ trait Types { self: Universe => * P_1 with ... with P_m RefinedType(List(P_1, ..., P_m), Scope()) * { D_1; ...; D_n} RefinedType(List(AnyRef), Scope(D_1, ..., D_n)) * }}} + * @template + * @group Types */ type RefinedType >: Null <: AnyRef with CompoundType with RefinedTypeApi /** A tag that preserves the identity of the `RefinedType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val RefinedTypeTag: ClassTag[RefinedType] - /** The constructor/deconstructor for `RefinedType` instances. */ + /** The constructor/deconstructor for `RefinedType` instances. + * @group Extractors + */ val RefinedType: RefinedTypeExtractor /** An extractor class to create and pattern match with syntax `RefinedType(parents, decls)` * Here, `parents` is the list of parent types of the class, and `decls` is the scope * containing all declarations in the class. + * @group Extractors */ abstract class RefinedTypeExtractor { def apply(parents: List[Type], decls: Scope): RefinedType @@ -487,6 +542,7 @@ trait Types { self: Universe => /** The API that all refined types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait RefinedTypeApi extends TypeApi { this: RefinedType => /** The superclasses of the type. */ @@ -505,21 +561,27 @@ trait Types { self: Universe => * {{{ * ClassInfo(List(P_1, ..., P_m), Scope(D_1, ..., D_n), C) * }}} + * @template + * @group Types */ type ClassInfoType >: Null <: AnyRef with CompoundType with ClassInfoTypeApi /** A tag that preserves the identity of the `ClassInfoType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ClassInfoTypeTag: ClassTag[ClassInfoType] - /** The constructor/deconstructor for `ClassInfoType` instances. */ + /** The constructor/deconstructor for `ClassInfoType` instances. + * @group Extractors + */ val ClassInfoType: ClassInfoTypeExtractor /** An extractor class to create and pattern match with syntax `ClassInfo(parents, decls, clazz)` * Here, `parents` is the list of parent types of the class, `decls` is the scope * containing all declarations in the class, and `clazz` is the symbol of the class * itself. + * @group Extractors */ abstract class ClassInfoTypeExtractor { def apply(parents: List[Type], decls: Scope, typeSymbol: Symbol): ClassInfoType @@ -528,6 +590,7 @@ trait Types { self: Universe => /** The API that all class info types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait ClassInfoTypeApi extends TypeApi { this: ClassInfoType => /** The superclasses of the class type. */ @@ -541,15 +604,20 @@ trait Types { self: Universe => } /** The `MethodType` type signature is used to indicate parameters and result type of a method + * @template + * @group Types */ type MethodType >: Null <: AnyRef with Type with MethodTypeApi /** A tag that preserves the identity of the `MethodType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val MethodTypeTag: ClassTag[MethodType] - /** The constructor/deconstructor for `MethodType` instances. */ + /** The constructor/deconstructor for `MethodType` instances. + * @group Extractors + */ val MethodType: MethodTypeExtractor /** An extractor class to create and pattern match with syntax `MethodType(params, respte)` @@ -565,6 +633,7 @@ trait Types { self: Universe => * def f: Int * }}} * its type is a `NullaryMethodType`. + * @group Extractors */ abstract class MethodTypeExtractor { def apply(params: List[Symbol], resultType: Type): MethodType @@ -573,6 +642,7 @@ trait Types { self: Universe => /** The API that all method types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait MethodTypeApi extends TypeApi { this: MethodType => /** The symbols that correspond to the parameters of the method. */ @@ -584,19 +654,25 @@ trait Types { self: Universe => /** The `NullaryMethodType` type signature is used for parameterless methods * with declarations of the form `def foo: T` + * @template + * @group Types */ type NullaryMethodType >: Null <: AnyRef with Type with NullaryMethodTypeApi /** A tag that preserves the identity of the `NullaryMethodType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val NullaryMethodTypeTag: ClassTag[NullaryMethodType] - /** The constructor/deconstructor for `NullaryMethodType` instances. */ + /** The constructor/deconstructor for `NullaryMethodType` instances. + * @group Extractors + */ val NullaryMethodType: NullaryMethodTypeExtractor /** An extractor class to create and pattern match with syntax `NullaryMethodType(resultType)`. * Here, `resultType` is the result type of the parameterless method. + * @group Extractors */ abstract class NullaryMethodTypeExtractor { def apply(resultType: Type): NullaryMethodType @@ -605,6 +681,7 @@ trait Types { self: Universe => /** The API that all nullary method types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait NullaryMethodTypeApi extends TypeApi { this: NullaryMethodType => /** The result type of the method. */ @@ -613,20 +690,26 @@ trait Types { self: Universe => /** The `PolyType` type signature is used for polymorphic methods * that have at least one type parameter. + * @template + * @group Types */ type PolyType >: Null <: AnyRef with Type with PolyTypeApi /** A tag that preserves the identity of the `PolyType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val PolyTypeTag: ClassTag[PolyType] - /** The constructor/deconstructor for `PolyType` instances. */ + /** The constructor/deconstructor for `PolyType` instances. + * @group Extractors + */ val PolyType: PolyTypeExtractor /** An extractor class to create and pattern match with syntax `PolyType(typeParams, resultType)`. * Here, `typeParams` are the type parameters of the method and `resultType` * is the type signature following the type parameters. + * @group Extractors */ abstract class PolyTypeExtractor { def apply(typeParams: List[Symbol], resultType: Type): PolyType @@ -635,6 +718,7 @@ trait Types { self: Universe => /** The API that all polymorphic types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait PolyTypeApi extends TypeApi { this: PolyType => /** The symbols corresponding to the type parameters. */ @@ -646,21 +730,27 @@ trait Types { self: Universe => /** The `ExistentialType` type signature is used for existential types and * wildcard types. + * @template + * @group Types */ type ExistentialType >: Null <: AnyRef with Type with ExistentialTypeApi /** A tag that preserves the identity of the `ExistentialType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ExistentialTypeTag: ClassTag[ExistentialType] - /** The constructor/deconstructor for `ExistentialType` instances. */ + /** The constructor/deconstructor for `ExistentialType` instances. + * @group Extractors + */ val ExistentialType: ExistentialTypeExtractor /** An extractor class to create and pattern match with syntax * `ExistentialType(quantified, underlying)`. * Here, `quantified` are the type variables bound by the existential type and `underlying` * is the type that's existentially quantified. + * @group Extractors */ abstract class ExistentialTypeExtractor { def apply(quantified: List[Symbol], underlying: Type): ExistentialType @@ -669,6 +759,7 @@ trait Types { self: Universe => /** The API that all existential types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait ExistentialTypeApi extends TypeApi { this: ExistentialType => /** The symbols corresponding to the `forSome` clauses of the existential type. */ @@ -680,21 +771,27 @@ trait Types { self: Universe => /** The `AnnotatedType` type signature is used for annotated types of the * for ` @`. + * @template + * @group Types */ type AnnotatedType >: Null <: AnyRef with Type with AnnotatedTypeApi /** A tag that preserves the identity of the `AnnotatedType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val AnnotatedTypeTag: ClassTag[AnnotatedType] - /** The constructor/deconstructor for `AnnotatedType` instances. */ + /** The constructor/deconstructor for `AnnotatedType` instances. + * @group Extractors + */ val AnnotatedType: AnnotatedTypeExtractor /** An extractor class to create and pattern match with syntax * `AnnotatedType(annotations, underlying, selfsym)`. * Here, `annotations` are the annotations decorating the underlying type `underlying`. * `selfSym` is a symbol representing the annotated type itself. + * @group Extractors */ abstract class AnnotatedTypeExtractor { def apply(annotations: List[Annotation], underlying: Type, selfsym: Symbol): AnnotatedType @@ -703,6 +800,7 @@ trait Types { self: Universe => /** The API that all annotated types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait AnnotatedTypeApi extends TypeApi { this: AnnotatedType => /** The annotations. */ @@ -724,20 +822,26 @@ trait Types { self: Universe => * T >: L TypeBounds(L, Any) * T <: U TypeBounds(Nothing, U) * }}} + * @template + * @group Types */ type TypeBounds >: Null <: AnyRef with Type with TypeBoundsApi /** A tag that preserves the identity of the `TypeBounds` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val TypeBoundsTag: ClassTag[TypeBounds] - /** The constructor/deconstructor for `TypeBounds` instances. */ + /** The constructor/deconstructor for `TypeBounds` instances. + * @group Extractors + */ val TypeBounds: TypeBoundsExtractor /** An extractor class to create and pattern match with syntax `TypeBound(lower, upper)` * Here, `lower` is the lower bound of the `TypeBounds` pair, and `upper` is * the upper bound. + * @group Extractors */ abstract class TypeBoundsExtractor { def apply(lo: Type, hi: Type): TypeBounds @@ -746,6 +850,7 @@ trait Types { self: Universe => /** The API that all type bounds support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait TypeBoundsApi extends TypeApi { this: TypeBounds => /** The lower bound. @@ -761,6 +866,7 @@ trait Types { self: Universe => /** An object representing an unknown type, used during type inference. * If you see WildcardType outside of inference it is almost certainly a bug. + * @group Types */ val WildcardType: Type @@ -773,19 +879,25 @@ trait Types { self: Universe => * the name of a method in the converted type, a HasMethodMatching * type is created: a MethodType with parameters typed as * BoundedWildcardTypes. + * @template + * @group Types */ type BoundedWildcardType >: Null <: AnyRef with Type with BoundedWildcardTypeApi /** A tag that preserves the identity of the `BoundedWildcardType` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val BoundedWildcardTypeTag: ClassTag[BoundedWildcardType] - /** The constructor/deconstructor for `BoundedWildcardType` instances. */ + /** The constructor/deconstructor for `BoundedWildcardType` instances. + * @group Extractors + */ val BoundedWildcardType: BoundedWildcardTypeExtractor /** An extractor class to create and pattern match with syntax `BoundedWildcardTypeExtractor(bounds)` * with `bounds` denoting the type bounds. + * @group Extractors */ abstract class BoundedWildcardTypeExtractor { def apply(bounds: TypeBounds): BoundedWildcardType @@ -794,37 +906,50 @@ trait Types { self: Universe => /** The API that all this types support. * The main source of information about types is the [[scala.reflect.api.Types]] page. + * @group API */ trait BoundedWildcardTypeApi extends TypeApi { this: BoundedWildcardType => /** Type bounds for the wildcard type. */ val bounds: TypeBounds } - /** The least upper bound of a list of types, as determined by `<:<`. */ + /** The least upper bound of a list of types, as determined by `<:<`. + * @group TypeOps + */ def lub(xs: List[Type]): Type - /** The greatest lower bound of a list of types, as determined by `<:<`. */ + /** The greatest lower bound of a list of types, as determined by `<:<`. + * @group TypeOps + */ def glb(ts: List[Type]): Type // Creators --------------------------------------------------------------- // too useful and too non-trivial to be left out of public API - /** The canonical creator for single-types */ + /** The canonical creator for single-types + * @group TypeCreators + */ def singleType(pre: Type, sym: Symbol): Type - /** the canonical creator for a refined type with a given scope */ + /** the canonical creator for a refined type with a given scope + * @group TypeCreators + */ def refinedType(parents: List[Type], owner: Symbol, decls: Scope, pos: Position): Type /** The canonical creator for a refined type with an initially empty scope. + * @group TypeCreators */ def refinedType(parents: List[Type], owner: Symbol): Type /** The canonical creator for typerefs + * @group TypeCreators */ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type /** A creator for intersection type where intersections of a single type are - * replaced by the type itself. */ + * replaced by the type itself. + * @group TypeCreators + */ def intersectionType(tps: List[Type]): Type /** A creator for intersection type where intersections of a single type are @@ -832,15 +957,19 @@ trait Types { self: Universe => * * !!! Repeated parent classes are not merged - is this a bug in the * comment or in the code? + * @group TypeCreators */ def intersectionType(tps: List[Type], owner: Symbol): Type - /** A creator for type applications */ + /** A creator for type applications + * @group Types + */ def appliedType(tycon: Type, args: List[Type]): Type /** A creator for type parameterizations that strips empty type parameter lists. * Use this factory method to indicate the type has kind * (it's a polymorphic value) * until we start tracking explicit kinds equivalent to typeFun (except that the latter requires tparams nonEmpty). + * @group Types */ def polyType(tparams: List[Symbol], tpe: Type): Type @@ -861,6 +990,7 @@ trait Types { self: Universe => * The abstraction drops all type parameters that are not directly or * indirectly referenced by type `tpe1`. If there are no remaining type * parameters, simply returns result type `tpe`. + * @group TypeCreators */ def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type } diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index 207dc98a91..c047d1641e 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -70,6 +70,7 @@ package api * 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`. + * @groupprio Universe -1 */ abstract class Universe extends Symbols with Types @@ -96,8 +97,8 @@ abstract class Universe extends Symbols * * {{{ * val five = reify{ 5 } // Literal(Constant(5)) - * reify{ 2 + 4 } // Apply( Select( Literal(Constant(2)), newTermName("$plus")), List( Literal(Constant(4)) ) ) - * reify{ five.splice + 4 } // Apply( Select( Literal(Constant(5)), newTermName("$plus")), List( Literal(Constant(4)) ) ) + * reify{ 2 + 4 } // Apply( Select( Literal(Constant(2)), newTermName("\$plus")), List( Literal(Constant(4)) ) ) + * reify{ five.splice + 4 } // Apply( Select( Literal(Constant(5)), newTermName("\$plus")), List( Literal(Constant(4)) ) ) * }}} * * The produced tree is path dependent on the Universe `reify` was called from. @@ -128,7 +129,7 @@ abstract class Universe extends Symbols * * {{{ * val two = mirror.reify(2) // Literal(Constant(2)) - * val four = mirror.reify(two.splice + two.splice) // Apply(Select(two.tree, newTermName("$plus")), List(two.tree)) + * val four = mirror.reify(two.splice + two.splice) // Apply(Select(two.tree, newTermName("\$plus")), List(two.tree)) * * def macroImpl[T](c: Context) = { * ... @@ -145,6 +146,7 @@ abstract class Universe extends Symbols * locally defined entities get erased and replaced with their original trees * - Free variables are detected and wrapped in symbols of the type `FreeTermSymbol` or `FreeTypeSymbol` * - Mutable variables that are accessed from a local function are wrapped in refs + * @group Universe */ // implementation is hardwired to `scala.reflect.reify.Taggers` // using the mechanism implemented in `scala.tools.reflect.FastTrack` diff --git a/src/reflect/scala/reflect/macros/Context.scala b/src/reflect/scala/reflect/macros/Context.scala index 1c01bbd5dc..1f6e97adbc 100644 --- a/src/reflect/scala/reflect/macros/Context.scala +++ b/src/reflect/scala/reflect/macros/Context.scala @@ -73,7 +73,7 @@ trait Context extends Aliases * x: Coll[String] = ... * * scala> x.filter(_ != "") - * $line11.$read.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.x + * \$line11.\$read.\$iw.\$iw.\$iw.\$iw.\$iw.\$iw.\$iw.\$iw.\$iw.\$iw.\$iw.\$iw.x * res1 @ 35563b4b: x.type = ... * }}} * diff --git a/src/reflect/scala/reflect/macros/Evals.scala b/src/reflect/scala/reflect/macros/Evals.scala index 69885c219c..6aab3d5b02 100644 --- a/src/reflect/scala/reflect/macros/Evals.scala +++ b/src/reflect/scala/reflect/macros/Evals.scala @@ -19,7 +19,7 @@ trait Evals { * {{{ * 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)}") + * | println(s"compile-time value is: \${c.eval(x1)}") * | x * | } * impl: (c: Context)(x: c.Expr[String])c.Expr[String] diff --git a/src/reflect/scala/reflect/macros/Parsers.scala b/src/reflect/scala/reflect/macros/Parsers.scala index daf490c275..bf73c36b1b 100644 --- a/src/reflect/scala/reflect/macros/Parsers.scala +++ b/src/reflect/scala/reflect/macros/Parsers.scala @@ -14,6 +14,6 @@ trait Parsers { def parse(code: String): Tree } -/** Indicates an error during [[scala.reflect.macros.Parsers#Parse]]. +/** Indicates an error during [[scala.reflect.macros.Parsers#parse]]. */ case class ParseException(val pos: scala.reflect.api.Position, val msg: String) extends Exception(msg) diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index f270671fb1..7c308fe4bf 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -6,14 +6,19 @@ package macros * 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`. + * @groupname Macros Macro Specific Additions + * @groupprio Macros -1 */ abstract class Universe extends scala.reflect.api.Universe { - /** A factory that encapsulates common tree-building functions. */ + /** A factory that encapsulates common tree-building functions. + * @group Macros + */ 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. + * @group Macros */ trait AttachableApi { /** The attachment of the reflection artifact. */ @@ -33,9 +38,14 @@ abstract class Universe extends scala.reflect.api.Universe { // Symbol extensions --------------------------------------------------------------- + /** The `Symbol` API is extended for macros: See [[SymbolContextApi]] for details. + * + * @group Macros + */ override type Symbol >: Null <: SymbolContextApi /** The extended API of symbols that's supported in macro context universes + * @group API */ trait SymbolContextApi extends SymbolApi with AttachableApi { self: Symbol => @@ -81,9 +91,14 @@ abstract class Universe extends scala.reflect.api.Universe { // Tree extensions --------------------------------------------------------------- + /** The `Tree` API is extended for macros: See [[TreeContextApi]] for details. + * + * @group Macros + */ override type Tree >: Null <: TreeContextApi /** The extended API of trees that's supported in macro context universes + * @group API */ trait TreeContextApi extends TreeApi with AttachableApi { self: Tree => @@ -102,7 +117,7 @@ abstract class Universe extends scala.reflect.api.Universe { /** Like `setType`, but if this is a previously empty TypeTree that * fact is remembered so that resetAllAttrs will snap back. * - * @PP: Attempting to elaborate on the above, I find: If defineType + * \@PP: Attempting to elaborate on the above, I find: If defineType * is called on a TypeTree whose type field is null or NoType, * this is recorded as "wasEmpty = true". That value is used in * ResetAttrsTraverser, which nulls out the type field of TypeTrees @@ -129,6 +144,7 @@ abstract class Universe extends scala.reflect.api.Universe { override type SymTree >: Null <: Tree with SymTreeContextApi /** The extended API of sym trees that's supported in macro context universes + * @group API */ trait SymTreeContextApi extends SymTreeApi { this: SymTree => /** Sets the `symbol` field of the sym tree. */ @@ -139,6 +155,7 @@ abstract class Universe extends scala.reflect.api.Universe { override type TypeTree >: Null <: TypTree with TypeTreeContextApi /** The extended API of sym trees that's supported in macro context universes + * @group API */ trait TypeTreeContextApi extends TypeTreeApi { this: TypeTree => /** Sets the `original` field of the type tree. */ @@ -149,6 +166,7 @@ abstract class Universe extends scala.reflect.api.Universe { override type Ident >: Null <: RefTree with IdentContextApi /** The extended API of idents that's supported in macro context universes + * @group API */ trait IdentContextApi extends IdentApi { this: Ident => /** Was this ident created from a backquoted identifier? */ @@ -156,24 +174,31 @@ abstract class Universe extends scala.reflect.api.Universe { } /** Mark a variable as captured; i.e. force boxing in a *Ref type. + * @group Macros */ def captureVariable(vble: Symbol): Unit /** Mark given identifier as a reference to a captured variable itself * suppressing dereferencing with the `elem` field. + * @group Macros */ def referenceCapturedVariable(vble: Symbol): Tree /** Convert type of a captured variable to *Ref type. + * @group Macros */ def capturedVariableType(vble: Symbol): Type - /** The type of compilation runs. */ + /** The type of compilation runs. + * @template + * @group Macros + */ type Run <: RunContextApi /** Compilation run uniquely identifies current invocation of the compiler * (e.g. can be used to implement per-run caches for macros) and provides access to units of work * of the invocation (currently processed unit of work and the list of all units). + * @group API */ trait RunContextApi { /** Currently processed unit of work (a real or a virtual file). */ @@ -183,11 +208,15 @@ abstract class Universe extends scala.reflect.api.Universe { def units: Iterator[CompilationUnit] } - /** The type of compilation units. */ + /** The type of compilation units. + * @template + * @group Macros + */ type CompilationUnit <: CompilationUnitContextApi /** Compilation unit describes a unit of work of the compilation run. * It provides such information as file name, textual representation of the unit and the underlying AST. + * @group API */ trait CompilationUnitContextApi { /** Source file corresponding to this compilation unit. diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala index 84a307e60e..3a2f04bcf2 100644 --- a/src/reflect/scala/reflect/macros/package.scala +++ b/src/reflect/scala/reflect/macros/package.scala @@ -6,7 +6,7 @@ package scala.reflect * 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. * - * See the [[docs.scala-lang.org/overviews/macros.html Macros Guide]] on how to get started with Scala macros. + * See the [[http://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 -- cgit v1.2.3 From e49ece4fb1c9e7b83624bc96c1d54078ef62c2bc Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Wed, 10 Oct 2012 22:12:23 +0200 Subject: Diagram tweaking blocked by SI-6511 --- src/reflect/scala/reflect/api/Annotations.scala | 2 ++ src/reflect/scala/reflect/api/Constants.scala | 2 ++ src/reflect/scala/reflect/api/JavaUniverse.scala | 2 ++ src/reflect/scala/reflect/api/Mirrors.scala | 2 ++ src/reflect/scala/reflect/api/Names.scala | 5 +++-- src/reflect/scala/reflect/api/Position.scala | 2 +- src/reflect/scala/reflect/api/Positions.scala | 2 ++ src/reflect/scala/reflect/api/Symbols.scala | 4 +++- src/reflect/scala/reflect/api/TagInterop.scala | 5 +++-- src/reflect/scala/reflect/api/Trees.scala | 2 ++ src/reflect/scala/reflect/api/Types.scala | 2 ++ src/reflect/scala/reflect/api/Universe.scala | 2 ++ src/reflect/scala/reflect/macros/Universe.scala | 4 +++- 13 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/reflect/scala/reflect/api/Annotations.scala b/src/reflect/scala/reflect/api/Annotations.scala index a828b254fe..adba0eb8ad 100644 --- a/src/reflect/scala/reflect/api/Annotations.scala +++ b/src/reflect/scala/reflect/api/Annotations.scala @@ -23,6 +23,8 @@ import scala.collection.immutable.ListMap * - literals (primitive and string constants), * - arrays and * - nested annotations. + * + * @contentDiagram */ trait Annotations { self: Universe => diff --git a/src/reflect/scala/reflect/api/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala index 8c532bd4dd..9e0573f0dc 100644 --- a/src/reflect/scala/reflect/api/Constants.scala +++ b/src/reflect/scala/reflect/api/Constants.scala @@ -10,6 +10,8 @@ package api * This trait is the [[scala.reflect.api.Universe reflection API]] component that mirrors constant irreducible expressions * such as `true`, `0` and `classOf[List]`. Constant values appear in the program abstract syntax tree and in annotation parameters * wrapped in [[Constant `Constant`]] case classes. + * + * @contentDiagram hideNodes "*Api" */ trait Constants { self: Universe => diff --git a/src/reflect/scala/reflect/api/JavaUniverse.scala b/src/reflect/scala/reflect/api/JavaUniverse.scala index 0283a75177..f83692034f 100644 --- a/src/reflect/scala/reflect/api/JavaUniverse.scala +++ b/src/reflect/scala/reflect/api/JavaUniverse.scala @@ -8,6 +8,8 @@ package api * * See the [[http://docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for details on how to use runtime reflection. * @groupname JavaUniverse Java Mirrors + * + * @contentDiagram hideNodes "*Api" */ trait JavaUniverse extends Universe with JavaMirrors { self => diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala index bebc9488dd..32cfdf07fb 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -5,6 +5,8 @@ package api * * See the [[http://docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for a description of mirrors * and infomation on getting started with Scala reflection API. + * + * @contentDiagram hideNodes "*Api" */ trait Mirrors { self: Universe => diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index 7b66906499..332c24e542 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -7,14 +7,15 @@ package api * distinguish names of terms (like objects or members) and types. A term and a type of the * same name can co-exist in an object. * - * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]]. - * === Examples === * * To search for the `map` method (which is a term) declared in the `List` class, * use `typeOf[List[_]].member(newTermName("map"))`. To search for a type member, use * newTypeName instead. * + * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]]. + * + * @contentDiagram hideNodes "*Api" */ trait Names { /** An implicit conversion from String to TermName. diff --git a/src/reflect/scala/reflect/api/Position.scala b/src/reflect/scala/reflect/api/Position.scala index d94df00875..3284caf155 100644 --- a/src/reflect/scala/reflect/api/Position.scala +++ b/src/reflect/scala/reflect/api/Position.scala @@ -26,7 +26,7 @@ trait Position extends Attachments { /** Java file corresponding to the source file of this position. * - * The return type is [[scala.reflect.io.AbstractFile]], which belongs to an experimental part of Scala reflection. + * The return type is `scala.reflect.io.AbstractFile`, which belongs to an experimental part of Scala reflection. * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined * and exposed as a part of scala.reflect.api. * diff --git a/src/reflect/scala/reflect/api/Positions.scala b/src/reflect/scala/reflect/api/Positions.scala index ec1cf21c75..8d8a0081cc 100644 --- a/src/reflect/scala/reflect/api/Positions.scala +++ b/src/reflect/scala/reflect/api/Positions.scala @@ -4,6 +4,8 @@ package api /** This trait defines the concept of positions and operations on them. * * @see [[scala.reflect.api.Position]] + * + * @contentDiagram hideNodes "*Api" */ trait Positions { self: Universe => diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index c69d2e1fc2..d59ca561a2 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -18,6 +18,8 @@ package api * @define SYMACCESSORS Class [[Symbol]] defines `isXXX` test methods such as `isPublic` or `isFinal`, `params` and * `returnType` methods for method symbols, `baseClasses` for class symbols and so on. Some of these methods don't * make sense for certain subclasses of `Symbol` and return `NoSymbol`, `Nil` or other empty values. + * + * @contentDiagram hideNodes "*Api" */ trait Symbols { self: Universe => @@ -330,7 +332,7 @@ trait Symbols { self: Universe => /** Source file if this symbol is created during this compilation run, * or a class file if this symbol is loaded from a *.class or *.jar. * - * The return type is [[scala.reflect.io.AbstractFile]], which belongs to an experimental part of Scala reflection. + * The return type is `scala.reflect.io.AbstractFile`, which belongs to an experimental part of Scala reflection. * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined * and exposed as a part of scala.reflect.api. * diff --git a/src/reflect/scala/reflect/api/TagInterop.scala b/src/reflect/scala/reflect/api/TagInterop.scala index b495c3f50c..4e43f59706 100644 --- a/src/reflect/scala/reflect/api/TagInterop.scala +++ b/src/reflect/scala/reflect/api/TagInterop.scala @@ -2,6 +2,7 @@ package scala.reflect package api /** This trait provides type tag <-> manifest interoperability. + * @groupname TagInterop TypeTag and Manifest Interoperability */ trait TagInterop { self: Universe => // TODO `mirror` parameters are now of type `Any`, because I can't make these path-dependent types work @@ -16,7 +17,7 @@ trait TagInterop { self: Universe => * {{{ * typeTagToManifest(scala.reflect.runtime.currentMirror, implicitly[TypeTag[String]]) * }}} - * @group Tags + * @group TagInterop */ 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.") @@ -30,7 +31,7 @@ trait TagInterop { self: Universe => * {{{ * manifestToTypeTag(scala.reflect.runtime.currentMirror, implicitly[Manifest[String]]) * }}} - * @group Tags + * @group TagInterop */ def manifestToTypeTag[T](mirror: Any, manifest: Manifest[T]): Universe#TypeTag[T] = throw new UnsupportedOperationException("This universe does not support manifest -> tag conversions. Use a JavaUniverse, e.g. the scala.reflect.runtime.universe.") diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 1142bb042f..44f5776a57 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -32,6 +32,8 @@ package api * @groupprio Factories 1 * @groupname Copying Tree Copying * @groupprio Copying 1 + * + * @contentDiagram hideNodes "*Api" */ trait Trees { self: Universe => diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala index f4760cf088..2267f21609 100644 --- a/src/reflect/scala/reflect/api/Types.scala +++ b/src/reflect/scala/reflect/api/Types.scala @@ -64,6 +64,8 @@ package api * * @groupname TypeCreators Types - Creation * @groupname TypeOps Types - Operations + * + * @contentDiagram hideNodes "*Api" */ trait Types { self: Universe => diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index c047d1641e..d9be73fde9 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -71,6 +71,8 @@ package api * `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`. * @groupprio Universe -1 + * + * @contentDiagram hideNodes "*Api" */ abstract class Universe extends Symbols with Types diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index 7c308fe4bf..86bc37b4c9 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -8,6 +8,8 @@ package macros * such as `Symbol.deSkolemize` or `Tree.attachments`. * @groupname Macros Macro Specific Additions * @groupprio Macros -1 + * + * @contentDiagram hideNodes "*Api" */ abstract class Universe extends scala.reflect.api.Universe { @@ -224,7 +226,7 @@ abstract class Universe extends scala.reflect.api.Universe { * Exposes information about the file as a part of a real or virtual file system * along with the contents of that file. * - * The return type is [[scala.reflect.io.AbstractFile]], which belongs to an experimental part of Scala reflection. + * The return type is `scala.reflect.io.AbstractFile`, which belongs to an experimental part of Scala reflection. * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined * and exposed as a part of scala.reflect.api. */ -- cgit v1.2.3 From 9945c1f877703855c5e30c09f0341cec0bc3d1e9 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Thu, 11 Oct 2012 04:36:42 +0200 Subject: Forgotten annotation in Annotations --- src/reflect/scala/reflect/api/Annotations.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reflect/scala/reflect/api/Annotations.scala b/src/reflect/scala/reflect/api/Annotations.scala index adba0eb8ad..1e658228f3 100644 --- a/src/reflect/scala/reflect/api/Annotations.scala +++ b/src/reflect/scala/reflect/api/Annotations.scala @@ -24,7 +24,7 @@ import scala.collection.immutable.ListMap * - arrays and * - nested annotations. * - * @contentDiagram + * @contentDiagram hideNodes "*Api" */ trait Annotations { self: Universe => -- cgit v1.2.3 From b55ca84dbc34f3337d4e95df3a045156d71f77d7 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Thu, 11 Oct 2012 05:23:14 +0200 Subject: runtime.JavaUniverse - put ungrouped members at the top --- src/reflect/scala/reflect/api/Position.scala | 1 - src/reflect/scala/reflect/runtime/JavaUniverse.scala | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/reflect/scala/reflect/api/Position.scala b/src/reflect/scala/reflect/api/Position.scala index 3284caf155..fb199bbd69 100644 --- a/src/reflect/scala/reflect/api/Position.scala +++ b/src/reflect/scala/reflect/api/Position.scala @@ -17,7 +17,6 @@ import scala.reflect.macros.Attachments * positions depending on how a symbol or tree node was generated. The guide fully describes compiler-generated positions. * * @groupname Common Commonly used methods - * @groupname default Compiler-specific methods */ trait Position extends Attachments { diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index 87520d406c..dc3cb3cbdc 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -5,7 +5,10 @@ import internal.{SomePhase, NoPhase, Phase, TreeGen} /** 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. + * Should not be instantiated directly, use [[scala.reflect.runtime.universe]] instead. + * + * @contentDiagram hideNodes "*Api" + * @groupprio Ungrouped -5 */ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.SymbolTable { self => -- cgit v1.2.3 From e95a00992599f59f7c74bcc171bb290f859ab848 Mon Sep 17 00:00:00 2001 From: Heather Miller Date: Thu, 11 Oct 2012 20:31:42 +0200 Subject: Adds lots of new documentation for TypeTags, Mirrors, Universes and more Additionally includes improvements, formatting fixes, and link additions and fixes. --- src/library/scala/reflect/ClassTag.scala | 35 ++- src/reflect/scala/reflect/api/Annotations.scala | 13 +- src/reflect/scala/reflect/api/Constants.scala | 76 +++++- src/reflect/scala/reflect/api/Exprs.scala | 3 +- src/reflect/scala/reflect/api/FlagSets.scala | 59 +++-- src/reflect/scala/reflect/api/Importers.scala | 34 +-- src/reflect/scala/reflect/api/JavaMirrors.scala | 22 +- src/reflect/scala/reflect/api/Mirror.scala | 13 +- src/reflect/scala/reflect/api/Mirrors.scala | 201 +++++++++++++++- src/reflect/scala/reflect/api/Names.scala | 4 +- src/reflect/scala/reflect/api/Position.scala | 24 ++ src/reflect/scala/reflect/api/Printers.scala | 78 ++++--- .../scala/reflect/api/StandardDefinitions.scala | 7 +- src/reflect/scala/reflect/api/StandardNames.scala | 3 +- src/reflect/scala/reflect/api/TreeCreator.scala | 2 +- src/reflect/scala/reflect/api/TypeCreator.scala | 6 +- src/reflect/scala/reflect/api/TypeTags.scala | 256 +++++++++++---------- src/reflect/scala/reflect/api/Universe.scala | 131 +++-------- src/reflect/scala/reflect/api/package.scala | 19 +- src/reflect/scala/reflect/runtime/package.scala | 12 +- 20 files changed, 646 insertions(+), 352 deletions(-) diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 5c2067a548..d699e34ffc 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -5,19 +5,34 @@ import java.lang.{ Class => jClass } import scala.language.{implicitConversions, existentials} import scala.runtime.ScalaRunTime.{ arrayClass, arrayElementClass } -/** A `ClassTag[T]` wraps a runtime class (the erasure) and can create array instances. +/** + * + * A `ClassTag[T]` stores the erased class of a given type `T`, accessible via the `runtimeClass` + * field. This is particularly useful for instantiating `Array`s whose element types are unknown + * at compile time. + * + * `ClassTag`s are a weaker special case of [[scala.reflect.api.TypeTags#TypeTag]]s, in that they + * wrap only the runtime class of a given type, whereas a `TypeTag` contains all static type + * information. That is, `ClassTag`s are constructed from knowing only the top-level class of a + * type, without necessarily knowing all of its argument types. This runtime information is enough + * for runtime `Array` creation. * - * If an implicit value of type ClassTag[T] is requested, the compiler will create one. - * The runtime class (i.e. the erasure, a java.lang.Class on the JVM) of T can be accessed - * via the `runtimeClass` field. References to type parameters or abstract type members are - * replaced by the concrete types if ClassTags are available for them. + * For example: + * {{{ + * scala> def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*) + * mkArray: [T](elems: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T] * - * Besides accessing the erasure, a ClassTag knows how to instantiate single- and multi- - * dimensional `Arrays` where the element type is unknown at compile time. + * scala> mkArray(42, 13) + * res0: Array[Int] = Array(42, 13) * - * [[scala.reflect.ClassTag]] corresponds to a previous concept of [[scala.reflect.ClassManifest]]. + * scala> mkArray("Japan","Brazil","Germany") + * res1: Array[String] = Array(Japan, Brazil, Germany) + * }}} + * + * See [[scala.reflect.api.TypeTags]] for more examples, or the + * [[http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html Reflection Guide: TypeTags]] + * for more details. * - * @see [[scala.reflect.api.TypeTags]] */ @scala.annotation.implicitNotFound(msg = "No ClassTag available for ${T}") trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serializable { @@ -29,7 +44,7 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial */ def runtimeClass: jClass[_] - /** Produces a `ClassTag` that knows how to build `Array[Array[T]]` */ + /** Produces a `ClassTag` that knows how to instantiate an `Array[Array[T]]` */ def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](arrayClass(runtimeClass)) /** Produces a new array with element type `T` and length `len` */ diff --git a/src/reflect/scala/reflect/api/Annotations.scala b/src/reflect/scala/reflect/api/Annotations.scala index 1e658228f3..fb353a5520 100644 --- a/src/reflect/scala/reflect/api/Annotations.scala +++ b/src/reflect/scala/reflect/api/Annotations.scala @@ -6,11 +6,16 @@ import scala.collection.immutable.ListMap /** This trait provides annotation support for the reflection API. * * 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. - * 1. ''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 + *
    + *
  • ''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.
  • + *
  • ''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 diff --git a/src/reflect/scala/reflect/api/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala index 9e0573f0dc..a92fc5cbb3 100644 --- a/src/reflect/scala/reflect/api/Constants.scala +++ b/src/reflect/scala/reflect/api/Constants.scala @@ -7,9 +7,79 @@ package scala.reflect package api /** - * This trait is the [[scala.reflect.api.Universe reflection API]] component that mirrors constant irreducible expressions - * such as `true`, `0` and `classOf[List]`. Constant values appear in the program abstract syntax tree and in annotation parameters - * wrapped in [[Constant `Constant`]] case classes. + * 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 + * } + * }}} * * @contentDiagram hideNodes "*Api" */ diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala index 788fc889a8..45bfddb55d 100644 --- a/src/reflect/scala/reflect/api/Exprs.scala +++ b/src/reflect/scala/reflect/api/Exprs.scala @@ -8,8 +8,7 @@ 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. +/** A trait that defines strongly-typed tree wrappers and operations on them for use in Scala Reflection. * * `Expr` wraps an abstract syntax tree ([[scala.reflect.api.Trees#Tree]]) and tags it with its type ([[scala.reflect.api.Types#Type]]). * diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala index 701442b632..a7d1ca05a6 100644 --- a/src/reflect/scala/reflect/api/FlagSets.scala +++ b/src/reflect/scala/reflect/api/FlagSets.scala @@ -3,32 +3,51 @@ 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. +/** + * The trait that defines flag sets and operations on them. * - * 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). + * `Flag`s 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: * - * 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, ...)`. + * - '''[[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. + * - '''[[scala.reflect.api.Trees#TypeDef]]'''. Type aliases, abstract type members and type parameters. * - * 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._`). + * For example, to create a class named `C` one would write something like: + * {{{ + * ClassDef(Modifiers(NoFlags), newTypeName("C"), Nil, ...) + * }}} + * + * Here, the flag set is empty. * - * 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. + * To make `C` private, one would write something like: + * {{{ + * ClassDef(Modifiers(PRIVATE), newTypeName("C"), Nil, ...) + * }}} * - * === Known issues === + * Flags can also be combined with the vertical bar operator (`|`). + * For example, a private final class is written something like: + * {{{ + * ClassDef(Modifiers(PRIVATE | FINAL), newTypeName("C"), Nil, ...) + * }}} + * + * The list of all available flags is defined in [[scala.reflect.api.FlagSets#FlagValues]], available via + * [[scala.reflect.api.FlagSets#Flag]]. (Typically one writes a blanket import for this, e.g. + * `import scala.reflect.runtime.universe.Flag._`). + * + * Definition trees are compiled down to symbols, so flags on modifiers of these 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 kinds of symbols. + * + * ''Of Note:'' This part of the Reflection API is being considered as a candidate for redesign. It is + * quite possible that in future releases of the reflection API, flag sets could be replaced with something else. + * + * For more details about `FlagSet`s and other aspects of Scala reflection, see the + * [[http://docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] * - * 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 => diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala index fde8794348..4286b2b45c 100644 --- a/src/reflect/scala/reflect/api/Importers.scala +++ b/src/reflect/scala/reflect/api/Importers.scala @@ -3,33 +3,23 @@ package api /** This trait provides support for importers, a facility to migrate reflection artifacts between universes. * - * 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 + * Reflection artifacts, such as [[scala.reflect.api.Symbols Symbols]] and [[scala.reflect.api.Types Types]], + * are contained in [[scala.reflect.api.Universes Universe]]s. 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, 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. + * Reflection artifacts are firmly grounded in their `Universe`s, which is reflected by the fact that types of artifacts + * from different universes are not compatible. By using `Importer`s, 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. + * and will import the corresponding type signatures into the target `Universe`. * - * Since importers match symbol tables of the source and the target universes using plain string names, + * Since importers match `Symbol` tables of the source and the target `Universe`s 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. + * `foo.bar.Baz` in the source `Universe` means the same that `foo.bar.Baz` does in the target `Universe`. * * === Example === * diff --git a/src/reflect/scala/reflect/api/JavaMirrors.scala b/src/reflect/scala/reflect/api/JavaMirrors.scala index 9bc888b884..df099006b5 100644 --- a/src/reflect/scala/reflect/api/JavaMirrors.scala +++ b/src/reflect/scala/reflect/api/JavaMirrors.scala @@ -5,7 +5,12 @@ package api * * This refinement equips mirrors with reflection capabilities for the JVM. `JavaMirror` can * convert Scala reflection artifacts (symbols and types) into Java reflection artifacts (classes) - * and vice versa. It can also perform reflective invocations (getting/settings field values, calling methods, etc). + * and vice versa. It can also perform reflective invocations (getting/setting field values, + * calling methods, etc). + * + * For more information about `Mirrors`s, see [[scala.reflect.api.Mirrors]] or the + * [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Mirrors]] + * * @groupname JavaMirrors Java Mirrors */ trait JavaMirrors { self: JavaUniverse => @@ -15,7 +20,7 @@ trait JavaMirrors { self: JavaUniverse => */ type RuntimeClass = java.lang.Class[_] - /** In runtime reflection universes, mirrors are JavaMirrors. + /** In runtime reflection universes, mirrors are `JavaMirrors`. * @group JavaMirrors */ override type Mirror >: Null <: JavaMirror @@ -23,10 +28,12 @@ trait JavaMirrors { self: JavaUniverse => /** 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). + * into Java reflection artifacts (classes) and vice versa. Consequently, refined mirrors + * become capable of performing reflective invocations (getting/setting field values, calling methods, etc). + * + * For more information about `Mirrors`s, see [[scala.reflect.api.Mirrors]] or the + * [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Mirrors]] * - * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection. * @group JavaMirrors */ trait JavaMirror extends scala.reflect.api.Mirror[self.type] with RuntimeMirror { @@ -35,7 +42,10 @@ trait JavaMirrors { self: JavaUniverse => } /** 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. + * + * For more information about `Mirrors`s, see [[scala.reflect.api.Mirrors]] or the + * [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Mirrors]] + * * @group JavaMirrors */ def runtimeMirror(cl: ClassLoader): Mirror diff --git a/src/reflect/scala/reflect/api/Mirror.scala b/src/reflect/scala/reflect/api/Mirror.scala index 60ba087933..b1290cc02e 100644 --- a/src/reflect/scala/reflect/api/Mirror.scala +++ b/src/reflect/scala/reflect/api/Mirror.scala @@ -4,16 +4,15 @@ package api /** * The base class for all mirrors. * - * See the [[http://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. + * See [[scala.reflect.api.Mirrors]] or [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] + * for a complete overview of `Mirror`s. * * @tparam U the type of the universe this mirror belongs to. */ +// 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. abstract class Mirror[U <: Universe with Singleton] { /** The universe this mirror belongs to. * @group Mirror diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala index 32cfdf07fb..cc1b9762cb 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -1,10 +1,205 @@ package scala.reflect package api -/** This trait provides support for Mirrors in the reflection API. +/** This trait provides support for Mirrors in the Scala Reflection API. * - * See the [[http://docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for a description of mirrors - * and infomation on getting started with Scala reflection API. + * `Mirror`s are a central part of Scala Reflection. All information provided by + * reflection is made accessible through `Mirror`s. Depending on the type of information + * to be obtained, or the reflective action to be taken, different flavors of mirrors + * must be used. "Classloader" mirrors can be used to obtain representations of types + * and members. From a classloader `Mirror`, it's possible to obtain more specialized + * "invoker" `Mirror`s (the most commonly-used mirrors), which implement reflective + * invocations, such as method/constructor calls and field accesses. + * + * The two flavors of mirrors: + * + *
    + *
  • ```“Classloader” mirrors```. These mirrors translate names to symbols + * (via methods `staticClass`/`staticModule`/`staticPackage`).
  • + *
  • ```"Invoker” mirrors```. These mirrors implement reflective invocations + * (via methods `MethodMirror.apply`, `FieldMirror.get`, etc). These "invoker" + * mirrors are the types of mirrors that are most commonly used.
  • + *
+ * + * === Compile-time Mirrors === + * Compile-time `Mirror`s make use of only classloader `Mirror`s to load `Symbol`s + * by name. + * + * The entry point to classloader `Mirror`s is via [[scala.reflect.macros.Context#mirror]]. + * Typical methods which use classloader `Mirror`s include [[scala.reflect.api.Mirror#staticClass]], + * [[scala.reflect.api.Mirror#staticModule]], and [[scala.reflect.api.Mirror#staticPackage]]. For + * example: + * {{{ + * import scala.reflect.macros.Context + * + * case class Location(filename: String, line: Int, column: Int) + * + * object Macros { + * def currentLocation: Location = macro impl + * + * def impl(c: Context): c.Expr[Location] = { + * import c.universe._ + * val pos = c.macroApplication.pos + * val clsLocation = c.mirror.staticModule("Location") // get symbol of "Location" object + * c.Expr(Apply(Ident(clsLocation), List(Literal(Constant(pos.source.path)), Literal(Constant(pos.line)), Literal(Constant(pos.column))))) + * } + * } + * }}} + * + * ''Of Note:'' There are several high-level alternatives that one can use to avoid having to manually + * lookup symbols. For example, `typeOf[Location.type].termSymbol` (or `typeOf[Location].typeSymbol` + * if we needed a `ClassSymbol`), which are type safe since we don’t have to use `String`s to lookup + * the `Symbol`. + * + * === Runtime Mirrors === + * + * Runtime `Mirror`s make use of both classloader and invoker `Mirror`s. + * + * The entry point to `Mirror`s for use at runtime is via `ru.runtimeMirror()`, where + * `ru` is [[scala.reflect.runtime.universe]]. + * + * The result of a [[scala.reflect.api.JavaMirrors#runtimeMirror]] call is a classloader mirror, + * of type [[scala.reflect.api.Mirrors#ReflectiveMirror]], which can load symbols by names as + * discussed above (in the “Compile-time” section). + * + * A classloader mirror can create invoker mirrors, which include: [[scala.reflect.api.Mirrors#InstanceMirror]], + * [[scala.reflect.api.Mirrors#MethodMirror]], [[scala.reflect.api.Mirrors#FieldMirror]], + * [[scala.reflect.api.Mirrors#ClassMirror]] and [[scala.reflect.api.Mirrors#ModuleMirror]]. + * + * Examples of how these two types of `Mirror`s interact are available below. + * + * === Types of Mirrors, Their Use Cases & Examples === + * + * '''[[scala.reflect.api.Mirrors#ReflectiveMirror]]'''. Used for loading `Symbol`s by name, and + * as an entry point into invoker mirrors. Entry point: `val m = ru.runtimeMirror()`. + * Example: + * {{{ + * scala> val ru = scala.reflect.runtime.universe + * ru: scala.reflect.api.JavaUniverse = ... + * + * scala> val m = ru.runtimeMirror(getClass.getClassLoader) + * m: reflect.runtime.universe.Mirror = JavaMirror ... + * }}} + * + * '''[[scala.reflect.api.Mirrors#InstanceMirror]]'''. Used for creating invoker `Mirror`s for methods + * and fields and for inner classes and inner objects (modules). Entry point: `val im = m.reflect()`. + * Example: + * {{{ + * scala> class C { def x = 2 } + * defined class C + * + * scala> val im = m.reflect(new C) + * im: reflect.runtime.universe.InstanceMirror = instance mirror for C@3442299e + * }}} + * + * '''[[scala.reflect.api.Mirrors#MethodMirror]]'''. Used for invoking instance methods (Scala only has + * instance methods-- methods of objects are instance methods of object instances, obtainable + * via `ModuleMirror.instance`). Entry point: `val mm = im.reflectMethod()`. + * Example: + * {{{ + * scala> val methodX = typeOf[C].declaration(newTermName("x")).asMethod + * methodX: reflect.runtime.universe.MethodSymbol = method x + * + * scala> val mm = im.reflectMethod(methodX) + * mm: reflect.runtime.universe.MethodMirror = method mirror for C.x: scala.Int (bound to C@3442299e) + * + * scala> mm() + * res0: Any = 2 + * }}} + * + * '''[[scala.reflect.api.Mirrors#FieldMirror]]'''. Used for getting/setting instance fields + * (Scala only has instance fields-- fields of objects are instance methods of object instances + * obtainable via ModuleMirror.instance). Entry point: + * `val fm = im.reflectMethod()`. + * Example: + * {{{ + * scala> class C { val x = 2; val y = 3 } + * defined class C + * + * scala> val m = ru.runtimeMirror(getClass.getClassLoader) + * m: reflect.runtime.universe.Mirror = JavaMirror ... + * + * scala> val im = m.reflect(new C) + * im: reflect.runtime.universe.InstanceMirror = instance mirror for C@5f0c8ac1 + * + * scala> val fieldX = typeOf[C].declaration(newTermName("x")).asTerm.accessed.asTerm + * fieldX: reflect.runtime.universe.TermSymbol = value x + * scala> val fmX = im.reflectField(fieldX) + * fmX: reflect.runtime.universe.FieldMirror = field mirror for C.x (bound to C@5f0c8ac1) + * + * scala> fmX.get + * res0: Any = 2 + * + * scala> fmX.set(3) + * scala.ScalaReflectionException: cannot set an immutable field x + * ... + * + * scala> val fieldY = typeOf[C].declaration(newTermName("y")).asTerm.accessed.asTerm + * fieldY: reflect.runtime.universe.TermSymbol = variable y + * + * scala> val fmY = im.reflectField(fieldY) + * fmY: reflect.runtime.universe.FieldMirror = field mirror for C.y (bound to C@5f0c8ac1) + * + * scala> fmY.get + * res1: Any = 3 + * + * scala> fmY.set(4) + * + * scala> fmY.get + * res2: Any = 4 + * }}} + * + * '''[[scala.reflect.api.Mirrors#ClassMirror]]'''. Used for creating invoker mirrors for constructors. + * Entry points: for ''static classes'' `val cm1 = m.reflectClass()`, + * for ''inner classes'' `val mm2 = im.reflectClass()`. + * Example: + * {{{ + * scala> case class C(x: Int) + * defined class C + * + * scala> val m = ru.runtimeMirror(getClass.getClassLoader) + * m: reflect.runtime.universe.Mirror = JavaMirror ... + * + * scala> val classC = typeOf[C].typeSymbol.asClass + * + * classC: reflect.runtime.universe.Symbol = class C + * + * scala> val cm = m.reflectClass(classC) + * cm: reflect.runtime.universe.ClassMirror = class mirror for C (bound to null) + * + * scala> val ctorC = typeOf[C].declaration(ru.nme.CONSTRUCTOR).asMethod + * ctorC: reflect.runtime.universe.MethodSymbol = constructor C + * + * scala> val ctorm = cm.reflectConstructor(ctorC) + * ctorm: reflect.runtime.universe.MethodMirror = constructor mirror for C.(x: scala.Int): C (bound to null) + * + * scala> ctorm(2) + * res0: Any = C(2) + * }}} + * + * '''[[scala.reflect.api.Mirrors#ModuleMirror]]'''. Used for getting singleton instances of objects. + * Entry points: for ''static objects (modules)'' `val mm1 = m.reflectModule()`, + * for ''inner objects (modules)'' `val mm2 = im.reflectModule()`. + * Example: + * {{{ + * scala> object C { def x = 2 } + * defined module C + * + * scala> val m = ru.runtimeMirror(getClass.getClassLoader) + * m: reflect.runtime.universe.Mirror = JavaMirror ... + * + * scala> val objectC = typeOf[C.type].termSymbol.asModule + * objectC: reflect.runtime.universe.ModuleSymbol = object C + * + * scala> val mm = m.reflectModule(objectC) + * mm: reflect.runtime.universe.ModuleMirror = module mirror for C (bound to null) + * + * scala> val obj = mm.instance + * obj: Any = C$@1005ec04 + * }}} + * + * For more information about `Mirrors`s, see the + * [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Mirrors]] * * @contentDiagram hideNodes "*Api" */ diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index 332c24e542..02eb79f8ed 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -5,7 +5,7 @@ package api * * Names are simple wrappers for strings. [[scala.reflect.api.Names#Name Name]] has two subtypes [[scala.reflect.api.Names#TermName TermName]] and [[scala.reflect.api.Names#TypeName TypeName]] which * distinguish names of terms (like objects or members) and types. A term and a type of the - * same name can co-exist in an object. + * same name can co-exist in an object. * * === Examples === * @@ -13,7 +13,7 @@ package api * use `typeOf[List[_]].member(newTermName("map"))`. To search for a type member, use * newTypeName instead. * - * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]]. + * See the [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for more about Scala Reflection. * * @contentDiagram hideNodes "*Api" */ diff --git a/src/reflect/scala/reflect/api/Position.scala b/src/reflect/scala/reflect/api/Position.scala index fb199bbd69..61d643b449 100644 --- a/src/reflect/scala/reflect/api/Position.scala +++ b/src/reflect/scala/reflect/api/Position.scala @@ -16,6 +16,30 @@ import scala.reflect.macros.Attachments * The compiler adds more information to positions, such a ranges in the source file and defines different types of * positions depending on how a symbol or tree node was generated. The guide fully describes compiler-generated positions. * + * - 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, + * `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)`. + * 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. + * * @groupname Common Commonly used methods */ trait Position extends Attachments { diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala index b7157af153..1e8161aeef 100644 --- a/src/reflect/scala/reflect/api/Printers.scala +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -3,9 +3,12 @@ package api import java.io.{ PrintWriter, StringWriter } -/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines prettyprinting functionality. +/** Utilities for nicely printing [[scala.reflect.api.Trees]] and [[scala.reflect.api.Types]]. * - * === Examples (trees) === + * === Printing Trees === + * The method `show` displays the "prettified" representation of reflection artifacts. + * This representation provides one with the desugared Java representation of Scala code. + * For example: * * {{{ * scala> import scala.reflect.runtime.universe._ @@ -14,9 +17,6 @@ import java.io.{ PrintWriter, StringWriter } * 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 = * { @@ -29,21 +29,17 @@ import java.io.{ PrintWriter, StringWriter } * }; * () * } + * }}} + * + * The method `showRaw` displays internal structure of a given reflection object + * as a Scala abstract syntax tree (AST), the representation that the Scala typechecker + * operates on. * - * // 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) + * Note, that while this representation appears to generate correct trees that one + * might think would be possible to use in a macro implementation, this is not usually + * the case. Symbols aren't fully represented (only their names are). Thus, this method + * is best-suited for use simply inspecting ASTs given some valid Scala code. + * {{{ * scala> showRaw(tree) * res1: String = Block(List( * ClassDef(Modifiers(FINAL), newTypeName("C"), List(), Template( @@ -57,15 +53,17 @@ import java.io.{ PrintWriter, StringWriter } * DefDef(Modifiers(), newTermName("x"), List(), List(), TypeTree(), * Literal(Constant(2))))))), * Literal(Constant(()))) - * + * }}} + * + * The method `showRaw` can also print [[scala.reflect.api.Types]] next to the artifacts + * being inspected + * {{{ * 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]( @@ -89,8 +87,9 @@ import java.io.{ PrintWriter, StringWriter } * [8] ConstantType(Constant(2)) * }}} * - * === Examples (types) === + * === Printing Types === * + * The method `show` * {{{ * scala> import scala.reflect.runtime.universe._ * import scala.reflect.runtime.universe._ @@ -98,10 +97,14 @@ import java.io.{ PrintWriter, StringWriter } * 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]} + * }}} * + * Like the method `showRaw` for [[scala.reflect.api.Trees]], `showRaw` + * for [[scala.reflect.api.Types]] provides a visualization of the Scala + * AST operated on by the Scala typechecker. + * {{{ * // showRaw has already been discussed above * scala> showRaw(tpe) * res1: String = RefinedType( @@ -109,18 +112,10 @@ import java.io.{ PrintWriter, StringWriter } * 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) + * `printIds` and/or `printKinds` can additionally be supplied as arguments in a call to + * `showRaw` which additionally shows the unique identifiers of symbols. * scala> showRaw(tpe, printIds = true, printKinds = true) * res2: String = RefinedType( * List(TypeRef(ThisType(scala#2043#PK), newTypeName("AnyRef")#691#TPE, List())), @@ -128,6 +123,10 @@ import java.io.{ PrintWriter, StringWriter } * newTermName("x")#2540#METH, * newTermName("y")#2541#GET)) * }}} + * + * For more details about `Printer`s and other aspects of Scala reflection, see the + * [[http://docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] + * */ trait Printers { self: Universe => @@ -176,8 +175,9 @@ trait Printers { self: Universe => */ override protected def treeToString(tree: Tree) = show(tree) - /** Renders a prettified representation of a reflection artifact. - * Typically it looks very close to the Scala code it represents. + /** Renders a representation of a reflection artifact + * as desugared Java code. + * * @group Printers */ def show(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None): String = @@ -188,7 +188,9 @@ trait Printers { self: Universe => */ protected def newTreePrinter(out: PrintWriter): TreePrinter - /** Renders internal structure of a reflection artifact. + /** Renders internal structure of a reflection artifact as the + * visualization of a Scala syntax tree. + * * @group Printers */ def showRaw(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None): String = diff --git a/src/reflect/scala/reflect/api/StandardDefinitions.scala b/src/reflect/scala/reflect/api/StandardDefinitions.scala index e1eadde3ad..a31a501357 100644 --- a/src/reflect/scala/reflect/api/StandardDefinitions.scala +++ b/src/reflect/scala/reflect/api/StandardDefinitions.scala @@ -5,10 +5,11 @@ package scala.reflect package api -/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines standard symbols and types. +/** All Scala 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]]. + * These standard definitions can accessed to using `definitions`. + * They're typically imported with a blanket import `import definitions`, and are + * listed in [[scala.reflect.api.StandardDefinitions#DefinitionsApi]]. */ trait StandardDefinitions { self: Universe => diff --git a/src/reflect/scala/reflect/api/StandardNames.scala b/src/reflect/scala/reflect/api/StandardNames.scala index 203bcdbdc4..fc18c02706 100644 --- a/src/reflect/scala/reflect/api/StandardNames.scala +++ b/src/reflect/scala/reflect/api/StandardNames.scala @@ -10,8 +10,7 @@ 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. -/** This trait is the [[scala.reflect.api.Universe reflection API]] component that defines standard [[Names names used in reflection and macros]]. - * +/** * 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. * diff --git a/src/reflect/scala/reflect/api/TreeCreator.scala b/src/reflect/scala/reflect/api/TreeCreator.scala index c668fe0b4d..cba90b72e6 100644 --- a/src/reflect/scala/reflect/api/TreeCreator.scala +++ b/src/reflect/scala/reflect/api/TreeCreator.scala @@ -3,7 +3,7 @@ package api /** This is an internal implementation class. * - * @see [[http://docs.scala-lang.org/overviews/reflection/architecture.html]]. + * This class is used internally by Scala Reflection, and is not recommended for use in client code. */ abstract class TreeCreator { def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Tree diff --git a/src/reflect/scala/reflect/api/TypeCreator.scala b/src/reflect/scala/reflect/api/TypeCreator.scala index 16585cd23f..9c386f2939 100644 --- a/src/reflect/scala/reflect/api/TypeCreator.scala +++ b/src/reflect/scala/reflect/api/TypeCreator.scala @@ -1,9 +1,9 @@ package scala.reflect package api -/** This is an internal implementation class. - * - * @see [[http://docs.scala-lang.org/overviews/reflection/architecture.html]]. +/** A mirror-aware factory for types. + * + * This class is used internally by Scala Reflection, and is not recommended for use in client code. */ abstract class TypeCreator { def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala index 9d66a9e236..812d5199fc 100644 --- a/src/reflect/scala/reflect/api/TypeTags.scala +++ b/src/reflect/scala/reflect/api/TypeTags.scala @@ -17,130 +17,143 @@ 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 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 === - * - * Type tags are organized in a hierarchy of three classes: - * [[scala.reflect.ClassTag]], [[scala.reflect.api.Universe#TypeTag]] and [[scala.reflect.api.Universe#WeakTypeTag]]. - * - * Examples: - * {{{ - * scala> class Person - * scala> class Container[T] - * scala> import scala.reflect.ClassTag - * scala> import scala.reflect.runtime.universe.TypeTag - * scala> import scala.reflect.runtime.universe.WeakTypeTag - * scala> def firstTypeArg( tag: WeakTypeTag[_] ) = (tag.tpe match {case TypeRef(_,_,typeArgs) => typeArgs})(0) - * }}} - * TypeTag contains concrete type arguments: - * {{{ - * scala> firstTypeArg( implicitly[TypeTag[Container[Person]]] ) - * res0: reflect.runtime.universe.Type = Person - * }}} - * TypeTag guarantees concrete type arguments (fails for references to unbound type arguments): - * {{{ - * scala> def foo1[T] = implicitly[TypeTag[Container[T]]] - * :11: error: No TypeTag available for Container[T] - * def foo1[T] = implicitly[TypeTag[Container[T]]] - * }}} - * WeakTypeTag allows references to unbound type arguments: - * {{{ - * scala> def foo2[T] = firstTypeArg( implicitly[WeakTypeTag[Container[T]]] ) - * foo2: [T]=> reflect.runtime.universe.Type - * scala> foo2[Person] - * res1: reflect.runtime.universe.Type = T - * }}} - * TypeTag allows unbound type arguments for which type tags are available: - * {{{ - * scala> def foo3[T:TypeTag] = firstTypeArg( implicitly[TypeTag[Container[T]]] ) - * foo3: [T](implicit evidence\$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.Type - * scala> foo3[Person] - * res1: reflect.runtime.universe.Type = Person - * }}} - * WeakTypeTag contains concrete type arguments if available via existing tags: - * {{{ - * scala> def foo4[T:WeakTypeTag] = firstTypeArg( implicitly[WeakTypeTag[Container[T]]] ) - * foo4: [T](implicit evidence\$1: reflect.runtime.universe.WeakTypeTag[T])reflect.runtime.universe.Type - * scala> foo4[Person] - * res1: reflect.runtime.universe.Type = Person - * }}} - * - * - * [[scala.reflect.api.Universe#TypeTag]] and [[scala.reflect.api.Universe#WeakTypeTag]] are path dependent on their universe. - * - * The default universe is [[scala.reflect.runtime.universe]] - * - * Type tags can be migrated to another universe given the corresponding mirror using - * - * {{{ - * tag.in( other_mirror ) - * }}} - * - * See [[scala.reflect.api.TypeTags#WeakTypeTag.in]] - * - * === WeakTypeTag vs TypeTag === - * - * Be careful with WeakTypeTag, because it will reify types even if these types are abstract. - * This makes it easy to forget to tag one of the methods in the call chain and discover it much later in the runtime - * by getting cryptic errors far away from their source. For example, consider the following snippet: +/** + * A `TypeTag[T]` encapsulates the runtime type representation of some type `T`. + * Like [[scala.reflect.Manifest]], the prime use case of `TypeTag`s is to give access + * to erased types. However, `TypeTag`s should be considered to be a richer + * replacement of the pre-2.10 notion of a [[scala.reflect.Manifest Manifest]], that + * are, in addition, fully integrated with Scala reflection. * + * There exist three different types of `TypeTags`: + * + *
    + *
  • [[scala.reflect.api.TypeTags#TypeTag]].
    A full type descriptor of a Scala type. + * For example, a `TypeTag[List[String]]` contains all type information, + * in this case, of type `scala.List[String]`.
  • + * + *
  • [[scala.reflect.ClassTag]].
    A partial type descriptor of a Scala type. For + * example, a `ClassTag[List[String]]` contains only the erased class + * type information, in this case, of type `scala.collection.immutable.List`. + * `ClassTag`s provide access only to the runtime class of a type. + * Analogous to [[scala.reflect.ClassManifest]]
  • + * + *
  • [[scala.reflect.api.TypeTags#WeakTypeTag]].
    A type descriptor for abstract + * types (see description below).
  • + *
+ * + * Like [[scala.reflect.Manifest Manifest]]s, `TypeTag`s are always generated by the + * compiler, and can be obtained in three ways: + * + * === #1 Via the methods [[scala.reflect.api.TypeTags#typeTag typeTag]], + * [[scala.reflect#classTag classTag]], or [[scala.reflect.api.TypeTags#weakTypeTag weakTypeTag]] === + * + * For example: * {{{ - * def bind[T: WeakTypeTag](name: String, value: T): IR.Result = bind((name, value)) - * def bind(p: NamedParam): IR.Result = bind(p.name, p.tpe, p.value) - * object NamedParam { - * implicit def namedValue[T: WeakTypeTag](name: String, x: T): NamedParam = apply(name, x) - * def apply[T: WeakTypeTag](name: String, x: T): NamedParam = new Typed[T](name, x) + * import scala.reflect.runtime.universe._ + * val tt = typeTag[Int] + * + * import scala.reflect._ + * val ct = classTag[String] + * }}} + * + * Each of these methods constructs a `TypeTag[T]` or `ClassTag[T]` for the given + * type argument `T`. + * + * === #2 Using an implicit parameter of type `TypeTag[T]`, `ClassTag[T]`, or `WeakTypeTag[T] + * + * For example: + * {{{ + * import scala.reflect.runtime.universe._ + * + * def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = { + * val targs = tag.tpe match { case TypeRef(_, _, args) => args } + * println(s"type of $x has type arguments $targs") * } + * + * scala> paramInfo(42) + * type of 42 has type arguments List() + * + * scala> paramInfo(List(1, 2)) + * type of List(1, 2) has type arguments List(Int) * }}} * - * This fragment of the Scala REPL implementation defines a `bind` function that carries a named value along with its type - * into the heart of the REPL. Using a [[scala.reflect.api.Universe#WeakTypeTag]] here is reasonable, because it is desirable - * to work with all types, even if they are type parameters or abstract type members. + * === #3 Context bound of a type parameter === * - * However if any of the three `WeakTypeTag` context bounds is omitted, the resulting code will be incorrect, - * because the missing `WeakTypeTag` will be transparently generated by the compiler, carrying meaningless information. - * Most likely, this problem will manifest itself elsewhere, making debugging complicated. - * If `WeakTypeTag` context bounds were replaced with `TypeTag`, then such errors would be reported statically. - * But in that case we wouldn't be able to use `bind` in arbitrary contexts. + * ...on methods or classes. The above example can be implemented as follows: * - * === Backward compatibility with Manifests === + * {{{ + * import scala.reflect.runtime.universe._ + * + * def paramInfo[T: TypeTag](x: T): Unit = { + * val targs = typeOf[T] match { case TypeRef(_, _, args) => args } + * println(s"type of $x has type arguments $targs") + * } + * + * scala> paramInfo(42) + * type of 42 has type arguments List() * - * Type tags correspond loosely to manifests. + * scala> paramInfo(List(1, 2)) + * type of List(1, 2) has type arguments List(Int) + * }}} + * + * === `WeakTypeTag`s === + * + *`WeakTypeTag[T]` generalizes `TypeTag[T]`. Unlike a regular `TypeTag`, components of + * its type representation can be references to type parameters or abstract types. + * However, `WeakTypeTag[T]` tries to be as concrete as possible, i.e. if type tags + * are available for the referenced type arguments or abstract types, they are used to + * embed the concrete types into the `WeakTypeTag[T]`. * - * More precisely: - * 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, + * Continuing the example above: + * {{{ + * def weakParamInfo[T](x: T)(implicit tag: WeakTypeTag[T]): Unit = { + * val targs = tag.tpe match { case TypeRef(_, _, args) => args } + * println(s"type of $x has type arguments $targs") + * } * - * 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. + * scala> def foo[T] = weakParamInfo(List[T]()) + * foo: [T]=> Unit * - * In most cases it is enough to replace `ClassManifest` with `ClassTag` and `Manifest` with `TypeTag`. - * There are however a few caveats: + * scala> foo[Int] + * type of List() has type arguments List(T) + * }}} * - * 1) Tags don't support the notion of `OptManifest`. Tags can reify arbitrary types, so they are always available. + * === TypeTags and Manifests === * - * 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`. + * `TypeTag`s correspond loosely to the pre-2.10 notion of + * [[scala.reflect.Manifest]]s. While [[scala.reflect.ClassTag]] corresponds to + * [[scala.reflect.ClassManifest]] and [[scala.reflect.api.TypeTags#TypeTag]] mostly + * corresponds to [[scala.reflect.Manifest]], other pre-2.10 `Manifest` types do not + * have a direct correspondence with a 2.10 "`Tag`" type. * - * 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). + *
    + *
  • '''[[scala.reflect.OptManifest]] is not supported.'''
    This is because `Tag`s + * can reify arbitrary types, so they are always available.
  • * - * 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. + *
  • '''There is no equivalent for [[scala.reflect.AnyValManifest]].'''
    Instead, one + * can compare their `Tag` with one of the base `Tag`s (defined in the corresponding + * companion objects) in order to find out whether or not it represents a primitive + * value class. Additionally, it's possible to simply use + * `.tpe.typeSymbol.isPrimitiveValueClass`.
  • * - * === Known issues === + *
  • '''There are no replacement for factory methods defined in the `Manifest` + * companion objects'''.
    Instead, one could generate corresponding types using the + * reflection APIs provided by Java (for classes) and Scala (for types).
  • * - * 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. + *
  • '''Certain manifest operations(i.e., <:<, >:> and typeArguments) are not + * supported.'''
    Instead, one culd use the reflection APIs provided by Java (for + * classes) and Scala (for types).
  • + *
* - * @see [[scala.reflect.ClassTag]], [[scala.reflect.api.Universe#TypeTag]], [[scala.reflect.api.Universe#WeakTypeTag]] + * In Scala 2.10, [[scala.reflect.ClassManifest]]s are deprecated, and it is planned + * to deprecate [[scala.reflect.Manifest]] in favor of `TypeTag`s and `ClassTag`s in + * an upcoming point release. Thus, it is advisable to migrate any `Manifest`-based + * APIs to use `Tag`s. + * + * For more information about `TypeTag`s, see the + * [[http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html Reflection Guide: TypeTags]] + * + * @see [[scala.reflect.ClassTag]], [[scala.reflect.api.TypeTags#TypeTag]], [[scala.reflect.api.TypeTags#WeakTypeTag]] * @group TypeTags Type Tags */ trait TypeTags { self: Universe => @@ -148,14 +161,17 @@ trait TypeTags { self: Universe => import definitions._ /** - * If an implicit value of type WeakTypeTag[T] is required, the compiler will create one. - * A reflective representation of T can be accessed via the tpe field. - * Components of T can be references to type parameters or abstract types. WeakTypeTag makes an effort to - * be as concrete as possible, i.e. if type tags are available for the referenced type arguments or abstract types, - * they are used to embed the concrete types into the WeakTypeTag. Otherwise the WeakTypeTag will contain a reference - * to an abstract type. This behavior can be useful, when one expects T to be possibly partially abstract, but - * requires special care to handle this case. If however T is expected to be fully known, use - * [[scala.reflect.api.Universe#TypeTag]] instead, which statically guarantees this property. + * If an implicit value of type `WeakTypeTag[T]` is required, the compiler will create one, + * and the reflective representation of `T` can be accessed via the `tpe` field. + * Components of `T` can be references to type parameters or abstract types. Note that `WeakTypeTag` + * makes an effort to be as concrete as possible, i.e. if `TypeTag`s are available for the referenced type arguments + * or abstract types, they are used to embed the concrete types into the WeakTypeTag. Otherwise the WeakTypeTag will + * contain a reference to an abstract type. This behavior can be useful, when one expects `T` to be perhaps be partially + * abstract, but requires special care to handle this case. However, if `T` is expected to be fully known, use + * [[scala.reflect.api.TypeTags#TypeTag]] instead, which statically guarantees this property. + * + * For more information about `TypeTag`s, see the + * [[http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html Reflection Guide: TypeTags]] * * @see [[scala.reflect.api.TypeTags]] * @group TypeTags @@ -163,7 +179,7 @@ trait TypeTags { self: Universe => @annotation.implicitNotFound(msg = "No WeakTypeTag available for ${T}") trait WeakTypeTag[T] extends Equals with Serializable { /** - * Underlying mirror of this type tag. + * The underlying `Mirror` of this type tag. */ val mirror: Mirror @@ -180,16 +196,16 @@ trait TypeTags { self: Universe => */ def tpe: Type - /** TODO how do I doc this? */ + // TODO how do I doc this? override def canEqual(x: Any) = x.isInstanceOf[WeakTypeTag[_]] - /** TODO how do I doc this? */ + // 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? */ + // TODO how do I doc this? override def hashCode = mirror.hashCode * 31 + tpe.hashCode - /** TODO how do I doc this? */ + // TODO how do I doc this? override def toString = "WeakTypeTag[" + tpe + "]" } @@ -249,7 +265,7 @@ trait TypeTags { self: Universe => } /** - * A `TypeTag` is a [[scala.reflect.api.Universe#WeakTypeTag]] with the additional + * A `TypeTag` is a [[scala.reflect.api.TypeTags#WeakTypeTag]] with the additional * static guarantee that all type references are concrete, i.e. it does not contain any references to * unresolved type parameters or abstract types. * diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index d9be73fde9..7d1f5c9df1 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -2,13 +2,18 @@ package scala.reflect package api /** - * The Scala reflection cake. + * `Universe` provides a complete set of reflection operations which make it possible for one + * to reflectively inspect Scala type relations, such as membership or subtyping. * - * 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. + * [[scala.reflect.api.Universe]] has two specialized sub-universes for different scenarios. + * [[scala.reflect.api.JavaUniverse]] adds operations that link symbols and types to the underlying + * classes and runtime values of a JVM instance-- this can be thought of as the `Universe` that + * should be used for all typical use-cases of Scala reflection. [[scala.reflect.macros.Universe]] + * adds operations which allow macros to access selected compiler data structures and operations-- + * this type of `Universe` should only ever exist within the implementation of a Scala macro. * - * 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: + * `Universe` can be thought of as the entry point to Scala reflection. It mixes-in, and thus provides + * an interface to the following main types: * * - [[scala.reflect.api.Types#Type Types]] represent types * - [[scala.reflect.api.Symbols#Symbol Symbols]] represent definitions @@ -19,58 +24,32 @@ package api * - [[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. + * + * To obtain a `Universe` to use with Scala runtime reflection, simply make sure to use or import + * `scala.reflect.runtime.universe._` + * {{{ + * scala> import scala.reflect.runtime.universe._ + * import scala.reflect.runtime.universe._ + * + * scala> typeOf[List[Int]] + * res0: reflect.runtime.universe.Type = scala.List[Int] + * + * scala> typeOf[Either[String, Int]] + * res1: reflect.runtime.universe.Type = scala.Either[String,Int] + * }}} * - * 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. - * + * To obtain a `Universe` for use within a Scala macro, use [[scala.reflect.macros.Context#universe]]. For example: * {{{ - * 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) + * def printf(format: String, params: Any*): Unit = macro impl + * def impl(c: Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = { + * import c.universe._ + * ... + * } * }}} * - * is equivalent to - * - * {{{ - * import scala.reflect.runtime.universe._ - * val iftree = reify{ if( condition ) 1 else 2 }.tree - * }}} + * For more information about `Universe`s, see the [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Universes]] * - * 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`. - * @groupprio Universe -1 + * @groupprio Universe -1 * * @contentDiagram hideNodes "*Api" */ @@ -93,9 +72,9 @@ abstract class Universe extends Symbols with Printers with Importers { - /** Produce the abstract syntax tree representing the given Scala expression. + /** Use `refiy` to produce the abstract syntax tree representing a given Scala expression. * - * For example + * For example: * * {{{ * val five = reify{ 5 } // Literal(Constant(5)) @@ -105,49 +84,7 @@ abstract class Universe extends Symbols * * The produced tree is path dependent on the Universe `reify` was called from. * - * Use [[scala.reflect.api.Exprs#Expr.splice]] to embed an existing expression into a reify call. Use [[Expr]] to turn a [[Tree]] into an expression that can be spliced. - * - * == Further info and implementation details == - * - * `reify` is implemented as a macro, which given an expression, generates a tree that when compiled and executed produces the original tree. - * - * For instance in `reify{ x + 1 }` the macro `reify` receives the abstract syntax tree of `x + 1` as its argument, which is - * - * {{{ - * Apply(Select(Ident("x"), "+"), List(Literal(Constant(1)))) - * }}} - * - * and returns a tree, which produces the tree above, when compiled and executed. So in other terms, the refiy call expands to something like - * - * {{{ - * val $u: u.type = u // where u is a reference to the Universe that calls the reify - * $u.Expr[Int]($u.Apply($u.Select($u.Ident($u.newFreeVar("x", , x), "+"), List($u.Literal($u.Constant(1)))))) - * }}} - * - * ------ - * - * Reification performs expression splicing (when processing Expr.splice) - * and type splicing (for every type T that has a TypeTag[T] implicit in scope): - * - * {{{ - * val two = mirror.reify(2) // Literal(Constant(2)) - * val four = mirror.reify(two.splice + two.splice) // Apply(Select(two.tree, newTermName("\$plus")), List(two.tree)) - * - * def macroImpl[T](c: Context) = { - * ... - * // T here is just a type parameter, so the tree produced by reify won't be of much use in a macro expansion - * // however, if T were annotated with c.WeakTypeTag (which would declare an implicit parameter for macroImpl) - * // then reification would substitute T with the TypeTree that was used in a TypeApply of this particular macro invocation - * val factory = c.reify{ new Queryable[T] } - * ... - * } - * }}} - * - * The transformation looks mostly straightforward, but it has its tricky parts: - * - Reifier retains symbols and types defined outside the reified tree, however - * locally defined entities get erased and replaced with their original trees - * - Free variables are detected and wrapped in symbols of the type `FreeTermSymbol` or `FreeTypeSymbol` - * - Mutable variables that are accessed from a local function are wrapped in refs + * Use [[scala.reflect.api.Exprs#Expr.splice]] to embed an existing expression into a `reify` call. Use [[Expr]] to turn a [[Tree]] into an expression that can be spliced. * @group Universe */ // implementation is hardwired to `scala.reflect.reify.Taggers` diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala index 449b7d5ce1..bd9c72a839 100644 --- a/src/reflect/scala/reflect/api/package.scala +++ b/src/reflect/scala/reflect/api/package.scala @@ -2,13 +2,22 @@ package scala.reflect import scala.reflect.api.{Universe => ApiUniverse} -/** The Scala reflection API (located at scala-reflect.jar). +/** The Scala Reflection API (located in scala-reflect.jar). * - * Using Scala reflection requires understanding of a couple of basic concepts like [[Symbols Symbols]], [[Types Types]], [[Mirror Mirrors]] and [[Universe Universes]]. - * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]]. + * In Scala 2.10.0, the Scala Reflection API and its implementation have an "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 some 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 + * The following types are the backbone of the Scala Reflection API, and serve as a good starting point + * for information about Scala Reflection: + * + * - [[scala.reflect.api.Symbols]] + * - [[scala.reflect.api.Types]] + * - [[scala.reflect.api.Mirrors]] + * - [[scala.reflect.api.Universe]] + * + * For more information about Scala Reflection, see the + * [[http://docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] * * @groupprio API 9 * @groupprio Extractors 10 diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala index b3f9ba5817..b97913daf0 100644 --- a/src/reflect/scala/reflect/runtime/package.scala +++ b/src/reflect/scala/reflect/runtime/package.scala @@ -5,14 +5,18 @@ package scala.reflect */ package object runtime { - /** The entry point into runtime reflection. - * See [[scala.reflect.api.package the overview page]] for details on how to use it. + /** The entry point into Scala runtime reflection. + * + * To use Scala runtime reflection, simply use or import `scala.reflect.runtime.universe._` + * + * See [[scala.reflect.api.Universe]] or the + * [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Universes]] + * for more details. */ 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. + * It's typically equivalent to `universe.runtimeMirror(getClass.getClassLoader)` invoked at the call site. */ // implementation hardwired to the `currentMirror` method below // using the mechanism implemented in `scala.tools.reflect.FastTrack` -- cgit v1.2.3 From 8989ce7c22b8a7329c1f3b770c9b2f6a32e04709 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Thu, 11 Oct 2012 16:42:46 +0200 Subject: Moved @contentDiagram in Symbols --- src/reflect/scala/reflect/api/Symbols.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index d59ca561a2..993cbd97a5 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -11,6 +11,8 @@ package api * to obtain the symbol that represents their declaration. During the typechecking phase, the compiler looks up the * symbol based on the name and scope and sets the [[Trees.SymTreeApi.symbol `symbol` field]] of tree nodes. * + * @contentDiagram hideNodes "*Api" + * * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]] * * The Reflection Guide provides more details on symbol usage and attached intricacies. @@ -18,8 +20,6 @@ package api * @define SYMACCESSORS Class [[Symbol]] defines `isXXX` test methods such as `isPublic` or `isFinal`, `params` and * `returnType` methods for method symbols, `baseClasses` for class symbols and so on. Some of these methods don't * make sense for certain subclasses of `Symbol` and return `NoSymbol`, `Nil` or other empty values. - * - * @contentDiagram hideNodes "*Api" */ trait Symbols { self: Universe => -- cgit v1.2.3 From 47f6d964a013db0861c6effd8c8ea7c7a78bd11d Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Thu, 11 Oct 2012 17:11:57 +0200 Subject: JavaUniverse --- src/reflect/scala/reflect/runtime/JavaUniverse.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index dc3cb3cbdc..e18435d5b0 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -7,8 +7,7 @@ import internal.{SomePhase, NoPhase, Phase, TreeGen} * * Should not be instantiated directly, use [[scala.reflect.runtime.universe]] instead. * - * @contentDiagram hideNodes "*Api" - * @groupprio Ungrouped -5 + * @contentDiagram hideNodes "*Api" "*Extractor" */ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.SymbolTable { self => -- cgit v1.2.3