diff options
Diffstat (limited to 'src')
87 files changed, 4272 insertions, 1088 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/compiler/scala/reflect/macros/runtime/Typers.scala b/src/compiler/scala/reflect/macros/runtime/Typers.scala index 9fa8567ada..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 @@ -25,7 +28,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 +52,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/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala index fb6765d9ed..b8b5f8033b 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 `<your expr>.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,26 +54,26 @@ 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) } def CannotReifyInvalidLazyVal(tree: ValDef) = { val msg = "internal error: could not reconstruct original lazy val due to missing accessor" - throw new UnexpectedReificationError(tree.pos, msg) + throw new UnexpectedReificationException(tree.pos, msg) } } diff --git a/src/compiler/scala/reflect/reify/Reifier.scala b/src/compiler/scala/reflect/reify/Reifier.scala index 5d3ac8cde0..b3224b1aa6 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 7db6394734..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} +import scala.reflect.macros.{ReificationException, UnexpectedReificationException, TypecheckException} import scala.reflect.macros.runtime.Context abstract class Taggers { @@ -65,22 +65,22 @@ 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 = { 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/reflect/reify/phases/Reshape.scala b/src/compiler/scala/reflect/reify/phases/Reshape.scala index 1b7509fdbe..9a1732a872 100644 --- a/src/compiler/scala/reflect/reify/phases/Reshape.scala +++ b/src/compiler/scala/reflect/reify/phases/Reshape.scala @@ -326,7 +326,8 @@ trait Reshape { case Some(ddef) => toPreTyperLazyVal(ddef) case None => - CannotReifyInvalidLazyVal(vdef) + if (reifyDebug) println("couldn't find corresponding lazy val accessor") + vdef } if (reifyDebug) println(s"reconstructed lazy val is $vdef1") vdef1::Nil 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/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/MemberLookup.scala b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala index 7f260bb90a..1248de625d 100644 --- a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala +++ b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala @@ -120,19 +120,17 @@ 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) => - 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)] = { @@ -153,7 +151,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/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 906c17faa0..a4ca881230 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 = comment flatMap (_.group) getOrElse "No Group" + def group = comment flatMap (_.group) getOrElse defaultGroup override def inTemplate = inTpl override def toRoot: List[MemberImpl] = this :: inTpl.toRoot def inDefinitionTemplates = @@ -284,7 +290,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 @@ -484,14 +491,28 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def inheritanceDiagram = makeInheritanceDiagram(this) def contentDiagram = makeContentDiagram(this) - def groupSearch[T](extractor: Comment => Option[T]): Option[T] = { - val comments = comment +: linearizationTemplates.collect { case dtpl: DocTemplateImpl => dtpl.comment } - comments.flatten.map(extractor).flatten.headOption + def groupSearch[T](extractor: Comment => T, default: T): T = { + // query this template + if (comment.isDefined) { + val entity = extractor(comment.get) + if (entity != default) return entity + } + // query linearization + 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)) - def groupPriority(group: String): Int = groupSearch(_.groupPrio.get(group)) getOrElse 0 - def groupName(group: String): String = groupSearch(_.groupNames.get(group)) getOrElse 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 { @@ -721,7 +742,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)) } } @@ -817,7 +838,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 @@ -1016,8 +1037,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: @@ -1057,6 +1078,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/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index ae38a082ca..b528948716 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: @@ -221,6 +222,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 +390,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 @@ -413,6 +416,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/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index ec3ed110fd..2e2c772a38 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/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 90d5a7ac75..14e5e352f7 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 = enteringPhase(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/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 2aeadb67d5..2c4034db84 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -391,6 +391,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, ( diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index a83787a43c..2c3ff0bfa4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1430,6 +1430,9 @@ trait Typers extends Modes with Adaptations with Tags { //see https://issues.scala-lang.org/browse/SI-6463 case _: ClassDef => implRestriction(tree, "nested class") + 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/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/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 "<root>" * and then when typing relative names, instead of picking <root>.scala.relect, typedIdentifier will pick up the 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: {{{ 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/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 = 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 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/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 */ diff --git a/src/reflect/scala/reflect/api/Annotations.scala b/src/reflect/scala/reflect/api/Annotations.scala index 37882a9f3c..fb353a5520 100644 --- a/src/reflect/scala/reflect/api/Annotations.scala +++ b/src/reflect/scala/reflect/api/Annotations.scala @@ -3,122 +3,195 @@ package api import scala.collection.immutable.ListMap -/** - * Defines the type hierarchy for annotations. +/** This trait provides annotation support for the reflection API. + * + * The API distinguishes between two kinds of annotations: + * + * <ul> + * <li>''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.</li> + * <li>''Scala annotations'': annotations on definitions or types produced by the Scala compiler.</li> + * </ul> + * + * 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. + * + * @contentDiagram hideNodes "*Api" */ 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. + * @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(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. + * @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])] } + /** 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. */ 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 */ + /** 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 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. + * @group API + */ trait LiteralArgumentApi { + /** The underlying compile-time constant value. */ def value: Constant } /** 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 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. + * @group API + */ trait ArrayArgumentApi { + /** The underlying array of Java annotation arguments. */ def args: Array[JavaArgument] } /** 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 def unapply(arg: NestedArgument): Option[Annotation] } + /** 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. */ def annotation: Annotation } }
\ No newline at end of file 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/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala index f2d8ef2eb9..a92fc5cbb3 100644 --- a/src/reflect/scala/reflect/api/Constants.scala +++ b/src/reflect/scala/reflect/api/Constants.scala @@ -7,50 +7,214 @@ package scala.reflect package api /** - * Defines the type hierachy for compile-time constants. + * 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. * - * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here. + * [[scala.reflect.api.Constants#Constant]] instances represent certain kinds of these expressions + * (with values stored in the `value` field and its strongly-typed views named `booleanValue`, `intValue` etc.), namely: + * 1. Literals of primitive value classes (bytes, shorts, ints, longs, floats, doubles, chars, booleans and voids). + * 1. String literals. + * 1. References to classes (typically constructed with [[scala.Predef#classOf]]). + * 1. References to enumeration values. + * + * Such constants are used to represent literals in abstract syntax trees (the [[scala.reflect.api.Trees#Literal]] node) + * and literal arguments for Java class file annotations (the [[scala.reflect.api.Annotations#LiteralArgument]] class). + * + * === Example === + * + * The `value` field deserves some explanation. Primitive and string values are represented as themselves, whereas + * references to classes and enums are a bit roundabout. + * + * Class references are represented as instances of [[scala.reflect.api.Types#Type]] + * (because when the Scala compiler processes a class reference, the underlying runtime class might not yet have been compiled). + * To convert such a reference to a runtime class, one should use the `runtimeClass` method of a mirror such as [[scala.reflect.api.Mirrors#RuntimeMirror]] + * (the simplest way to get such a mirror is using [[scala.reflect.runtime.package#currentMirror]]). + * + * Enumeration value references are represented as instances of [[scala.reflect.api.Symbols#Symbol]], which on JVM point to methods + * that return underlying enum values. To inspect an underlying enumeration or to get runtime value of a reference to an enum, + * one should use a [[scala.reflect.api.Mirrors#RuntimeMirror]] (the simplest way to get such a mirror is again [[scala.reflect.runtime.package#currentMirror]]). + + * {{{ + * enum JavaSimpleEnumeration { FOO, BAR } + * + * import java.lang.annotation.*; + * @Retention(RetentionPolicy.RUNTIME) + * @Target({ElementType.TYPE}) + * public @interface JavaSimpleAnnotation { + * Class<?> classRef(); + * JavaSimpleEnumeration enumRef(); + * } + * + * @JavaSimpleAnnotation( + * classRef = JavaAnnottee.class, + * enumRef = JavaSimpleEnumeration.BAR + * ) + * public class JavaAnnottee {} + * }}} + * {{{ + * import scala.reflect.runtime.universe._ + * import scala.reflect.runtime.{currentMirror => cm} + * + * object Test extends App { + * val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs + * def jarg(name: String) = jann(newTermName(name)).asInstanceOf[LiteralArgument].value + * + * val classRef = jarg("classRef").typeValue + * println(showRaw(classRef)) // TypeRef(ThisType(<empty>), JavaAnnottee, List()) + * println(cm.runtimeClass(classRef)) // class JavaAnnottee + * + * val enumRef = jarg("enumRef").symbolValue + * println(enumRef) // value BAR + * + * val siblings = enumRef.owner.typeSignature.declarations + * val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic) + * println(enumValues) // Scope{ + * // final val FOO: JavaSimpleEnumeration; + * // final val BAR: JavaSimpleEnumeration + * // } + * + * // doesn't work because of https://issues.scala-lang.org/browse/SI-6459 + * // val enumValue = mirror.reflectField(enumRef.asTerm).get + * val enumClass = cm.runtimeClass(enumRef.owner.asClass) + * val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null) + * println(enumValue) // BAR + * } + * }}} + * + * @contentDiagram hideNodes "*Api" */ 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(<empty>), 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. + * @group API + */ abstract class ConstantApi { + /** Payload of the constant, that can be accessed directly or pattern matched against. */ val value: Any + + /** Scala type that describes the constant. It is generated automatically based on the type of the value. */ def tpe: Type - def isNaN: Boolean - - 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 - - def convertTo(pt: Type): Constant } } diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala index b86f36420d..45bfddb55d 100644 --- a/src/reflect/scala/reflect/api/Exprs.scala +++ b/src/reflect/scala/reflect/api/Exprs.scala @@ -8,9 +8,29 @@ package api import scala.reflect.runtime.{universe => ru} +/** 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]]). + * + * 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. + * + * `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. + * + * `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#universe]], the default mirror is typically [[scala.reflect.runtime#currentMirror]]. + */ 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. + * @group Expressions + */ trait Expr[+T] extends Equals with Serializable { /** * Underlying mirror of this expr. @@ -19,23 +39,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 +86,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 +103,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 +121,9 @@ 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. + * @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 599c4ca426..a7d1ca05a6 100644 --- a/src/reflect/scala/reflect/api/FlagSets.scala +++ b/src/reflect/scala/reflect/api/FlagSets.scala @@ -3,32 +3,95 @@ package api import scala.language.implicitConversions +/** + * The trait that defines flag sets and operations on them. + * + * `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: + * + * - '''[[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. + * + * 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. + * + * To make `C` private, one would write something like: + * {{{ + * ClassDef(Modifiers(PRIVATE), newTypeName("C"), Nil, ...) + * }}} + * + * 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]] + * + */ 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. + * @group Flags + */ implicit def addFlagOps(left: FlagSet): FlagOps + /** A module that contains all possible values that can constitute flag sets. + * @group Flags + */ 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 { + /** 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 { /** Flag indicating that tree represents a trait */ val TRAIT: FlagSet @@ -106,6 +169,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 fbc29a514e..4286b2b45c 100644 --- a/src/reflect/scala/reflect/api/Importers.scala +++ b/src/reflect/scala/reflect/api/Importers.scala @@ -1,21 +1,97 @@ package scala.reflect package api +/** This trait provides support for importers, a facility to migrate reflection artifacts between universes. + * + * 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 `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 signatures into the target `Universe`. + * + * 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`. + * + * === 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. + * @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. + * 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 new file mode 100644 index 0000000000..df099006b5 --- /dev/null +++ b/src/reflect/scala/reflect/api/JavaMirrors.scala @@ -0,0 +1,52 @@ +package scala.reflect +package api + +/** A refinement of [[scala.reflect.api.Mirror]] for runtime reflection using JVM classloaders. + * + * 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/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 => + + /** 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`. + * @group 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/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]] + * + * @group JavaMirrors + */ + 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. + * + * 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/JavaUniverse.scala b/src/reflect/scala/reflect/api/JavaUniverse.scala index cc703e833d..f83692034f 100644 --- a/src/reflect/scala/reflect/api/JavaUniverse.scala +++ b/src/reflect/scala/reflect/api/JavaUniverse.scala @@ -1,19 +1,19 @@ 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 +/** 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 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 => + /* @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] @@ -21,6 +21,7 @@ trait JavaUniverse extends Universe with Mirrors { 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 2de0d7120e..b1290cc02e 100644 --- a/src/reflect/scala/reflect/api/Mirror.scala +++ b/src/reflect/scala/reflect/api/Mirror.scala @@ -2,32 +2,41 @@ package scala.reflect package api /** - * The base interface for all mirrors. + * The base class for all mirrors. * - * @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 - * 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. * - * @see [[Mirrors]] + * @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. */ + /** 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 +80,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 +107,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 bff899daa4..cc1b9762cb 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -1,13 +1,207 @@ package scala.reflect package api -/** - * Defines a type hierarchy for mirrors. +/** This trait provides support for Mirrors in the Scala Reflection API. * - * 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. + * `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. * - * On the JVM, there is a one to one correspondance between class loaders and mirrors. + * The two flavors of mirrors: + * + * <ul> + * <li>```“Classloader” mirrors```. These mirrors translate names to symbols + * (via methods `staticClass`/`staticModule`/`staticPackage`).</li> + * <li>```"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.</li> + * </ul> + * + * === 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(<classloader>)`, 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(<classloader>)`. + * 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(<value>)`. + * 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(<method symbol>)`. + * 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(<field or accessor symbol>)`. + * 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(<class symbol>)`, + * for ''inner classes'' `val mm2 = im.reflectClass(<module symbol>)`. + * 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.<init>(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(<module symbol>)`, + * for ''inner objects (modules)'' `val mm2 = im.reflectModule(<module symbol>)`. + * 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" */ trait Mirrors { self: Universe => @@ -15,27 +209,35 @@ 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. + * @group Mirrors + */ 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. + * @group Mirrors + */ 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 +305,10 @@ 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. + * @group Mirrors + */ trait FieldMirror { /** The object containing the field */ @@ -145,7 +350,10 @@ 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. + * @group Mirrors + */ trait MethodMirror { /** The receiver object of the method */ @@ -163,12 +371,12 @@ 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. + * @group Mirrors + */ 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,21 +388,12 @@ 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 */ + /** 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 { /** The Scala module symbol corresponding to the reflected object */ @@ -205,17 +404,12 @@ 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 */ + /** 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 { /** The Scala class symbol corresponding to the reflected class */ @@ -232,17 +426,12 @@ 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 */ + /** 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] { /** A reflective mirror for the given object. @@ -277,7 +466,10 @@ 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. + * @group Mirrors + */ 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 e8665ca736..02eb79f8ed 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -1,40 +1,70 @@ package scala.reflect package api -/** A trait that manages names. +/** This trait defines Names (a Scala reflection concept) and operations on them. * - * @see TermName - * @see TypeName + * 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. + * + * === 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 the [[docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for more about Scala Reflection. + * + * @contentDiagram hideNodes "*Api" */ 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")`. + * @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 - * - * 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. + /** 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 - implicit val TypeNameTag: ClassTag[TypeName] - /** The abstract type of names representing types */ + /** 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] + + /** 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 names that's supported on reflect mirror via an - * implicit conversion in reflect.ops + /** The API of Name instances. + * @group API */ abstract class NameApi { /** Checks wether the name is a a term name */ @@ -69,18 +99,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 - - /** 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/Position.scala b/src/reflect/scala/reflect/api/Position.scala index 9c63e4becf..61d643b449 100644 --- a/src/reflect/scala/reflect/api/Position.scala +++ b/src/reflect/scala/reflect/api/Position.scala @@ -1,64 +1,65 @@ package scala.reflect package api -/** 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. +import scala.reflect.macros.Attachments + +/** 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. + * + * 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. + * + * <b>Please note that this trait may be refactored in future versions of the Scala reflection API.</b> * - * INV1: A tree with an offset position never contains a child + * @see [[http://docs.scala-lang.org/overviews/reflection/names-exprs-scopes-more.html]] + * + * 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, + * - 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. * - * 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 { + /** @inheritdoc */ type Pos >: Null <: Position /** 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. + * + * @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 @@ -69,36 +70,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. @@ -121,7 +132,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. */ @@ -154,14 +165,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/Positions.scala b/src/reflect/scala/reflect/api/Positions.scala index 5c530e7e70..8d8a0081cc 100644 --- a/src/reflect/scala/reflect/api/Positions.scala +++ b/src/reflect/scala/reflect/api/Positions.scala @@ -1,26 +1,34 @@ package scala.reflect package api -/** - * Defines the type hierachy for positions. +/** This trait defines the concept of positions and operations on them. * - * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here. + * @see [[scala.reflect.api.Position]] + * + * @contentDiagram hideNodes "*Api" */ trait Positions { self: Universe => - /** .. */ + /** 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 @@ -28,6 +36,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 @@ -35,6 +44,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 65ff2ed9fa..1e8161aeef 100644 --- a/src/reflect/scala/reflect/api/Printers.scala +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -3,9 +3,135 @@ package api import java.io.{ PrintWriter, StringWriter } +/** Utilities for nicely printing [[scala.reflect.api.Trees]] and [[scala.reflect.api.Types]]. + * + * === 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._ + * import scala.reflect.runtime.universe._ + * + * scala> def tree = reify{ final class C { def x = 2 } }.tree + * tree: reflect.runtime.universe.Tree + * + * scala> show(tree) + * res0: String = + * { + * final class C extends AnyRef { + * def <init>() = { + * super.<init>(); + * () + * }; + * def x = 2 + * }; + * () + * } + * }}} + * + * 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. + * + * 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( + * 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(()))) + * }}} + * + * 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} + * + * 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)) + * }}} + * + * === Printing Types === + * + * The method `show` + * {{{ + * 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]} + * }}} + * + * 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( + * List(TypeRef(ThisType(scala), newTypeName("AnyRef"), List())), + * Scope( + * newTermName("x"), + * newTermName("y"))) + * }}} + * + * `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())), + * Scope( + * 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 => - trait TreePrinter { + /** @group Printers */ + protected trait TreePrinter { def print(args: Any*) protected var printTypes = false protected var printIds = false @@ -21,13 +147,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) @@ -41,41 +170,54 @@ 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. + /** 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 = render(any, newTreePrinter(_), printTypes, printIds, printKinds, printMirrors) /** Hook to define what `show(...)` means. + * @group Printers */ - def newTreePrinter(out: PrintWriter): TreePrinter + 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 = render(any, newRawTreePrinter(_), printTypes, printIds, printKinds, printMirrors) /** Hook to define what `showRaw(...)` means. + * @group Printers */ - def newRawTreePrinter(out: PrintWriter): TreePrinter + 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 d30da07ad5..80683c8e76 100644 --- a/src/reflect/scala/reflect/api/Scopes.scala +++ b/src/reflect/scala/reflect/api/Scopes.scala @@ -1,34 +1,57 @@ package scala.reflect package api -/** - * Defines the type hierachy for scopes. +/** This trait provides support for scopes in the reflection API. * - * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here. + * 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]], + * 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. + * @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] - /** The type of member scopes, as in class definitions, for example. */ + /** 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. + * @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. - * 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] @@ -36,15 +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] - - /** 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 diff --git a/src/reflect/scala/reflect/api/StandardDefinitions.scala b/src/reflect/scala/reflect/api/StandardDefinitions.scala index 03f2a6b0aa..a31a501357 100644 --- a/src/reflect/scala/reflect/api/StandardDefinitions.scala +++ b/src/reflect/scala/reflect/api/StandardDefinitions.scala @@ -5,139 +5,305 @@ package scala.reflect package api -/** - * Defines standard symbols and types. +/** All Scala standard symbols and types. + * + * 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 => - /** A value containing all standard defnitions. */ + /** 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 class symbol of package `scala`. */ + /** The module class symbol of package `scala`. */ def ScalaPackageClass: ClassSymbol - /** The module class symbol of package `scala`. */ + /** The module symbol of package `scala`. */ def ScalaPackage: ModuleSymbol - // top types + /** The class symbol of core class `scala.Any`. */ def AnyClass : ClassSymbol + + /** The class symbol of core class `scala.AnyVal`. */ def AnyValClass: ClassSymbol + + /** The class symbol of core class `java.lang.Object`. */ def ObjectClass: ClassSymbol + + /** The type symbol of core class `scala.AnyRef`. */ def AnyRefClass: TypeSymbol - // bottom types + /** The class symbol of core class `scala.Null`. */ def NullClass : ClassSymbol + + /** The class symbol of core class `scala.Nothing`. */ def NothingClass: ClassSymbol - // the scala value classes + /** The class symbol of primitive class `scala.Unit`. */ def UnitClass : ClassSymbol + + /** The class symbol of primitive class `scala.Byte`. */ def ByteClass : ClassSymbol + + /** The class symbol of primitive class `scala.Short`. */ def ShortClass : ClassSymbol + + /** The class symbol of primitive class `scala.Char`. */ def CharClass : ClassSymbol + + /** The class symbol of primitive class `scala.Int`. */ def IntClass : ClassSymbol + + /** The class symbol of primitive class `scala.Long`. */ def LongClass : ClassSymbol + + /** The class symbol of primitive class `scala.Float`. */ def FloatClass : ClassSymbol + + /** The class symbol of primitive class `scala.Double`. */ def DoubleClass : ClassSymbol + + /** The class symbol of primitive class `scala.Boolean`. */ def BooleanClass: ClassSymbol - /** The class symbol of class `String`. */ + /** The class symbol of class `scala.String`. */ def StringClass : ClassSymbol - /** The class symbol of class `Class`. */ + /** The class symbol of class `java.lang.Class`. */ def ClassClass : ClassSymbol - /** The class symbol of class `Array`. */ + /** The class symbol of class `scala.Array`. */ def ArrayClass : ClassSymbol - /** The class symbol of class `List`. */ + /** The class symbol of class `scala.List`. */ def ListClass : ClassSymbol - /** The module symbol of `scala.Predef`. */ + /** The module symbol of module `scala.Predef`. */ def PredefModule: ModuleSymbol + /** The module class symbol of package `java.lang`. */ def JavaLangPackageClass: ClassSymbol + + /** The module symbol of package `java.lang`. */ def JavaLangPackage: ModuleSymbol + + /** The module symbol of module `scala.Array`. */ def ArrayModule: ModuleSymbol + + /** The method symbol of method `apply` in module `scala.Array`. */ def ArrayModule_overloadedApply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod + + /** The method symbol of method `apply` in class `scala.Array`. */ def Array_apply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod + + /** The method symbol of method `clone` in class `scala.Array`. */ def Array_clone: TermSymbol // todo. fix the bug in Definitions.getMemberMethod + + /** The method symbol of method `length` in class `scala.Array`. */ def Array_length: TermSymbol // todo. fix the bug in Definitions.getMemberMethod + + /** The method symbol of method `update` in class `scala.Array`. */ def Array_update: TermSymbol // todo. fix the bug in Definitions.getMemberMethod + + /** A dummy class symbol that is used to indicate by-name parameters. + * + * {{{ + * scala> class C { def m(x: => Int) = ??? } + * defined class C + * + * scala> import scala.reflect.runtime.universe._ + * import scala.reflect.runtime.universe._ + * + * scala> val m = typeOf[C].member(newTermName("m")).asMethod + * m: reflect.runtime.universe.MethodSymbol = method m + * + * scala> m.params(0)(0).typeSignature + * res1: reflect.runtime.universe.Type = => scala.Int + * + * scala> showRaw(m.params(0)(0).typeSignature) + * res2: String = TypeRef( + * ThisType(scala), + * scala.<byname>, // <-- ByNameParamClass + * List(TypeRef(ThisType(scala), scala.Int, List()))) + * }}} + */ def ByNameParamClass: ClassSymbol - def 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 + + /** A dummy class symbol that is used to indicate repeated parameters + * compiled by the Java compiler. + * + * {{{ + * class C { + * public void m(Object... x) {} + * } + * }}} + * + * {{{ + * scala> import scala.reflect.runtime.universe._ + * import scala.reflect.runtime.universe._ + * + * scala> val m = typeOf[C].member(newTermName("m")).asMethod + * m: reflect.runtime.universe.MethodSymbol = method m + * + * scala> m.params(0)(0).typeSignature + * res1: reflect.runtime.universe.Type = <repeated...>[Object] + * + * scala> showRaw(m.params(0)(0).typeSignature) + * res2: String = TypeRef( + * ThisType(scala), + * scala.<repeated...>, // <-- JavaRepeatedParamClass + * List(TypeRef(ThisType(java.lang), Object, List()))) + * }}} + */ def JavaRepeatedParamClass: ClassSymbol + + /** A dummy class symbol that is used to indicate repeated parameters + * compiled by the Scala compiler. + * + * {{{ + * scala> class C { def m(x: Int*) = ??? } + * defined class C + * + * scala> import scala.reflect.runtime.universe._ + * import scala.reflect.runtime.universe._ + * + * scala> val m = typeOf[C].member(newTermName("m")).asMethod + * m: reflect.runtime.universe.MethodSymbol = method m + * + * scala> m.params(0)(0).typeSignature + * res1: reflect.runtime.universe.Type = scala.Int* + * + * scala> showRaw(m.params(0)(0).typeSignature) + * res2: String = TypeRef( + * ThisType(scala), + * scala.<repeated>, // <-- RepeatedParamClass + * List(TypeRef(ThisType(scala), scala.Int, List()))) + * }}} + */ + def RepeatedParamClass: ClassSymbol + + /** The module symbol of module `scala.List`. */ def ListModule: ModuleSymbol + + /** The method symbol of method `apply` in class `scala.List`. */ def List_apply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod + + /** The module symbol of module `scala.collection.immutable.Nil`. */ def NilModule: ModuleSymbol - def NoneModule: ModuleSymbol + + /** The class symbol of class `scala.Option`. */ def OptionClass: ClassSymbol - def ProductClass : Array[ClassSymbol] - def RepeatedParamClass: ClassSymbol - def SeqClass: ClassSymbol - def SeqModule: ModuleSymbol - def SomeClass: ClassSymbol + + /** The module symbol of module `scala.None`. */ + def NoneModule: ModuleSymbol + + /** The module symbol of module `scala.Some`. */ def SomeModule: ModuleSymbol - def StringBuilderClass: ClassSymbol - def SymbolClass : ClassSymbol - def TraversableClass: ClassSymbol + + /** 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. */ + /** Defines standard types. + * @group Definitions + */ 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 354a9f9328..fc18c02706 100644 --- a/src/reflect/scala/reflect/api/StandardNames.scala +++ b/src/reflect/scala/reflect/api/StandardNames.scala @@ -10,35 +10,95 @@ 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. + * Standard names are names that are essential to creating trees or to reflecting Scala artifacts. + * For example, `CONSTRUCTOR` (aka `<init>` on JVM) is necessary to create and invoke constructors. + * + * These standard names can be referred to using [[nme `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 [[TermNamesApi standard term names]]. + * @group StandardNames + */ val nme: TermNamesApi + + /** A value containing all [[TypeNamesApi standard type names]]. + * @group StandardNames + */ val tpnme: TypeNamesApi + /** 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 + + /** The term or type name `_`. + * Used to construct trees that correspond to underscores in Scala. + */ val WILDCARD: NameType - val ROOT: 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 [[Trees#Modifiers]], for [[Trees#This]], + * for [[Trees#Super]], etc. + */ val EMPTY: NameType + + /** The term or type name `<error>`. + * Indicates that the enclosing tree or symbol contains a compilation error. + */ val ERROR: NameType + + /** The term or type name `package`. + * Used to get modules representing package objects. + */ val PACKAGE: NameType } + /** Defines standard term names that can be accessed via the [[nme]] member. + * @group API + */ trait TermNamesApi extends NamesApi { + /** @inheritdoc */ type NameType = TermName + + /** The term name `<init>`. + * Represents the constructor name on the JVM. + */ val CONSTRUCTOR: NameType + + /** The term name `_root_`. + * Represents the root package. + */ val ROOTPKG: NameType + + /** The string " " (a single whitespace). + * `LOCAL_SUFFIX_STRING` is appended to the names of local identifiers, + * when it's necessary to prevent a naming conflict. For example, underlying fields + * of non-private vals and vars are renamed using `LOCAL_SUFFIX_STRING`. + */ val LOCAL_SUFFIX_STRING: String } + /** Defines standard type names that can be accessed via the [[tpnme]] member. + * @group API + */ trait TypeNamesApi extends NamesApi { + /** @inheritdoc */ type NameType = TypeName - val EMPTY: NameType + + /** 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..993cbd97a5 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -1,85 +1,164 @@ package scala.reflect package api -/** - * Defines the type hierachy for symbols +/** This trait defines symbols and operations on them. * - * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here. + * 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 an associated symbol. + * + * 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. + * + * @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. + * + * @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 API of symbols. + * 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 FreeTerm 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 => /** The owner of this symbol. This is the symbol @@ -90,6 +169,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 @@ -98,15 +179,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 @@ -114,11 +198,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") @@ -126,21 +214,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 = @@ -151,92 +247,135 @@ 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, * 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. + * + * @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. - * 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`. + * + * @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 *******************/ @@ -244,11 +383,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 @@ -258,20 +401,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 @@ -299,20 +450,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 @@ -320,62 +479,96 @@ 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 - /** ... + /** 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. + * + * @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 API of term symbols. + * The main source of information about symbols is the [[Symbols]] page. + * + * $SYMACCESSORS + * @group API + */ trait TermSymbolApi extends SymbolApi { this: TermSymbol => /** Term symbols have their names of type `TermName`. */ @@ -385,78 +578,117 @@ 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 API of type symbols. + * The main source of information about symbols is the [[Symbols]] page. + * + * $SYMACCESSORS + * @group API + */ trait TypeSymbolApi extends SymbolApi { this: TypeSymbol => /** Type symbols have their names of type `TypeName`. */ @@ -468,11 +700,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 @@ -486,42 +722,64 @@ 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 API of method symbols. + * The main source of information about symbols is the [[Symbols]] page. + * + * $SYMACCESSORS + * @group API + */ trait MethodSymbolApi extends TermSymbolApi { this: MethodSymbol => final override def isMethod = true final override def asMethod = this @@ -530,13 +788,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. @@ -545,22 +811,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 API of module symbols. + * The main source of information about symbols is the [[Symbols]] page. + * + * $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 @@ -569,7 +849,12 @@ 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 [[Symbols]] page. + * + * $SYMACCESSORS + * @group API + */ trait ClassSymbolApi extends TypeSymbolApi { this: ClassSymbol => final override def isClass = true final override def asClass = this @@ -577,82 +862,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 API of free term symbols. + * The main source of information about symbols is the [[Symbols]] page. + * + * $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 term symbols */ + /** The API of free type symbols. + * The main source of information about symbols is the [[Symbols]] page. + * + * $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 } } diff --git a/src/reflect/scala/reflect/api/TagInterop.scala b/src/reflect/scala/reflect/api/TagInterop.scala index fc0558d717..4e43f59706 100644 --- a/src/reflect/scala/reflect/api/TagInterop.scala +++ b/src/reflect/scala/reflect/api/TagInterop.scala @@ -1,26 +1,37 @@ 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 // 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]]) * }}} + * @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.") /** - * 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]]) * }}} + * @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/TreeCreator.scala b/src/reflect/scala/reflect/api/TreeCreator.scala index a8e8ae1b58..cba90b72e6 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. + * 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/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index bbd5d00be3..9ff3efc799 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -5,67 +5,62 @@ package scala.reflect package api -// Syncnote: Trees are currently not thread-safe. +/** 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.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)) + * + * @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 + * + * @contentDiagram hideNodes "*Api" + */ 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. + * @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 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 => - // 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,32 +71,37 @@ 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. + * 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 - /** 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 - /** ... */ - def hasSymbolField: Boolean - /** Provides an alternate if tree is empty * @param alt The alternate tree * @return If this tree is non empty, this tree, otherwise `alt`. @@ -175,166 +175,239 @@ 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 `<List>` part of `Ident("List": TermName)`. + */ def name: Name } /** 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 => - def qualifier: Tree // empty for Idents + /** The qualifier of the reference. + * For example, the `<scala>` part of `Select("scala": TermName, "List": TermName)`. + * `EmptyTree` for `Ident` instances. + */ + def qualifier: Tree + + /** @inheritdoc */ def name: Name } /** 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 } /** 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 + + /** Body of the package definition. */ val stats: List[Tree] } /** 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)`. @@ -345,32 +418,47 @@ 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 + + /** The name of the class. */ val name: TypeName + + /** The type parameters of the class. */ val tparams: List[TypeDef] + + /** @inheritdoc */ val impl: Template } /** 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)`. @@ -381,32 +469,55 @@ 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 + + /** The name of the module. */ val name: TermName + + /** @inheritdoc */ val impl: Template } /** 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. + + /** 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 } @@ -417,15 +528,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)`. @@ -441,31 +557,46 @@ 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 + + /** @inheritdoc */ val name: TermName + + /** @inheritdoc */ val tpt: Tree + + /** @inheritdoc */ val rhs: Tree } /** 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)`. @@ -475,33 +606,52 @@ 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 + + /** @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 } /** 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)`. @@ -514,17 +664,29 @@ 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 + + /** @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 } @@ -541,15 +703,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)`. @@ -558,21 +725,33 @@ 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 + + /** 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 } @@ -586,30 +765,51 @@ 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 + + /** 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 } @@ -617,15 +817,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)`. @@ -644,15 +849,25 @@ 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]]. + */ val expr: Tree + + /** The selectors of the import. + * See the example for [[scala.reflect.api.Trees#ImportExtractor]]. + */ val selectors: List[ImportSelector] } @@ -660,15 +875,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)`. @@ -688,28 +908,45 @@ 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] + + /** 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] } - /** 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)`. @@ -718,30 +955,43 @@ 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. + */ val stats: List[Tree] + + /** The last expression in the block. */ val expr: Tree } /** 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)`. @@ -751,16 +1001,28 @@ 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 + + /** 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 } @@ -769,58 +1031,76 @@ 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] } /** 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 } @@ -830,30 +1110,46 @@ 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)`. + */ 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 } @@ -883,41 +1179,62 @@ 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]]. + */ val fun: Tree + + /** The arguments of the unapplication. + * See the example for [[scala.reflect.api.Trees#UnApplyExtractor]]. + */ 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)`. @@ -927,56 +1244,83 @@ 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. + */ val vparams: List[ValDef] + + /** The body of the function. + */ 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. + */ val lhs: Tree + + /** The right-hand side of the assignment. + */ val rhs: Tree } /** 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)`. @@ -989,27 +1333,41 @@ 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. + */ val lhs: Tree + + /** The right-hand side of the expression. + */ 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)`. @@ -1018,16 +1376,28 @@ 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. + */ 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 } @@ -1041,15 +1411,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)`. @@ -1058,27 +1433,39 @@ 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 + + /** The arms of the pattern match. */ 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)`. @@ -1087,26 +1474,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 } - /** [Eugene++] 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)`. @@ -1115,55 +1512,77 @@ 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 + + /** The `catch` pattern-matching clauses of the try. */ val catches: List[CaseDef] + + /** The `finally` part of the try. */ 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 @@ -1175,6 +1594,7 @@ trait Trees { self: Universe => * This node always occurs in the following context: * * (`new` tpt).<init>[targs](args) + * @group Extractors */ abstract class NewExtractor { /** A user level `new`. @@ -1186,50 +1606,75 @@ 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]]. + */ 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 + + /** The type being ascribed to the expression. */ val tpt: Tree } /** 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 + + /** The arguments of the application. */ val args: List[Tree] } @@ -1237,40 +1682,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)`. @@ -1285,27 +1745,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)`. @@ -1321,27 +1789,43 @@ 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]]. + */ val qual: Tree + + /** The selector of the `super` expression. + * See the example for [[scala.reflect.api.Trees#SuperExtractor]]. + */ 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)`. @@ -1351,55 +1835,77 @@ 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 ??? + * @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. + */ val qual: TypeName } - /** Designator <qualifier> . <name> */ + /** A member selection <qualifier> . <name> + * @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 + + /** @inheritdoc */ val name: Name } - /** Identifier <name> */ + /** 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)`. @@ -1409,32 +1915,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 + * + * <b>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)`. @@ -1455,40 +1971,54 @@ 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 } @@ -1496,15 +2026,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)`. @@ -1512,54 +2047,76 @@ 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 + + /** The annotee. */ 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 <qualifier> # <name>, eliminated by RefCheck */ + /** Type selection <qualifier> # <name>, 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)`. @@ -1568,151 +2125,219 @@ 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 + + /** @inheritdoc */ val name: TypeName } - /** Intersection type <parent1> with ... with <parentN> { <decls> }, eliminated by RefCheck */ + /** Intersection type <parent1> with ... with <parentN> { <decls> }, 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 <tpt> [ <args> ], eliminated by RefCheck */ + /** Applied type <tpt> [ <args> ], 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 + + /** The arguments of the application. */ 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(<scala.Nothing>)` if not specified explicitly. + */ val lo: Tree + + /** The upper bound. + * Is equal to `Ident(<scala.Any>)` if not specified explicitly. + */ val hi: Tree } - /** Document me! */ + /** 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 + + /** The clauses of the definition of the existential type. */ val whereClauses: List[Tree] } /** 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. + */ def original: Tree } @@ -1720,156 +2345,415 @@ 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 ---------------------------------------------- - /** @param sym the class symbol - * @param impl the implementation template + /** A factory method for `ClassDef` nodes. + * @group Factories */ def ClassDef(sym: Symbol, impl: Template): ClassDef - /** - * @param sym the class symbol - * @param impl the implementation template + /** 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 TypeDef node which defines given `sym` with given tight hand side `rhs`. */ + /** A factory method for `TypeDef` nodes. + * @group Factories + */ 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. + * @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 - /** Block factory that flattens directly nested blocks. + /** A factory method for `Block` nodes. + * Flattens directly nested blocks. + * @group Factories */ def Block(stats: Tree*): Block - /** casedef shorthand */ + /** 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).<init>(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 `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 standard (lazy) tree copier + /** 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 - * tree copiers are made available by an implicit conversion in reflect.ops + * @group API */ 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. + * @group Traversal + */ 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)) @@ -1877,6 +2761,7 @@ trait Trees { self: Universe => ) } + /** Performs a traversal with a given owner symbol. */ def atOwner(owner: Symbol)(traverse: => Unit) { val prevOwner = currentOwner currentOwner = owner @@ -1889,49 +2774,81 @@ 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. + * @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. */ 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 @@ -1941,39 +2858,83 @@ trait Trees { self: Universe => } } + /** 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. + * @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 + * @group API + */ 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. + * @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, EmptyTypeName, List()) + def apply(): Modifiers = Modifiers(NoFlags, tpnme.EMPTY, List()) def apply(flags: FlagSet, privateWithin: Name, annotations: List[Tree]): Modifiers } + /** The factory for `Modifiers` instances. + * @group Traversal + */ def Modifiers(flags: FlagSet, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List()) - def Modifiers(flags: FlagSet): Modifiers = Modifiers(flags, EmptyTypeName) - /** ... */ + /** 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. + * @group Traversal + */ lazy val NoMods = Modifiers() } diff --git a/src/reflect/scala/reflect/api/TypeCreator.scala b/src/reflect/scala/reflect/api/TypeCreator.scala index 2b3ef4320b..9c386f2939 100644 --- a/src/reflect/scala/reflect/api/TypeCreator.scala +++ b/src/reflect/scala/reflect/api/TypeCreator.scala @@ -3,23 +3,7 @@ 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 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 fc3f067a96..812d5199fc 100644 --- a/src/reflect/scala/reflect/api/TypeTags.scala +++ b/src/reflect/scala/reflect/api/TypeTags.scala @@ -18,143 +18,168 @@ import scala.language.implicitConversions * 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. - * - * 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]]. - * - * @see [[scala.reflect.ClassTag]], [[scala.reflect.api.Universe#TypeTag]], [[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]]] - * <console>: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`: + * + * <ul> + * <li>[[scala.reflect.api.TypeTags#TypeTag]]. <br/>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]`.</li> + * + * <li>[[scala.reflect.ClassTag]]. <br/>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]]</li> + * + * <li>[[scala.reflect.api.TypeTags#WeakTypeTag]]. <br/>A type descriptor for abstract + * types (see description below).</li> + * </ul> + * + * 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: + * {{{ + * 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) + * }}} + * + * === #3 Context bound of a type parameter === + * + * ...on methods or classes. The above example can be implemented as follows: * * {{{ - * 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._ + * + * 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() + * + * scala> paramInfo(List(1, 2)) + * type of List(1, 2) has type arguments List(Int) * }}} + * + * === `WeakTypeTag`s === * - * 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. + *`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]`. * - * 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. + * 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") + * } + * + * scala> def foo[T] = weakParamInfo(List[T]()) + * foo: [T]=> Unit * - * === Backward compatibility with Manifests === + * scala> foo[Int] + * type of List() has type arguments List(T) + * }}} * - * Type tags correspond loosely to manifests. + * === TypeTags and Manifests === * - * 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, + * `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. * - * 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. + * <ul> + * <li>'''[[scala.reflect.OptManifest]] is not supported.''' <br/>This is because `Tag`s + * can reify arbitrary types, so they are always available.<li> * - * In most cases it will be enough to replace ClassManifest with ClassTag and Manifest with TypeTag. - * There are however a few caveats: + * <li>'''There is no equivalent for [[scala.reflect.AnyValManifest]].''' <br/>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 + * `<tag>.tpe.typeSymbol.isPrimitiveValueClass`.</li> * - * 1) The notion of OptManifest is no longer supported. Tags can reify arbitrary types, so they are always available. + * <li>'''There are no replacement for factory methods defined in the `Manifest` + * companion objects'''. <br/>Instead, one could generate corresponding types using the + * reflection APIs provided by Java (for classes) and Scala (for types).</li> * - * 2) There's no equivalent for AnyValManifest. Consider comparing your tag with one of the base tags - * (defined in the corresponding companion objects) to find out whether it represents a primitive value class. - * You can also use `<tag>.tpe.typeSymbol.isPrimitiveValueClass` for that purpose (requires scala-reflect.jar). + * <li>'''Certain manifest operations(i.e., <:<, >:> and typeArguments) are not + * supported.''' <br/>Instead, one culd use the reflection APIs provided by Java (for + * classes) and Scala (for types).</li> + *</ul> * - * 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). + * 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. * - * 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. + * 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 => 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 */ @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 @@ -171,15 +196,22 @@ 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 + "]" } /** * Type tags corresponding to primitive types and constructor/extractor for WeakTypeTags. + * @group TypeTags */ object WeakTypeTag { val Byte : WeakTypeTag[scala.Byte] = TypeTag.Byte @@ -222,6 +254,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] = { @@ -232,11 +265,12 @@ 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 <b>not</b> contain any references to * 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 { @@ -245,13 +279,23 @@ 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. + * @group TypeTags + */ 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) @@ -292,6 +336,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]] @@ -300,12 +345,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) @@ -313,22 +360,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 af70c9e761..2267f21609 100644 --- a/src/reflect/scala/reflect/api/Types.scala +++ b/src/reflect/scala/reflect/api/Types.scala @@ -1,37 +1,102 @@ package scala.reflect package api -/** - * Defines the type hierachy for types. +/** A trait that defines types and operations on them. * - * Note: Because of implementation details, some type factories have return type `Type` - * instead of a more precise type. + * 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. * - * @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`. + * 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.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`. + * 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 should be avoided if possible. + * + * === Using types === + * + * 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 + * 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 + * 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 === + * + * {{{ + * 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] + * }}} + * + * @groupname TypeCreators Types - Creation + * @groupname TypeOps Types - Operations + * + * @contentDiagram hideNodes "*Api" */ 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, <x>)`, where `<x>` stands for * the symbol for `x`. + * @group Types */ 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. + * @group API */ abstract class TypeApi { /** The term symbol associated with the type, or `NoSymbol` for types @@ -92,7 +157,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 @@ -186,11 +252,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] @@ -199,19 +268,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 { /** @@ -221,8 +296,12 @@ 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. + * @group API + */ trait ThisTypeApi extends TypeApi { this: ThisType => + /** The underlying class symbol. */ val sym: Symbol } @@ -233,29 +312,41 @@ 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 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. + * @group API + */ 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 @@ -266,27 +357,43 @@ 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 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. + * @group API + */ 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. @@ -295,27 +402,37 @@ 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 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. + * @group API + */ trait ConstantTypeApi extends TypeApi { this: ConstantType => + /** The compile-time constant underlying this type. */ val value: Constant } @@ -329,40 +446,61 @@ 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 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. + * @group API + */ 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] } /** 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] @@ -373,20 +511,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 @@ -398,9 +542,15 @@ 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. + * @group API + */ 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 } @@ -413,44 +563,63 @@ 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 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. + * @group API + */ 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 } /** 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)` @@ -466,128 +635,183 @@ 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 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. + * @group API + */ 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 } /** 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 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. + * @group API + */ trait NullaryMethodTypeApi extends TypeApi { this: NullaryMethodType => + /** The result type of the method. */ val resultType: Type } /** 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 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. + * @group API + */ trait PolyTypeApi extends TypeApi { this: PolyType => + /** The symbols corresponding to the type parameters. */ val typeParams: List[Symbol] + + /** The underlying type. */ val resultType: Type } /** 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 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. + * @group API + */ 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 } /** The `AnnotatedType` type signature is used for annotated types of the * for `<type> @<annotation>`. + * @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 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. + * @group API + */ 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 } @@ -600,34 +824,51 @@ 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 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. + * @group API + */ 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 } /** 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 @@ -640,55 +881,77 @@ 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 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. + * @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 @@ -696,15 +959,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 @@ -725,6 +992,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 7d0f6cf0d6..7d1f5c9df1 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -1,6 +1,58 @@ package scala.reflect package api +/** + * `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. + * + * [[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. + * + * `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 + * - [[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. + * + * 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] + * }}} + * + * To obtain a `Universe` for use within a Scala macro, use [[scala.reflect.macros.Context#universe]]. For example: + * {{{ + * 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._ + * ... + * } + * }}} + * + * For more information about `Universe`s, see the [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Universes]] + * + * @groupprio Universe -1 + * + * @contentDiagram hideNodes "*Api" + */ abstract class Universe extends Symbols with Types with FlagSets @@ -20,61 +72,20 @@ 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)) - * 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. * - * 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", <Int>, 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` // using the mechanism implemented in `scala.tools.reflect.FastTrack` diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala index 0b2a43936e..bd9c72a839 100644 --- a/src/reflect/scala/reflect/api/package.scala +++ b/src/reflect/scala/reflect/api/package.scala @@ -2,72 +2,35 @@ 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 (located in scala-reflect.jar). + * + * 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. + * + * 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 + * @groupprio Tags 11 + * @groupdesc API The methods available for each reflection entity, without the implementation. Since the + * 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. + * @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 { 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 diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index b4f03cfdd1..eaa05bc89d 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 hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol val isError = hasSymbolField && 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 _ => 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/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 7d0c05bc81..ee97b3fe2a 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/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index e15340543e..92db92d5f3 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3923,7 +3923,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 @@ -3943,7 +3953,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)) @@ -6330,21 +6346,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 _ => } @@ -6353,14 +6374,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/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala index 151a64daff..5456d66584 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 @@ -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/api/Attachments.scala b/src/reflect/scala/reflect/macros/Attachments.scala index edbb0131ca..ba5ccf88f1 100644 --- a/src/reflect/scala/reflect/api/Attachments.scala +++ b/src/reflect/scala/reflect/macros/Attachments.scala @@ -1,12 +1,20 @@ package scala.reflect -package api +package macros -/** Attachments is a generalization of Position. Typically it stores a Position of a tree, but this can be extended to +/** 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]`. * - * 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. + * 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 => @@ -30,8 +38,7 @@ abstract class Attachments { self => (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. + * 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) diff --git a/src/reflect/scala/reflect/macros/Context.scala b/src/reflect/scala/reflect/macros/Context.scala index 7a365ed37b..1f6e97adbc 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..6aab3d5b02 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 c2d4d8a3ab..bf73c36b1b 100644 --- a/src/reflect/scala/reflect/macros/Parsers.scala +++ b/src/reflect/scala/reflect/macros/Parsers.scala @@ -1,14 +1,19 @@ 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 } -// 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) diff --git a/src/reflect/scala/reflect/macros/Reifiers.scala b/src/reflect/scala/reflect/macros/Reifiers.scala index ed31663c68..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 => @@ -76,6 +79,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) 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 eef6507418..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 => @@ -24,11 +27,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 +39,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 +81,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/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index 97d0a8d98a..86bc37b4c9 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -1,69 +1,125 @@ 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`. + * @groupname Macros Macro Specific Additions + * @groupprio Macros -1 + * + * @contentDiagram hideNodes "*Api" + */ abstract class Universe extends scala.reflect.api.Universe { + /** 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 { - /** ... */ - def attachments: scala.reflect.api.Attachments { type Pos = Position } + /** 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 } // 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 => + /** 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 } // 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 => - /** ... */ + /** 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 * 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 @@ -79,55 +135,72 @@ 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 + * @group API */ 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 + * @group API */ 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 + * @group API */ trait IdentContextApi extends IdentApi { this: Ident => + /** Was this ident created from a backquoted identifier? */ def isBackquoted: Boolean } /** 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. + * @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). */ @@ -137,10 +210,15 @@ abstract class Universe extends scala.reflect.api.Universe { def units: Iterator[CompilationUnit] } + /** 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. @@ -148,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. */ diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala new file mode 100644 index 0000000000..3a2f04bcf2 --- /dev/null +++ b/src/reflect/scala/reflect/macros/package.scala @@ -0,0 +1,12 @@ +package scala.reflect + +/** 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. + * + * 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 diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index f7664a46cc..f517c30fe6 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]]() @@ -446,8 +446,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUnive 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 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUnive 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 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUnive 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)" } @@ -1279,6 +1270,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/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index 1d875b10f1..e18435d5b0 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -3,8 +3,11 @@ 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.universe]] instead. + * + * @contentDiagram hideNodes "*Api" "*Extractor" */ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.SymbolTable { self => 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 08d58aaadc..7d04202455 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 27107856f3..2b192ce570 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 775583649f..366b4319c3 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..b97913daf0 100644 --- a/src/reflect/scala/reflect/runtime/package.scala +++ b/src/reflect/scala/reflect/runtime/package.scala @@ -1,17 +1,30 @@ 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 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. + * 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` def currentMirror: universe.Mirror = ??? // macro } 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 |