diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-09-19 15:04:38 -0700 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-09-19 15:04:38 -0700 |
commit | 3b120ff12891968d02296abb60adb9137d335ae2 (patch) | |
tree | d6ffd5abe0c5b53543185d2b40ecc5966c304d1a /src/reflect | |
parent | dbe69dc0db04e32f8c9b254470ca1fc9c9a8f516 (diff) | |
parent | d3095cbeb29ae53d6796103b33a37560e9ba2cce (diff) | |
download | scala-3b120ff12891968d02296abb60adb9137d335ae2.tar.gz scala-3b120ff12891968d02296abb60adb9137d335ae2.tar.bz2 scala-3b120ff12891968d02296abb60adb9137d335ae2.zip |
Merge pull request #1354 from scalamacros/ticket/6363
merges scala.reflect.base into scala.reflect.api
Diffstat (limited to 'src/reflect')
37 files changed, 3462 insertions, 244 deletions
diff --git a/src/reflect/scala/reflect/api/Annotations.scala b/src/reflect/scala/reflect/api/Annotations.scala index 43e95f9902..37882a9f3c 100644 --- a/src/reflect/scala/reflect/api/Annotations.scala +++ b/src/reflect/scala/reflect/api/Annotations.scala @@ -3,26 +3,121 @@ package api import scala.collection.immutable.ListMap -trait Annotations extends base.Annotations { self: Universe => +/** + * Defines the type hierarchy for annotations. + */ +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. + */ + 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. + */ + implicit val AnnotationTag: ClassTag[Annotation] + + /** The constructor/deconstructor for `Annotation` instances. */ + val Annotation: AnnotationExtractor + + /** An extractor class to create and pattern match with syntax `Annotation(atp, scalaArgs, javaArgs)`. + * Here, `atp` is the annotation type, `scalaArgs` the arguments, and `javaArgs` the annotation's key-value + * pairs. + * + * Annotations are pickled, i.e. written to scala symtab attribute in the classfile. + * Annotations are written to the classfile as Java annotations if `atp` conforms to `ClassfileAnnotation`. + * + * For Scala annotations, arguments are stored in `scalaArgs` and `javaArgs` is empty. Arguments in + * `scalaArgs` are represented as typed trees. Note that these trees are not transformed by any phases + * following the type-checker. For Java annotations, `scalaArgs` is empty and arguments are stored in + * `javaArgs`. + */ + 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])] + } - override type Annotation >: Null <: AnyRef with AnnotationApi trait AnnotationApi { def tpe: Type def scalaArgs: List[Tree] def javaArgs: ListMap[Name, JavaArgument] } - override type LiteralArgument >: Null <: JavaArgument with LiteralArgumentApi + /** A Java annotation argument */ + type JavaArgument >: Null <: AnyRef + implicit val JavaArgumentTag: ClassTag[JavaArgument] + + /** A literal argument to a Java annotation as `"Use X instead"` in `@Deprecated("Use X instead")`*/ + 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. + */ + implicit val LiteralArgumentTag: ClassTag[LiteralArgument] + + /** The constructor/deconstructor for `LiteralArgument` instances. */ + val LiteralArgument: LiteralArgumentExtractor + + /** An extractor class to create and pattern match with syntax `LiteralArgument(value)` + * where `value` is the constant argument. + */ + abstract class LiteralArgumentExtractor { + def apply(value: Constant): LiteralArgument + def unapply(arg: LiteralArgument): Option[Constant] + } + trait LiteralArgumentApi { def value: Constant } - override type ArrayArgument >: Null <: JavaArgument with ArrayArgumentApi + /** An array argument to a Java annotation as in `@Target(value={TYPE,FIELD,METHOD,PARAMETER})` + */ + 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. + */ + implicit val ArrayArgumentTag: ClassTag[ArrayArgument] + + /** The constructor/deconstructor for `ArrayArgument` instances. */ + val ArrayArgument: ArrayArgumentExtractor + + /** An extractor class to create and pattern match with syntax `ArrayArgument(args)` + * where `args` is the argument array. + */ + abstract class ArrayArgumentExtractor { + def apply(args: Array[JavaArgument]): ArrayArgument + def unapply(arg: ArrayArgument): Option[Array[JavaArgument]] + } + trait ArrayArgumentApi { def args: Array[JavaArgument] } - override type NestedArgument >: Null <: JavaArgument with NestedArgumentApi + /** A nested annotation argument to a Java annotation as `@Nested` in `@Outer(@Nested)`. + */ + 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. + */ + implicit val NestedArgumentTag: ClassTag[NestedArgument] + + /** The constructor/deconstructor for `NestedArgument` instances. */ + val NestedArgument: NestedArgumentExtractor + + /** An extractor class to create and pattern match with syntax `NestedArgument(annotation)` + * where `annotation` is the nested annotation. + */ + abstract class NestedArgumentExtractor { + def apply(annotation: Annotation): NestedArgument + def unapply(arg: NestedArgument): Option[Annotation] + } + trait NestedArgumentApi { def annotation: Annotation } diff --git a/src/reflect/scala/reflect/api/Attachments.scala b/src/reflect/scala/reflect/api/Attachments.scala new file mode 100644 index 0000000000..edbb0131ca --- /dev/null +++ b/src/reflect/scala/reflect/api/Attachments.scala @@ -0,0 +1,50 @@ +package scala.reflect +package api + +/** Attachments is a generalization of Position. Typically it stores a Position of a tree, but this can be extended to + * encompass arbitrary payloads. Payloads are stored in type-indexed slots, which can be read with `get[T]` and written + * with `update[T]` and `remove[T]`. + * + * Attachments always carry positions because we don't want to introduce an additional field for attachments in `Tree` + * imposing an unnecessary memory tax because of something that will not be used in most cases. + */ +abstract class Attachments { self => + + /** The position type of this attachment */ + type Pos >: Null + + /** The underlying position */ + def pos: Pos + + /** Creates a copy of this attachment with the position replaced by `newPos` */ + def withPos(newPos: Pos): Attachments { type Pos = self.Pos } + + /** The underlying payload with the guarantee that no two elements have the same type. */ + def all: Set[Any] = Set.empty + + private def matchesTag[T: ClassTag](datum: Any) = + classTag[T].runtimeClass == datum.getClass + + /** An underlying payload of the given class type `T`. */ + def get[T: ClassTag]: Option[T] = + (all filter matchesTag[T]).headOption.asInstanceOf[Option[T]] + + /** Creates a copy of this attachment with the payload slot of T added/updated with the provided value. + * + * Replaces an existing payload of the same type, if exists. + */ + def update[T: ClassTag](attachment: T): Attachments { type Pos = self.Pos } = + new NonemptyAttachments(this.pos, remove[T].all + attachment) + + /** Creates a copy of this attachment with the payload of the given class type `T` removed. */ + def remove[T: ClassTag]: Attachments { type Pos = self.Pos } = { + val newAll = all filterNot matchesTag[T] + if (newAll.isEmpty) pos.asInstanceOf[Attachments { type Pos = self.Pos }] + else new NonemptyAttachments(this.pos, newAll) + } + + private class NonemptyAttachments(override val pos: Pos, override val all: Set[Any]) extends Attachments { + type Pos = self.Pos + def withPos(newPos: Pos) = new NonemptyAttachments(newPos, all) + } +} diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala new file mode 100644 index 0000000000..2bb0cc3c76 --- /dev/null +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -0,0 +1,75 @@ +package scala.reflect +package api + +/** + * This is an internal implementation class. + */ +trait BuildUtils { self: Universe => + + 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 + + abstract class BuildApi { + /** Selects type symbol with given simple name `name` from the defined members of `owner`. + */ + def selectType(owner: Symbol, name: String): TypeSymbol + + /** Selects term symbol with given name and type from the defined members of prefix type + */ + def selectTerm(owner: Symbol, name: String): TermSymbol + + /** Selects overloaded method symbol with given name and index + */ + def selectOverloadedMethod(owner: Symbol, name: String, index: Int): MethodSymbol + + /** A fresh symbol with given name `name`, position `pos` and flags `flags` that has + * the current symbol as its owner. + */ + def newNestedSymbol(owner: Symbol, name: Name, pos: Position, flags: FlagSet, isClass: Boolean): Symbol + + /** Create a fresh free term symbol. + * @param name the name of the free variable + * @param value the value of the free variable at runtime + * @param flags (optional) flags of the free variable + * @param origin debug information that tells where this symbol comes from + */ + def newFreeTerm(name: String, value: => Any, flags: FlagSet = NoFlags, origin: String = null): FreeTermSymbol + + /** Create a fresh free type symbol. + * @param name the name of the free variable + * @param flags (optional) flags of the free variable + * @param origin debug information that tells where this symbol comes from + */ + def newFreeType(name: String, flags: FlagSet = NoFlags, origin: String = null): FreeTypeSymbol + + /** Set symbol's type signature to given type. + * @return the symbol itself + */ + def setTypeSignature[S <: Symbol](sym: S, tpe: Type): S + + /** Set symbol's annotations to given annotations `annots`. + */ + def setAnnotations[S <: Symbol](sym: S, annots: List[Annotation]): S + + def flagsFromBits(bits: Long): FlagSet + + def emptyValDef: ValDef + + def This(sym: Symbol): Tree + + def Select(qualifier: Tree, sym: Symbol): Select + + def Ident(sym: Symbol): Ident + + def TypeTree(tp: Type): TypeTree + + def thisPrefix(sym: Symbol): Type + + def setType[T <: Tree](tree: T, tpe: Type): T + + def setSymbol[T <: Tree](tree: T, sym: Symbol): T + } +} diff --git a/src/reflect/scala/reflect/api/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala index 6657245003..f2d8ef2eb9 100644 --- a/src/reflect/scala/reflect/api/Constants.scala +++ b/src/reflect/scala/reflect/api/Constants.scala @@ -6,10 +6,33 @@ package scala.reflect package api -trait Constants extends base.Constants { +/** + * Defines the type hierachy for compile-time constants. + * + * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here. + */ +trait Constants { self: Universe => - override type Constant >: Null <: AnyRef with ConstantApi + /** The type of compile-time 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. + */ + implicit val ConstantTag: ClassTag[Constant] + + /** The constructor/deconstructor for `Constant` instances. */ + val Constant: ConstantExtractor + + /** An extractor class to create and pattern match with syntax `Constant(value)` + * where `value` is the Scala value of the constant. + */ + abstract class ConstantExtractor { + def apply(value: Any): Constant + def unapply(arg: Constant): Option[Any] + } abstract class ConstantApi { val value: Any diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala new file mode 100644 index 0000000000..65b0eb9301 --- /dev/null +++ b/src/reflect/scala/reflect/api/Exprs.scala @@ -0,0 +1,139 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2012 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package api + +import scala.reflect.runtime.{universe => ru} + +trait Exprs { self: Universe => + + /** Expr wraps an expression tree and tags it with its type. */ + trait Expr[+T] extends Equals with Serializable { + val mirror: Mirror + /** + * 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: MirrorOf[U]): U # Expr[T] + + /** + * The Scala syntax tree representing the wrapped expression. + */ + def tree: Tree + + /** + * Representation of the type of the wrapped expression tree as found via type tags. + */ + def staticType: Type + /** + * Representation of the type of the wrapped expression tree as found in the tree. + */ + def actualType: Type + + /** + * A dummy method to mark expression splicing in reification. + * + * It should only be used within a `reify` call, which eliminates the `splice` call and embeds + * the wrapped tree into the reified surrounding expression. + * If used alone `splice` throws an exception when called at runtime. + * + * If you want to use an Expr in reification of some Scala code, you need to splice it in. + * For an expr of type `Expr[T]`, where `T` has a method `foo`, the following code + * {{{ + * reify{ expr.splice.foo } + * }}} + * uses splice to turn an expr of type Expr[T] into a value of type T in the context of `reify`. + * + * It is equivalent to + * {{{ + * Select( expr.tree, newTermName("foo") ) + * }}} + * + * The following example code however does not compile + * {{{ + * reify{ expr.foo } + * }}} + * 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. + * + * For example for the following macro definition: + * {{{ + * class X { type T } + * object Macros { def foo(x: X): x.T = macro Impls.foo_impl } + * }}} + * + * The corresponding macro implementation should have the following signature (note how the return type denotes path-dependency on x): + * {{{ + * object Impls { def foo_impl(c: Context)(x: c.Expr[X]): c.Expr[x.value.T] = ... } + * }}} + */ + val value: T + + /** case class accessories */ + override def canEqual(x: Any) = x.isInstanceOf[Expr[_]] + override def equals(x: Any) = x.isInstanceOf[Expr[_]] && this.mirror == x.asInstanceOf[Expr[_]].mirror && this.tree == x.asInstanceOf[Expr[_]].tree + override def hashCode = mirror.hashCode * 31 + tree.hashCode + override def toString = "Expr["+staticType+"]("+tree+")" + } + + /** + * Constructor/Extractor for Expr. + * + * 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. + */ + object Expr { + def apply[T: WeakTypeTag](mirror: MirrorOf[self.type], treec: TreeCreator): Expr[T] = new ExprImpl[T](mirror.asInstanceOf[Mirror], treec) + def unapply[T](expr: Expr[T]): Option[Tree] = Some(expr.tree) + } + + private class ExprImpl[+T: WeakTypeTag](val mirror: Mirror, val treec: TreeCreator) extends Expr[T] { + def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # Expr[T] = { + val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]] + val tag1 = (implicitly[WeakTypeTag[T]] in otherMirror).asInstanceOf[otherMirror.universe.WeakTypeTag[T]] + otherMirror.universe.Expr[T](otherMirror1, treec)(tag1) + } + + lazy val tree: Tree = treec(mirror) + lazy val staticType: Type = implicitly[WeakTypeTag[T]].tpe + def actualType: Type = tree.tpe + + def splice: T = throw new UnsupportedOperationException(""" + |the function you're calling has not been spliced by the compiler. + |this means there is a cross-stage evaluation involved, and it needs to be invoked explicitly. + |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) + lazy val value: T = throw new UnsupportedOperationException(""" + |the value you're calling is only meant to be used in cross-stage path-dependent types. + |if you want to splice the underlying expression, use `<your expr>.splice`. + |if you want to get a value of the underlying expression, add scala-compiler.jar to the classpath, + |import `scala.tools.reflect.Eval` and call `<your expr>.eval` instead.""".trim.stripMargin) + + private def writeReplace(): AnyRef = new SerializedExpr(treec, implicitly[WeakTypeTag[T]].in(ru.rootMirror)) + } +} + +private[scala] class SerializedExpr(var treec: TreeCreator, var tag: ru.WeakTypeTag[_]) extends Serializable { + private def writeObject(out: java.io.ObjectOutputStream): Unit = { + out.writeObject(treec) + out.writeObject(tag) + } + + private def readObject(in: java.io.ObjectInputStream): Unit = { + treec = in.readObject().asInstanceOf[TreeCreator] + tag = in.readObject().asInstanceOf[ru.WeakTypeTag[_]] + } + + private def readResolve(): AnyRef = { + import ru._ + Expr(rootMirror, treec)(tag) + } +}
\ No newline at end of file diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala index fdd43f1883..599c4ca426 100644 --- a/src/reflect/scala/reflect/api/FlagSets.scala +++ b/src/reflect/scala/reflect/api/FlagSets.scala @@ -3,10 +3,16 @@ package api import scala.language.implicitConversions -trait FlagSets extends base.FlagSets { self: Universe => +trait FlagSets { self: Universe => + /** An abstract type representing sets of flags (like private, final, etc.) that apply to definition trees and symbols */ 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. + */ + implicit val FlagSetTag: ClassTag[FlagSet] + trait FlagOps extends Any { def | (right: FlagSet): FlagSet } @@ -99,4 +105,7 @@ trait FlagSets extends base.FlagSets { self: Universe => /** Flag indicating that tree represents a variable or a member initialized to the default value */ val DEFAULTINIT: FlagSet } + + /** The empty set of flags */ + val NoFlags: FlagSet } diff --git a/src/reflect/scala/reflect/api/JavaUniverse.scala b/src/reflect/scala/reflect/api/JavaUniverse.scala index f2388433c4..ba38381561 100644 --- a/src/reflect/scala/reflect/api/JavaUniverse.scala +++ b/src/reflect/scala/reflect/api/JavaUniverse.scala @@ -1,7 +1,7 @@ package scala.reflect package api -trait JavaUniverse extends Universe with Mirrors with TagInterop { self => +trait JavaUniverse extends Universe with Mirrors { self => type RuntimeClass = java.lang.Class[_] @@ -13,5 +13,28 @@ trait JavaUniverse extends Universe with Mirrors with TagInterop { self => } def runtimeMirror(cl: ClassLoader): Mirror -} + 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] + val runtimeClass = mirror.runtimeClass(tag.in(mirror).tpe) + Manifest.classType(runtimeClass).asInstanceOf[Manifest[T]] + } + + 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: MirrorOf[U]): U # Type = { + mirror.universe match { + case ju: JavaUniverse => + val jm = mirror.asInstanceOf[ju.Mirror] + val sym = jm.classSymbol(manifest.erasure) + val tpe = + if (manifest.typeArguments.isEmpty) sym.toType + else ju.appliedType(sym.toTypeConstructor, manifest.typeArguments map (targ => ju.manifestToTypeTag(jm, targ)) map (_.in(jm).tpe)) + tpe.asInstanceOf[U # Type] + case u => + u.manifestToTypeTag(mirror.asInstanceOf[u.Mirror], manifest).in(mirror).tpe + } + } + }) +} diff --git a/src/reflect/scala/reflect/api/MirrorOf.scala b/src/reflect/scala/reflect/api/MirrorOf.scala new file mode 100644 index 0000000000..cd5641e692 --- /dev/null +++ b/src/reflect/scala/reflect/api/MirrorOf.scala @@ -0,0 +1,107 @@ +package scala.reflect +package api + +/** + * The base interface 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 MirrorOf and also need to be defined outside the cake as they are + * used by type tags, which can be migrated between different universes and consequently + * cannot be bound to a fixed one. + * + * @see [[Mirrors]] + */ +abstract class MirrorOf[U <: Universe with Singleton] { + /** The universe this mirror belongs to. */ + val universe: U + + /** The class symbol of the `_root_` package */ + def RootClass: U#ClassSymbol + + /** The module symbol of the `_root_` package */ + def RootPackage: U#ModuleSymbol + + /** The module class symbol of the default (unnamed) package */ + def EmptyPackageClass: U#ClassSymbol + + /** The module symbol of the default (unnamed) package */ + def EmptyPackage: U#ModuleSymbol + + /** The symbol corresponding to the globally accessible class with the + * given fully qualified name `fullName`. + * + * If the name points to a type alias, it's recursively dealiased and its target is returned. + * If you need a symbol that corresponds to the type alias itself, load it directly from the package class: + * + * scala> cm.staticClass("scala.List") + * res0: reflect.runtime.universe.ClassSymbol = class List + * + * scala> res0.fullName + * res1: String = scala.collection.immutable.List + * + * scala> cm.staticPackage("scala") + * res2: reflect.runtime.universe.ModuleSymbol = package scala + * + * scala> res2.moduleClass.typeSignature member newTypeName("List") + * res3: reflect.runtime.universe.Symbol = type List + * + * scala> res3.fullName + * res4: String = scala.List + * + * To be consistent with Scala name resolution rules, in case of ambiguity between + * a package and an object, the object is never been considered. + * + * For example for the following code: + * + * package foo { + * class B + * } + * + * object foo { + * class A + * class B + * } + * + * staticClass("foo.B") will resolve to the symbol corresponding to the class B declared in the package foo, and + * staticClass("foo.A") will throw a MissingRequirementException (which is exactly what scalac would do if this + * fully qualified class name is written inside any package in a Scala program). + * + * 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. + */ + def staticClass(fullName: String): U#ClassSymbol + + /** The symbol corresponding to the globally accessible object with the + * given fully qualified name `fullName`. + * + * To be consistent with Scala name resolution rules, in case of ambiguity between + * a package and an object, the object is never been considered. + * + * For example for the following code: + * + * package foo { + * object B + * } + * + * object foo { + * object A + * object B + * } + * + * staticModule("foo.B") will resolve to the symbol corresponding to the object B declared in the package foo, and + * staticModule("foo.A") will throw a MissingRequirementException (which is exactly what scalac would do if this + * fully qualified class name is written inside any package in a Scala program). + * + * 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. + */ + def staticModule(fullName: String): U#ModuleSymbol + + /** The symbol corresponding to a package with the + * given fully qualified name `fullName`. + */ + 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 8c4c423221..c935533027 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -1,7 +1,23 @@ package scala.reflect package api -trait Mirrors extends base.Mirrors { self: Universe => +/** + * Defines a type hierarchy for mirrors. + * + * Every universe has one or more mirrors. A mirror defines a hierarchy of symbols starting with the root package `_root_` + * and provides methods to locate and define classes and singleton objects in that hierarchy. + * + * On the JVM, there is a one to one correspondance between class loaders and mirrors. + */ +trait Mirrors { self: Universe => + + /** The base type of all mirrors of this universe */ + type Mirror >: Null <: MirrorOf[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. + */ + val rootMirror: Mirror type RuntimeClass >: Null diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index d6868c26ab..e8665ca736 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -2,23 +2,52 @@ package scala.reflect package api /** A trait that manages names. - * A name is a string in one of two name universes: terms and types. - * The same string can be a name in both universes. - * Two names are equal if they represent the same string and they are - * members of the same universe. * - * Names are interned. That is, for two names `name11 and `name2`, - * `name1 == name2` implies `name1 eq name2`. + * @see TermName + * @see TypeName */ -trait Names extends base.Names { +trait Names { + // Intentionally no implicit from String => Name. + implicit def stringToTermName(s: String): TermName = newTermName(s) + implicit def stringToTypeName(s: String): TypeName = newTypeName(s) - /** The abstract type of names */ + /** + * 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. + */ type Name >: Null <: NameApi + implicit val NameTag: ClassTag[Name] + + /** The abstract type of names representing terms */ + type TypeName >: Null <: Name + implicit val TypeNameTag: ClassTag[TypeName] - /** The extended API of names that's supported on reflect mirror via an + /** The abstract type of names representing types */ + type TermName >: Null <: Name + implicit val TermNameTag: ClassTag[TermName] + + /** The API of names that's supported on reflect mirror via an * implicit conversion in reflect.ops */ - abstract class NameApi extends NameBase { + abstract class NameApi { + /** Checks wether the name is a a term name */ + def isTermName: Boolean + + /** Checks wether the name is a a type name */ + def isTypeName: Boolean + + /** Returns a term name that wraps the same string as `this` */ + def toTermName: TermName + + /** Returns a type name that wraps the same string as `this` */ + def toTypeName: TypeName /** Replaces all occurrences of \$op_names in this name by corresponding operator symbols. * Example: `foo_\$plus\$eq` becomes `foo_+=` @@ -38,4 +67,20 @@ trait Names extends base.Names { */ def encodedName: Name } + + /** Create a new term name. + */ + def newTermName(s: String): TermName + + /** Creates a new type name. + */ + def newTypeName(s: String): TypeName + + /** Wraps the empty string. Can be used as the null object for term name. + */ + def EmptyTermName: TermName = newTermName("") + + /** Wraps the empty string. Can be used as the null object for type name. + */ + def EmptyTypeName: TypeName = EmptyTermName.toTypeName } diff --git a/src/reflect/scala/reflect/api/Positions.scala b/src/reflect/scala/reflect/api/Positions.scala index 5e8d958f02..0eddc88fc4 100644 --- a/src/reflect/scala/reflect/api/Positions.scala +++ b/src/reflect/scala/reflect/api/Positions.scala @@ -1,12 +1,25 @@ package scala.reflect package api -trait Positions extends base.Positions { +/** + * Defines the type hierachy for positions. + * + * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here. + */ +trait Positions { self: Universe => /** .. */ type Position >: Null <: PositionApi { 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. + */ + implicit val PositionTag: ClassTag[Position] + + /** A special "missing" position. */ + val NoPosition: Position + /** Assigns a given position to all position-less nodes of a given AST. */ def atPos[T <: Tree](pos: Position)(tree: T): T diff --git a/src/reflect/scala/reflect/api/Scopes.scala b/src/reflect/scala/reflect/api/Scopes.scala new file mode 100644 index 0000000000..d30da07ad5 --- /dev/null +++ b/src/reflect/scala/reflect/api/Scopes.scala @@ -0,0 +1,50 @@ +package scala.reflect +package api + +/** + * Defines the type hierachy for scopes. + * + * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here. + */ +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. + */ + type Scope >: Null <: ScopeApi + + /** The API that all scopes support */ + 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. + */ + implicit val ScopeTag: ClassTag[Scope] + + /** The type of member scopes, as in class definitions, for example. */ + type MemberScope >: Null <: Scope with MemberScopeApi + + /** The API that all member scopes support */ + 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. + * 3) Synthetic members (e.g. getters/setters for vals/vars) might appear in arbitrary order. + */ + def sorted: List[Symbol] + } + + /** A tag that preserves the identity of the `MemberScope` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + */ + implicit val MemberScopeTag: ClassTag[MemberScope] + + /** Create a new scope. */ + def newScope: Scope + + /** Create a new scope nested in another one with which it shares its elements. */ + def newNestedScope(outer: Scope): Scope + + /** Create a new scope with the given initial elements. */ + def newScopeWith(elems: Symbol*): Scope +}
\ No newline at end of file diff --git a/src/reflect/scala/reflect/api/StandardDefinitions.scala b/src/reflect/scala/reflect/api/StandardDefinitions.scala index c6f02f1a33..03f2a6b0aa 100644 --- a/src/reflect/scala/reflect/api/StandardDefinitions.scala +++ b/src/reflect/scala/reflect/api/StandardDefinitions.scala @@ -5,12 +5,59 @@ package scala.reflect package api -trait StandardDefinitions extends base.StandardDefinitions { +/** + * Defines standard symbols and types. + */ +trait StandardDefinitions { self: Universe => + /** A value containing all standard defnitions. */ val definitions: DefinitionsApi - trait DefinitionsApi extends DefinitionsBase { + /** Defines standard symbols (and types via its base trait). */ + trait DefinitionsApi extends StandardTypes { + /** The class symbol of package `scala`. */ + def ScalaPackageClass: ClassSymbol + + /** The module class symbol of package `scala`. */ + def ScalaPackage: ModuleSymbol + + // top types + def AnyClass : ClassSymbol + def AnyValClass: ClassSymbol + def ObjectClass: ClassSymbol + def AnyRefClass: TypeSymbol + + // bottom types + def NullClass : ClassSymbol + def NothingClass: ClassSymbol + + // the scala value classes + def UnitClass : ClassSymbol + def ByteClass : ClassSymbol + def ShortClass : ClassSymbol + def CharClass : ClassSymbol + def IntClass : ClassSymbol + def LongClass : ClassSymbol + def FloatClass : ClassSymbol + def DoubleClass : ClassSymbol + def BooleanClass: ClassSymbol + + /** The class symbol of class `String`. */ + def StringClass : ClassSymbol + + /** The class symbol of class `Class`. */ + def ClassClass : ClassSymbol + + /** The class symbol of class `Array`. */ + def ArrayClass : ClassSymbol + + /** The class symbol of class `List`. */ + def ListClass : ClassSymbol + + /** The module symbol of `scala.Predef`. */ + def PredefModule: ModuleSymbol + def JavaLangPackageClass: ClassSymbol def JavaLangPackage: ModuleSymbol def ArrayModule: ModuleSymbol @@ -45,4 +92,52 @@ trait StandardDefinitions extends base.StandardDefinitions { def ScalaPrimitiveValueClasses: List[ClassSymbol] def ScalaNumericValueClasses: List[ClassSymbol] } + + /** Defines standard types. */ + trait StandardTypes { + /** The `Type` of type `Unit`. */ + val UnitTpe: Type + + /** The `Type` of primitive type `Byte`. */ + val ByteTpe: Type + + /** The `Type` of primitive type `Short`. */ + val ShortTpe: Type + + /** The `Type` of primitive type `Char`. */ + val CharTpe: Type + + /** The `Type` of primitive type `Int`. */ + val IntTpe: Type + + /** The `Type` of primitive type `Long`. */ + val LongTpe: Type + + /** The `Type` of primitive type `Float`. */ + val FloatTpe: Type + + /** The `Type` of primitive type `Double`. */ + val DoubleTpe: Type + + /** The `Type` of primitive type `Boolean`. */ + val BooleanTpe: Type + + /** The `Type` of type `Any`. */ + val AnyTpe: Type + + /** The `Type` of type `AnyVal`. */ + val AnyValTpe: Type + + /** The `Type` of type `AnyRef`. */ + val AnyRefTpe: Type + + /** The `Type` of type `Object`. */ + val ObjectTpe: Type + + /** The `Type` of type `Nothing`. */ + val NothingTpe: Type + + /** The `Type` of type `Null`. */ + val NullTpe: Type + } } diff --git a/src/reflect/scala/reflect/api/StandardNames.scala b/src/reflect/scala/reflect/api/StandardNames.scala index 65d87ad7f0..354a9f9328 100644 --- a/src/reflect/scala/reflect/api/StandardNames.scala +++ b/src/reflect/scala/reflect/api/StandardNames.scala @@ -5,26 +5,40 @@ package scala.reflect package api -// Q: I have a pretty name. Where do I put it - into base.StandardNames or into api.StandardNames? -// A: <see base.StandardNames> +// Q: I have a pretty name. Can I put it here? +// A: Is it necessary to construct trees (like EMPTY or WILDCARD_STAR)? If yes, then sure. +// 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. -trait StandardNames extends base.StandardNames { +// TODO: document better +/** + * Names necessary to create Scala trees. + */ +trait StandardNames { self: Universe => val nme: TermNamesApi val tpnme: TypeNamesApi - trait NamesApi extends NamesBase { + trait NamesApi { + type NameType >: Null <: Name + val WILDCARD: NameType val ROOT: NameType val EMPTY: NameType val ERROR: NameType val PACKAGE: NameType } - trait TermNamesApi extends NamesApi with TermNamesBase { + trait TermNamesApi extends NamesApi { + type NameType = TermName + val CONSTRUCTOR: NameType + val ROOTPKG: NameType val LOCAL_SUFFIX_STRING: String } - trait TypeNamesApi extends NamesApi with TypeNamesBase { + trait TypeNamesApi extends NamesApi { + type NameType = TypeName + val EMPTY: NameType + val WILDCARD_STAR: NameType } } diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index 0c4be4f7e1..542673ff00 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -1,19 +1,211 @@ package scala.reflect package api -trait Symbols extends base.Symbols { self: Universe => - - override type Symbol >: Null <: SymbolApi - override type TypeSymbol >: Null <: Symbol with TypeSymbolApi - override type TermSymbol >: Null <: Symbol with TermSymbolApi - override type MethodSymbol >: Null <: TermSymbol with MethodSymbolApi - override type ModuleSymbol >: Null <: TermSymbol with ModuleSymbolApi - override type ClassSymbol >: Null <: TypeSymbol with ClassSymbolApi - override type FreeTermSymbol >: Null <: TermSymbol with FreeTermSymbolApi - override type FreeTypeSymbol >: Null <: TypeSymbol with FreeTypeSymbolApi +/** + * Defines the type hierachy for symbols + * + * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here. + */ +trait Symbols { self: Universe => + + /** The type of symbols representing declarations */ + 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. + */ + implicit val SymbolTag: ClassTag[Symbol] + + /** The type of type symbols representing type, class, and trait declarations, + * as well as type parameters + */ + 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. + */ + implicit val TypeSymbolTag: ClassTag[TypeSymbol] + + /** The type of term symbols representing val, var, def, and object declarations as + * well as packages and value parameters. + */ + 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. + */ + implicit val TermSymbolTag: ClassTag[TermSymbol] + + /** The type of method symbols representing def declarations */ + 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. + */ + implicit val MethodSymbolTag: ClassTag[MethodSymbol] + + /** The type of module symbols representing object declarations */ + 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. + */ + implicit val ModuleSymbolTag: ClassTag[ModuleSymbol] + + /** The type of class symbols representing class and trait definitions */ + 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. + */ + implicit val ClassSymbolTag: ClassTag[ClassSymbol] + + /** The type of free terms introduced by reification */ + 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. + */ + implicit val FreeTermSymbolTag: ClassTag[FreeTermSymbol] + + /** The type of free types introduced by reification */ + 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. + */ + implicit val FreeTypeSymbolTag: ClassTag[FreeTypeSymbol] + + /** A special "missing" symbol */ + val NoSymbol: Symbol /** The API of symbols */ - trait SymbolApi extends SymbolBase { this: Symbol => + trait SymbolApi { this: Symbol => + + /** The owner of this symbol. This is the symbol + * that directly contains the current symbol's definition. + * The `NoSymbol` symbol does not have an owner, and calling this method + * on one causes an internal error. + * The owner of the Scala root class [[scala.reflect.api.MirrorOf.RootClass]] + * and the Scala root object [[scala.reflect.api.MirrorOf.RootPackage]] is `NoSymbol`. + * Every other symbol has a chain of owners that ends in + * [[scala.reflect.api.MirrorOf.RootClass]]. + */ + def owner: Symbol + + /** The type of the symbol name. + * Can be either `TermName` or `TypeName` depending on whether this is a `TermSymbol` or a `TypeSymbol`. + * + * Type name namespaces do not intersect with term name namespaces. + * This fact is reflected in different types for names of `TermSymbol` and `TypeSymbol`. + */ + type NameType >: Null <: Name + + /** The name of the symbol as a member of the `Name` type. + */ + def name: Name + + /** The encoded full path name of this symbol, where outer names and inner names + * are separated by periods. + */ + def fullName: String + + /** Does this symbol represent the definition of a type? + * 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. + */ + def isType: Boolean = false + + /** This symbol cast to a TypeSymbol. + * @throws ScalaReflectionException if `isType` is false. + */ + def asType: TypeSymbol = throw new ScalaReflectionException(s"$this is not a type") + + /** Does this symbol represent the definition of a term? + * 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. + */ + def isTerm: Boolean = false + + /** This symbol cast to a TermSymbol. + * @throws ScalaReflectionException if `isTerm` is false. + */ + 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. + */ + def isMethod: Boolean = false + + /** This symbol cast to a MethodSymbol. + * @throws ScalaReflectionException if `isMethod` is false. + */ + def asMethod: MethodSymbol = { + def overloadedMsg = + "encapsulates multiple overloaded alternatives and cannot be treated as a method. "+ + "Consider invoking `<offending symbol>.asTerm.alternatives` and manually picking the required method" + def vanillaMsg = "is not a method" + val msg = if (isOverloadedMethod) overloadedMsg else vanillaMsg + throw new ScalaReflectionException(s"$this $msg") + } + + /** Used to provide a better error message for `asMethod` */ + 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. + */ + def isModule: Boolean = false + + /** This symbol cast to a ModuleSymbol defined by an object definition. + * @throws ScalaReflectionException if `isModule` is false. + */ + 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. + */ + 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. + */ + def isModuleClass: Boolean = false + + /** This symbol cast to a ClassSymbol representing a class or trait. + * @throws ScalaReflectionException if `isClass` is false. + */ + 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. + */ + def isFreeTerm: Boolean = false + + /** This symbol cast to a free term symbol. + * @throws ScalaReflectionException if `isFreeTerm` is false. + */ + 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. + */ + def isFreeType: Boolean = false + + /** This symbol cast to a free type symbol. + * @throws ScalaReflectionException if `isFreeType` is false. + */ + def asFreeType: FreeTypeSymbol = throw new ScalaReflectionException(s"$this is not a free type") + + def newTermSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TermSymbol + def newModuleAndClassSymbol(name: Name, pos: Position = NoPosition, flags: FlagSet = NoFlags): (ModuleSymbol, ClassSymbol) + def newMethodSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): MethodSymbol + def newTypeSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TypeSymbol + 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. @@ -195,7 +387,14 @@ trait Symbols extends base.Symbols { self: Universe => } /** The API of term symbols */ - trait TermSymbolApi extends SymbolApi with TermSymbolBase { this: TermSymbol => + trait TermSymbolApi extends SymbolApi { this: TermSymbol => + /** Term symbols have their names of type `TermName`. + */ + final type NameType = TermName + + final override def isTerm = true + final override def asTerm = this + /** Is this symbol introduced as `val`? */ def isVal: Boolean @@ -269,7 +468,41 @@ trait Symbols extends base.Symbols { self: Universe => } /** The API of type symbols */ - trait TypeSymbolApi extends SymbolApi with TypeSymbolBase { this: TypeSymbol => + trait TypeSymbolApi extends SymbolApi { this: TypeSymbol => + /** Type symbols have their names of type `TypeName`. + */ + final type NameType = TypeName + + /** The type constructor corresponding to this type symbol. + * This is different from `toType` in that type parameters + * are part of results of `toType`, but not of `toTypeConstructor`. + * + * 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`. + */ + def toTypeConstructor: Type + + /** A type reference that refers to this type symbol seen + * as a member of given type `site`. + */ + def toTypeIn(site: Type): Type + + /** A type reference that refers to this type symbol + * Note if symbol is a member of a class, one almost always is interested + * in `asTypeIn` with a site type instead. + * + * Example: Given a class declaration `class C[T] { ... } `, that generates a symbol + * `C`. Then `C.toType` is the type `C[T]`. + * + * 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`. + */ + def toType: Type + + final override def isType = true + final override def asType = this + /** Is the type parameter represented by this symbol contravariant? */ def isContravariant : Boolean @@ -300,7 +533,10 @@ trait Symbols extends base.Symbols { self: Universe => } /** The API of method symbols */ - trait MethodSymbolApi extends TermSymbolApi with MethodSymbolBase { this: MethodSymbol => + trait MethodSymbolApi extends TermSymbolApi { this: MethodSymbol => + final override def isMethod = true + final override def asMethod = this + /** Does this method represent a constructor? * * If `owner` is a class, then this is a vanilla JVM constructor. @@ -331,11 +567,23 @@ trait Symbols extends base.Symbols { self: Universe => } /** The API of module symbols */ - trait ModuleSymbolApi extends TermSymbolApi with ModuleSymbolBase { this: ModuleSymbol => + 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`. + */ + def moduleClass: Symbol // needed for tree traversals + // when this becomes `moduleClass: ClassSymbol`, it will be the happiest day in my life + + final override def isModule = true + final override def asModule = this } /** The API of class symbols */ - trait ClassSymbolApi extends TypeSymbolApi with ClassSymbolBase { this: ClassSymbol => + trait ClassSymbolApi extends TypeSymbolApi { this: ClassSymbol => + final override def isClass = true + final override def asClass = this + /** 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]]? @@ -398,7 +646,10 @@ trait Symbols extends base.Symbols { self: Universe => } /** The API of free term symbols */ - trait FreeTermSymbolApi extends TermSymbolApi with FreeTermSymbolBase { this: FreeTermSymbol => + trait FreeTermSymbolApi extends TermSymbolApi { this: FreeTermSymbol => + final override def isFreeTerm = true + final override def asFreeTerm = this + /** The place where this symbol has been spawned */ def origin: String @@ -407,7 +658,10 @@ trait Symbols extends base.Symbols { self: Universe => } /** The API of free term symbols */ - trait FreeTypeSymbolApi extends TypeSymbolApi with FreeTypeSymbolBase { this: FreeTypeSymbol => + trait FreeTypeSymbolApi extends TypeSymbolApi { this: FreeTypeSymbol => + final override def isFreeType = true + final override def asFreeType = this + /** The place where this symbol has been spawned */ def origin: String } diff --git a/src/reflect/scala/reflect/api/TagInterop.scala b/src/reflect/scala/reflect/api/TagInterop.scala index 5ab085741e..fc0558d717 100644 --- a/src/reflect/scala/reflect/api/TagInterop.scala +++ b/src/reflect/scala/reflect/api/TagInterop.scala @@ -1,32 +1,27 @@ package scala.reflect package api -import scala.reflect.base.TypeCreator -import scala.reflect.base.{Universe => BaseUniverse} +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 -trait TagInterop { self: JavaUniverse => + /** + * Convert a typetag to a pre `Scala-2.10` manifest. + * For example + * {{{ + * typeTagToManifest( scala.reflect.runtime.currentMirror, implicitly[TypeTag[String]] ) + * }}} + */ + def typeTagToManifest[T: ClassTag](mirror: Any, tag: Universe#TypeTag[T]): Manifest[T] = + throw new UnsupportedOperationException("This universe does not support tag -> manifest conversions. Use a JavaUniverse, e.g. the scala.reflect.runtime.universe.") - override def typeTagToManifest[T: ClassTag](mirror0: Any, tag: base.Universe # TypeTag[T]): Manifest[T] = { - // SI-6239: make this conversion more precise - val mirror = mirror0.asInstanceOf[Mirror] - val runtimeClass = mirror.runtimeClass(tag.in(mirror).tpe) - Manifest.classType(runtimeClass).asInstanceOf[Manifest[T]] - } - - override def manifestToTypeTag[T](mirror0: Any, manifest: Manifest[T]): base.Universe # TypeTag[T] = - TypeTag(mirror0.asInstanceOf[Mirror], new TypeCreator { - def apply[U <: BaseUniverse with Singleton](mirror: MirrorOf[U]): U # Type = { - mirror.universe match { - case ju: JavaUniverse => - val jm = mirror.asInstanceOf[ju.Mirror] - val sym = jm.classSymbol(manifest.erasure) - val tpe = - if (manifest.typeArguments.isEmpty) sym.toType - else ju.appliedType(sym.toTypeConstructor, manifest.typeArguments map (targ => ju.manifestToTypeTag(jm, targ)) map (_.in(jm).tpe)) - tpe.asInstanceOf[U # Type] - case u => - u.manifestToTypeTag(mirror.asInstanceOf[u.Mirror], manifest).in(mirror).tpe - } - } - }) + /** + * Convert a pre `Scala-2.10` manifest to a typetag. + * For example + * {{{ + * manifestToTypeTag( scala.reflect.runtime.currentMirror, implicitly[Manifest[String]] ) + * }}} + */ + 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 new file mode 100644 index 0000000000..0c8701775c --- /dev/null +++ b/src/reflect/scala/reflect/api/TreeCreator.scala @@ -0,0 +1,26 @@ +package scala.reflect +package api + +/** A mirror-aware factory for trees. + * + * 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. + */ +abstract class TreeCreator { + def apply[U <: Universe with Singleton](m: MirrorOf[U]): U # Tree +} diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index e46a977be8..1f15ee6070 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -6,12 +6,75 @@ package scala.reflect package api // Syncnote: Trees are currently not thread-safe. -trait Trees extends base.Trees { self: Universe => +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. + */ + type Tree >: Null <: TreeApi - override 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. + */ + implicit val TreeTag: ClassTag[Tree] - /** ... */ - trait TreeApi extends TreeBase { this: Tree => + /** The API that all trees support */ + trait TreeApi extends Product { this: Tree => + // TODO + /** ... */ + def isDef: Boolean + + // TODO + /** ... */ + def isEmpty: Boolean + + /** The canonical way to test if a Tree represents a term. + */ + def isTerm: Boolean + + /** The canonical way to test if a Tree represents a type. + */ + def isType: Boolean /** ... */ def pos: Position @@ -107,37 +170,83 @@ trait Trees extends base.Trees { self: Universe => * in this tree will be found when searching by position). */ def duplicate: this.type + + /** Obtains string representation of a tree */ + override def toString: String = treeToString(this) } - override protected def treeType(tree: Tree) = tree.tpe + /** Obtains string representation of a tree */ + protected def treeToString(tree: Tree): String - override type TermTree >: Null <: Tree with TermTreeApi + /** The empty tree */ + val EmptyTree: Tree + + /** A tree for a term. Not all trees representing terms are TermTrees; use isTerm + * to reliably identify terms. + */ + 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. + */ + implicit val TermTreeTag: ClassTag[TermTree] /** The API that all term trees support */ trait TermTreeApi extends TreeApi { this: TermTree => } - override type TypTree >: Null <: Tree with TypTreeApi + /** A tree for a type. Not all trees representing types are TypTrees; use isType + * to reliably identify types. + */ + 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. + */ + implicit val TypTreeTag: ClassTag[TypTree] /** The API that all typ trees support */ trait TypTreeApi extends TreeApi { this: TypTree => } - override type SymTree >: Null <: Tree with SymTreeApi + /** A tree with a mutable symbol field, initialized to NoSymbol. + */ + 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. + */ + implicit val SymTreeTag: ClassTag[SymTree] /** The API that all sym trees support */ trait SymTreeApi extends TreeApi { this: SymTree => def symbol: Symbol } - override type NameTree >: Null <: Tree with NameTreeApi + /** A tree with a name - effectively, a DefTree or RefTree. + */ + 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. + */ + implicit val NameTreeTag: ClassTag[NameTree] /** The API that all name trees support */ trait NameTreeApi extends TreeApi { this: NameTree => def name: Name } - override type RefTree >: Null <: SymTree with NameTree with RefTreeApi + /** A tree which references a symbol-carrying entity. + * References one, as opposed to defining one; definitions + * are in DefTrees. + */ + 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. + */ + implicit val RefTreeTag: ClassTag[RefTree] /** The API that all ref trees support */ trait RefTreeApi extends SymTreeApi with NameTreeApi { this: RefTree => @@ -145,21 +254,56 @@ trait Trees extends base.Trees { self: Universe => def name: Name } - override type DefTree >: Null <: SymTree with NameTree with DefTreeApi + /** A tree which defines a symbol-carrying entity. + */ + 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. + */ + implicit val DefTreeTag: ClassTag[DefTree] /** The API that all def trees support */ trait DefTreeApi extends SymTreeApi with NameTreeApi { this: DefTree => def name: Name } - override type MemberDef >: Null <: DefTree with MemberDefApi + /** Common base class for all member definitions: types, classes, + * objects, packages, vals and vars, defs. + */ + 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. + */ + implicit val MemberDefTag: ClassTag[MemberDef] /** The API that all member defs support */ trait MemberDefApi extends DefTreeApi { this: MemberDef => def mods: Modifiers } - override type PackageDef >: Null <: MemberDef with PackageDefApi + /** A packaging, such as `package pid { stats }` + */ + 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. + */ + implicit val PackageDefTag: ClassTag[PackageDef] + + /** The constructor/deconstructor for `PackageDef` instances. */ + 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 } + */ + 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 */ trait PackageDefApi extends MemberDefApi { this: PackageDef => @@ -167,14 +311,45 @@ trait Trees extends base.Trees { self: Universe => val stats: List[Tree] } - override type ImplDef >: Null <: MemberDef with ImplDefApi + /** A common base class for class and object definitions. + */ + 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. + */ + implicit val ImplDefTag: ClassTag[ImplDef] /** The API that all impl defs support */ trait ImplDefApi extends MemberDefApi { this: ImplDef => val impl: Template } - override type ClassDef >: Null <: ImplDef with ClassDefApi + /** A class definition. + */ + 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. + */ + implicit val ClassDefTag: ClassTag[ClassDef] + + /** The constructor/deconstructor for `ClassDef` instances. */ + val ClassDef: ClassDefExtractor + + /** An extractor class to create and pattern match with syntax `ClassDef(mods, name, tparams, impl)`. + * This AST node corresponds to the following Scala code: + * + * mods `class` name [tparams] impl + * + * Where impl stands for: + * + * `extends` parents { defs } + */ + 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 */ trait ClassDefApi extends ImplDefApi { this: ClassDef => @@ -184,7 +359,33 @@ trait Trees extends base.Trees { self: Universe => val impl: Template } - override type ModuleDef >: Null <: ImplDef with ModuleDefApi + /** An object definition, e.g. `object Foo`. Internally, objects are + * quite frequently called modules to reduce ambiguity. + * Eliminated by compiler phase refcheck. + */ + 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. + */ + implicit val ModuleDefTag: ClassTag[ModuleDef] + + /** The constructor/deconstructor for `ModuleDef` instances. */ + val ModuleDef: ModuleDefExtractor + + /** An extractor class to create and pattern match with syntax `ModuleDef(mods, name, impl)`. + * This AST node corresponds to the following Scala code: + * + * mods `object` name impl + * + * Where impl stands for: + * + * `extends` parents { defs } + */ + 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 */ trait ModuleDefApi extends ImplDefApi { this: ModuleDef => @@ -193,7 +394,14 @@ trait Trees extends base.Trees { self: Universe => val impl: Template } - override type ValOrDefDef >: Null <: MemberDef with ValOrDefDefApi + /** A common base class for ValDefs and DefDefs. + */ + 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. + */ + implicit val ValOrDefDefTag: ClassTag[ValOrDefDef] /** The API that all val defs and def defs support */ trait ValOrDefDefApi extends MemberDefApi { this: ValOrDefDef => @@ -202,7 +410,42 @@ trait Trees extends base.Trees { self: Universe => def rhs: Tree } - override type ValDef >: Null <: ValOrDefDef with ValDefApi + /** Broadly speaking, a value definition. All these are encoded as ValDefs: + * + * - immutable values, e.g. "val x" + * - mutable values, e.g. "var x" - the MUTABLE flag set in mods + * - 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 => } + */ + 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. + */ + implicit val ValDefTag: ClassTag[ValDef] + + /** The constructor/deconstructor for `ValDef` instances. */ + val ValDef: ValDefExtractor + + /** An extractor class to create and pattern match with syntax `ValDef(mods, name, tpt, rhs)`. + * This AST node corresponds to any of the following Scala code: + * + * mods `val` name: tpt = rhs + * + * mods `var` name: tpt = rhs + * + * mods name: tpt = rhs // in signatures of function and method definitions + * + * self: Bar => // self-types + * + * 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`!). + */ + 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 */ trait ValDefApi extends ValOrDefDefApi { this: ValDef => @@ -212,7 +455,31 @@ trait Trees extends base.Trees { self: Universe => val rhs: Tree } - override type DefDef >: Null <: ValOrDefDef with DefDefApi + /** 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 + */ + 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. + */ + implicit val DefDefTag: ClassTag[DefDef] + + /** The constructor/deconstructor for `DefDef` instances. */ + val DefDef: DefDefExtractor + + /** An extractor class to create and pattern match with syntax `DefDef(mods, name, tparams, vparamss, tpt, rhs)`. + * This AST node corresponds to the following Scala code: + * + * mods `def` name[tparams](vparams_1)...(vparams_n): tpt = rhs + * + * 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`!). + */ + 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 */ trait DefDefApi extends ValOrDefDefApi { this: DefDef => @@ -224,7 +491,34 @@ trait Trees extends base.Trees { self: Universe => val rhs: Tree } - override type TypeDef >: Null <: MemberDef with TypeDefApi + /** An abstract type, a type parameter, or a type alias. + * Eliminated by erasure. + */ + 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. + */ + implicit val TypeDefTag: ClassTag[TypeDef] + + /** The constructor/deconstructor for `TypeDef` instances. */ + val TypeDef: TypeDefExtractor + + /** An extractor class to create and pattern match with syntax `TypeDef(mods, name, tparams, rhs)`. + * This AST node corresponds to the following Scala code: + * + * mods `type` name[tparams] = rhs + * + * mods `type` name[tparams] >: lo <: hi + * + * 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. + */ + 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 */ trait TypeDefApi extends MemberDefApi { this: TypeDef => @@ -234,7 +528,46 @@ trait Trees extends base.Trees { self: Universe => val rhs: Tree } - override type LabelDef >: Null <: DefTree with TermTree with LabelDefApi + /** A labelled expression. Not expressible in language syntax, but + * generated by the compiler to simulate while/do-while loops, and + * also by the pattern matcher. + * + * The label acts much like a nested function, where `params` represents + * the incoming parameters. The symbol given to the LabelDef should have + * a MethodType, as if it were a nested function. + * + * Jumps are apply nodes attributed with a label's symbol. The + * arguments from the apply node will be passed to the label and + * assigned to the Idents. + * + * Forward jumps within a block are allowed. + */ + 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. + */ + implicit val LabelDefTag: ClassTag[LabelDef] + + /** The constructor/deconstructor for `LabelDef` instances. */ + val LabelDef: LabelDefExtractor + + /** An extractor class to create and pattern match with syntax `LabelDef(name, params, rhs)`. + * + * This AST node does not have direct correspondence to Scala code. + * 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 ()) + * }}} + * {{{ + * do body while (cond) ==> LabelDef($L, List(), body; if (cond) L$() else ()) + * }}} + */ + 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 */ trait LabelDefApi extends DefTreeApi with TermTreeApi { this: LabelDef => @@ -243,7 +576,34 @@ trait Trees extends base.Trees { self: Universe => val rhs: Tree } - override type ImportSelector >: Null <: ImportSelectorApi + /** Import selector + * + * Representation of an imported name its optional rename and their optional positions + * + * Eliminated by typecheck. + * + * @param name the imported name + * @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 + */ + 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. + */ + implicit val ImportSelectorTag: ClassTag[ImportSelector] + + /** The constructor/deconstructor for `ImportSelector` instances. */ + 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. + */ + 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 */ trait ImportSelectorApi { this: ImportSelector => @@ -253,7 +613,42 @@ trait Trees extends base.Trees { self: Universe => val renamePos: Int } - override type Import >: Null <: SymTree with ImportApi + /** Import clause + * + * @param expr + * @param selectors + */ + 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. + */ + implicit val ImportTag: ClassTag[Import] + + /** The constructor/deconstructor for `Import` instances. */ + val Import: ImportExtractor + + /** An extractor class to create and pattern match with syntax `Import(expr, selectors)`. + * This AST node corresponds to the following Scala code: + * + * import expr.{selectors} + * + * Selectors are a list of ImportSelectors, which conceptually are pairs of names (from, to). + * The last (and maybe only name) may be a nme.WILDCARD. For instance: + * + * import qual.{x, y => z, _} + * + * Would be represented as: + * + * Import(qual, List(("x", "x"), ("y", "z"), (WILDCARD, null))) + * + * 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. + */ + 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 */ trait ImportApi extends SymTreeApi { this: Import => @@ -261,7 +656,43 @@ trait Trees extends base.Trees { self: Universe => val selectors: List[ImportSelector] } - override type Template >: Null <: SymTree with TemplateApi + /** Instantiation template of a class or trait + * + * @param parents + * @param body + */ + 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. + */ + implicit val TemplateTag: ClassTag[Template] + + /** The constructor/deconstructor for `Template` instances. */ + val Template: TemplateExtractor + + /** An extractor class to create and pattern match with syntax `Template(parents, self, body)`. + * This AST node corresponds to the following Scala code: + * + * `extends` parents { self => body } + * + * In case when the self-type annotation is missing, it is represented as + * an empty value definition with nme.WILDCARD as name and NoType as type. + * + * The symbol of a template is a local dummy. @see Symbol.newLocalDummy + * The owner of the local dummy is the enclosing trait or class. + * The local dummy is itself the owner of any local blocks. For example: + * + * class C { + * def foo { // owner is C + * def bar // owner is local dummy + * } + * } + */ + 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 */ trait TemplateApi extends SymTreeApi { this: Template => @@ -270,7 +701,28 @@ trait Trees extends base.Trees { self: Universe => val body: List[Tree] } - override type Block >: Null <: TermTree with BlockApi + /** Block of expressions (semicolon separated expressions) */ + 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. + */ + implicit val BlockTag: ClassTag[Block] + + /** The constructor/deconstructor for `Block` instances. */ + val Block: BlockExtractor + + /** An extractor class to create and pattern match with syntax `Block(stats, expr)`. + * This AST node corresponds to the following Scala code: + * + * { stats; expr } + * + * If the block is empty, the `expr` is set to `Literal(Constant(()))`. + */ + 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 */ trait BlockApi extends TermTreeApi { this: Block => @@ -278,7 +730,32 @@ trait Trees extends base.Trees { self: Universe => val expr: Tree } - override type CaseDef >: Null <: Tree with CaseDefApi + /** 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) + */ + 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. + */ + implicit val CaseDefTag: ClassTag[CaseDef] + + /** The constructor/deconstructor for `CaseDef` instances. */ + val CaseDef: CaseDefExtractor + + /** An extractor class to create and pattern match with syntax `CaseDef(pat, guard, body)`. + * This AST node corresponds to the following Scala code: + * + * `case` pat `if` guard => body + * + * 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())` + */ + 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 */ trait CaseDefApi extends TreeApi { this: CaseDef => @@ -287,21 +764,92 @@ trait Trees extends base.Trees { self: Universe => val body: Tree } - override type Alternative >: Null <: TermTree with AlternativeApi + /** Alternatives of patterns. + * + * 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(...))) + */ + 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. + */ + implicit val AlternativeTag: ClassTag[Alternative] + + /** The constructor/deconstructor for `Alternative` instances. */ + 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 + */ + abstract class AlternativeExtractor { + def apply(trees: List[Tree]): Alternative + def unapply(alternative: Alternative): Option[List[Tree]] + } /** The API that all alternatives support */ trait AlternativeApi extends TermTreeApi { this: Alternative => val trees: List[Tree] } - override type Star >: Null <: TermTree with StarApi + /** 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). + */ + 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. + */ + implicit val StarTag: ClassTag[Star] + + /** The constructor/deconstructor for `Star` instances. */ + 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* + */ + abstract class StarExtractor { + def apply(elem: Tree): Star + def unapply(star: Star): Option[Tree] + } /** The API that all stars support */ trait StarApi extends TermTreeApi { this: Star => val elem: Tree } - override type Bind >: Null <: DefTree with BindApi + /** Bind a variable to a rhs pattern. + * + * Eliminated by compiler phases patmat (in the new pattern matcher of 2.10) or explicitouter (in the old pre-2.10 pattern matcher). + * + * @param name + * @param body + */ + 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. + */ + implicit val BindTag: ClassTag[Bind] + + /** The constructor/deconstructor for `Bind` instances. */ + 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* + */ + abstract class BindExtractor { + def apply(name: Name, body: Tree): Bind + def unapply(bind: Bind): Option[(Name, Tree)] + } /** The API that all binds support */ trait BindApi extends DefTreeApi { this: Bind => @@ -309,7 +857,51 @@ trait Trees extends base.Trees { self: Universe => val body: Tree } - override type UnApply >: Null <: TermTree with UnApplyApi + /** + * Used to represent `unapply` methods in pattern matching. + * + * For example: + * {{{ + * 2 match { case Foo(x) => x } + * }}} + * + * Is represented as: + * {{{ + * Match( + * Literal(Constant(2)), + * List( + * CaseDef( + * UnApply( + * // a dummy node that carries the type of unapplication to patmat + * // the <unapply-selector> here doesn't have an underlying symbol + * // it only has a type assigned, therefore after `resetAllAttrs` this tree is no longer typeable + * Apply(Select(Ident(Foo), newTermName("unapply")), List(Ident(newTermName("<unapply-selector>")))), + * // arguments of the unapply => nothing synthetic here + * List(Bind(newTermName("x"), Ident(nme.WILDCARD)))), + * EmptyTree, + * Ident(newTermName("x"))))) + * }}} + * + * 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). + */ + 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. + */ + implicit val UnApplyTag: ClassTag[UnApply] + + /** The constructor/deconstructor for `UnApply` instances. */ + 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. + */ + 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 */ trait UnApplyApi extends TermTreeApi { this: UnApply => @@ -317,23 +909,56 @@ trait Trees extends base.Trees { self: Universe => val args: List[Tree] } - override type ArrayValue >: Null <: TermTree with ArrayValueApi + /** Anonymous function, eliminated by compiler phase lambdalift */ + type Function >: Null <: TermTree with SymTree with FunctionApi - /** The API that all array values support */ - trait ArrayValueApi extends TermTreeApi { this: ArrayValue => - val elemtpt: Tree - val elems: List[Tree] + /** A tag that preserves the identity of the `Function` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + */ + implicit val FunctionTag: ClassTag[Function] + + /** The constructor/deconstructor for `Function` instances. */ + val Function: FunctionExtractor + + /** An extractor class to create and pattern match with syntax `Function(vparams, body)`. + * This AST node corresponds to the following Scala code: + * + * vparams => body + * + * The symbol of a Function is a synthetic TermSymbol. + * It is the owner of the function's parameters. + */ + abstract class FunctionExtractor { + def apply(vparams: List[ValDef], body: Tree): Function + def unapply(function: Function): Option[(List[ValDef], Tree)] } - override type Function >: Null <: TermTree with SymTree with FunctionApi - /** The API that all functions support */ trait FunctionApi extends TermTreeApi with SymTreeApi { this: Function => val vparams: List[ValDef] val body: Tree } - override type Assign >: Null <: TermTree with AssignApi + /** Assignment */ + 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. + */ + implicit val AssignTag: ClassTag[Assign] + + /** The constructor/deconstructor for `Assign` instances. */ + 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 + */ + abstract class AssignExtractor { + def apply(lhs: Tree, rhs: Tree): Assign + def unapply(assign: Assign): Option[(Tree, Tree)] + } /** The API that all assigns support */ trait AssignApi extends TermTreeApi { this: Assign => @@ -341,7 +966,34 @@ trait Trees extends base.Trees { self: Universe => val rhs: Tree } - override type AssignOrNamedArg >: Null <: TermTree with AssignOrNamedArgApi + /** Either an assignment or a named argument. Only appears in argument lists, + * eliminated by compiler phase typecheck (doTypedApply), resurrected by reifier. + */ + 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. + */ + implicit val AssignOrNamedArgTag: ClassTag[AssignOrNamedArg] + + /** The constructor/deconstructor for `AssignOrNamedArg` instances. */ + val AssignOrNamedArg: AssignOrNamedArgExtractor + + /** An extractor class to create and pattern match with syntax `AssignOrNamedArg(lhs, rhs)`. + * This AST node corresponds to the following Scala code: + * + * {{{ + * m.f(lhs = rhs) + * }}} + * {{{ + * @annotation(lhs = rhs) + * }}} + * + */ + abstract class AssignOrNamedArgExtractor { + def apply(lhs: Tree, rhs: Tree): AssignOrNamedArg + def unapply(assignOrNamedArg: AssignOrNamedArg): Option[(Tree, Tree)] + } /** The API that all assigns support */ trait AssignOrNamedArgApi extends TermTreeApi { this: AssignOrNamedArg => @@ -349,7 +1001,28 @@ trait Trees extends base.Trees { self: Universe => val rhs: Tree } - override type If >: Null <: TermTree with IfApi + /** Conditional expression */ + 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. + */ + implicit val IfTag: ClassTag[If] + + /** The constructor/deconstructor for `If` instances. */ + val If: IfExtractor + + /** An extractor class to create and pattern match with syntax `If(cond, thenp, elsep)`. + * This AST node corresponds to the following Scala code: + * + * `if` (cond) thenp `else` elsep + * + * If the alternative is not present, the `elsep` is set to `Literal(Constant(()))`. + */ + 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 */ trait IfApi extends TermTreeApi { this: If => @@ -358,7 +1031,38 @@ trait Trees extends base.Trees { self: Universe => val elsep: Tree } - override type Match >: Null <: TermTree with MatchApi + /** - Pattern matching expression (before compiler phase explicitouter before 2.10 / patmat from 2.10) + * - Switch statements (after compiler phase explicitouter before 2.10 / patmat from 2.10) + * + * After compiler phase explicitouter before 2.10 / patmat from 2.10, cases will satisfy the following constraints: + * + * - all guards are `EmptyTree`, + * - all patterns will be either `Literal(Constant(x:Int))` + * or `Alternative(lit|...|lit)` + * - except for an "otherwise" branch, which has pattern + * `Ident(nme.WILDCARD)` + */ + 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. + */ + implicit val MatchTag: ClassTag[Match] + + /** The constructor/deconstructor for `Match` instances. */ + val Match: MatchExtractor + + /** An extractor class to create and pattern match with syntax `Match(selector, cases)`. + * This AST node corresponds to the following Scala code: + * + * selector `match` { cases } + * + * `Match` is also used in pattern matching assignments like `val (foo, bar) = baz`. + */ + 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 */ trait MatchApi extends TermTreeApi { this: Match => @@ -366,14 +1070,56 @@ trait Trees extends base.Trees { self: Universe => val cases: List[CaseDef] } - override type Return >: Null <: TermTree with SymTree with ReturnApi + /** Return expression */ + 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. + */ + implicit val ReturnTag: ClassTag[Return] + + /** The constructor/deconstructor for `Return` instances. */ + val Return: ReturnExtractor + + /** An extractor class to create and pattern match with syntax `Return(expr)`. + * This AST node corresponds to the following Scala code: + * + * `return` expr + * + * The symbol of a Return node is the enclosing method. + */ + abstract class ReturnExtractor { + def apply(expr: Tree): Return + def unapply(return_ : Return): Option[Tree] + } /** The API that all returns support */ trait ReturnApi extends TermTreeApi { this: Return => val expr: Tree } - override type Try >: Null <: TermTree with TryApi + /** [Eugene++] comment me! */ + 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. + */ + implicit val TryTag: ClassTag[Try] + + /** The constructor/deconstructor for `Try` instances. */ + val Try: TryExtractor + + /** An extractor class to create and pattern match with syntax `Try(block, catches, finalizer)`. + * This AST node corresponds to the following Scala code: + * + * `try` block `catch` { catches } `finally` finalizer + * + * If the finalizer is not present, the `finalizer` is set to `EmptyTree`. + */ + 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 */ trait TryApi extends TermTreeApi { this: Try => @@ -382,21 +1128,89 @@ trait Trees extends base.Trees { self: Universe => val finalizer: Tree } - override type Throw >: Null <: TermTree with ThrowApi + /** Throw expression */ + 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. + */ + implicit val ThrowTag: ClassTag[Throw] + + /** The constructor/deconstructor for `Throw` instances. */ + 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 + */ + abstract class ThrowExtractor { + def apply(expr: Tree): Throw + def unapply(throw_ : Throw): Option[Tree] + } /** The API that all tries support */ trait ThrowApi extends TermTreeApi { this: Throw => val expr: Tree } - override type New >: Null <: TermTree with NewApi + /** Object instantiation + */ + 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. + */ + implicit val NewTag: ClassTag[New] + + /** The constructor/deconstructor for `New` instances. + */ + val New: NewExtractor + + /** An extractor class to create and pattern match with syntax `New(tpt)`. + * This AST node corresponds to the following Scala code: + * + * `new` T + * + * This node always occurs in the following context: + * + * (`new` tpt).<init>[targs](args) + */ + abstract class NewExtractor { + /** A user level `new`. + * One should always use this factory method to build a user level `new`. + * + * @param tpt a class type + */ + def apply(tpt: Tree): New + def unapply(new_ : New): Option[Tree] + } /** The API that all news support */ trait NewApi extends TermTreeApi { this: New => val tpt: Tree } - override type Typed >: Null <: TermTree with TypedApi + /** Type annotation, eliminated by compiler phase cleanup */ + 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. + */ + implicit val TypedTag: ClassTag[Typed] + + /** The constructor/deconstructor for `Typed` instances. */ + 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 + */ + abstract class TypedExtractor { + def apply(expr: Tree, tpt: Tree): Typed + def unapply(typed: Typed): Option[(Tree, Tree)] + } /** The API that all typeds support */ trait TypedApi extends TermTreeApi { this: Typed => @@ -404,7 +1218,14 @@ trait Trees extends base.Trees { self: Universe => val tpt: Tree } - override type GenericApply >: Null <: TermTree with GenericApplyApi + /** Common base class for Apply and TypeApply. + */ + 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. + */ + implicit val GenericApplyTag: ClassTag[GenericApply] /** The API that all applies support */ trait GenericApplyApi extends TermTreeApi { this: GenericApply => @@ -412,19 +1233,99 @@ trait Trees extends base.Trees { self: Universe => val args: List[Tree] } - override type TypeApply >: Null <: GenericApply with TypeApplyApi + /* @PP: All signs point toward it being a requirement that args.nonEmpty, + * 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. */ + 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. + */ + implicit val TypeApplyTag: ClassTag[TypeApply] + + /** The constructor/deconstructor for `TypeApply` instances. */ + 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] + */ + 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 */ trait TypeApplyApi extends GenericApplyApi { this: TypeApply => } - override type Apply >: Null <: GenericApply with ApplyApi + /** Value application */ + 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. + */ + implicit val ApplyTag: ClassTag[Apply] + + /** The constructor/deconstructor for `Apply` instances. */ + val Apply: ApplyExtractor + + /** An extractor class to create and pattern match with syntax `Apply(fun, args)`. + * This AST node corresponds to the following Scala code: + * + * fun(args) + * + * For instance: + * + * fun[targs](args) + * + * Is expressed as: + * + * Apply(TypeApply(fun, targs), args) + */ + 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 */ trait ApplyApi extends GenericApplyApi { this: Apply => } - override type Super >: Null <: TermTree with SuperApi + /** Super reference, where `qual` is the corresponding `this` reference. + * A super reference `C.super[M]` is represented as `Super(This(C), M)`. + */ + 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. + */ + implicit val SuperTag: ClassTag[Super] + + /** The constructor/deconstructor for `Super` instances. */ + val Super: SuperExtractor + + /** An extractor class to create and pattern match with syntax `Super(qual, mix)`. + * This AST node corresponds to the following Scala code: + * + * C.super[M] + * + * Which is represented as: + * + * Super(This(C), M) + * + * If `mix` is empty, it is tpnme.EMPTY. + * + * The symbol of a Super is the class _from_ which the super reference is made. + * For instance in C.super(...), it would be C. + */ + abstract class SuperExtractor { + def apply(qual: Tree, mix: TypeName): Super + def unapply(super_ : Super): Option[(Tree, TypeName)] + } /** The API that all supers support */ trait SuperApi extends TermTreeApi { this: Super => @@ -432,14 +1333,57 @@ trait Trees extends base.Trees { self: Universe => val mix: TypeName } - override type This >: Null <: TermTree with SymTree with ThisApi + /** Self reference */ + 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. + */ + implicit val ThisTag: ClassTag[This] + + /** The constructor/deconstructor for `This` instances. */ + val This: ThisExtractor + + /** An extractor class to create and pattern match with syntax `This(qual)`. + * This AST node corresponds to the following Scala code: + * + * qual.this + * + * The symbol of a This is the class to which the this refers. + * For instance in C.this, it would be C. + * + * If `mix` is empty, then ??? + */ + abstract class ThisExtractor { + def apply(qual: TypeName): This + def unapply(this_ : This): Option[TypeName] + } /** The API that all thises support */ trait ThisApi extends TermTreeApi with SymTreeApi { this: This => val qual: TypeName } - override type Select >: Null <: RefTree with SelectApi + /** Designator <qualifier> . <name> */ + 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. + */ + implicit val SelectTag: ClassTag[Select] + + /** The constructor/deconstructor for `Select` instances. */ + 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 + */ + abstract class SelectExtractor { + def apply(qualifier: Tree, name: Name): Select + def unapply(select: Select): Option[(Tree, Name)] + } /** The API that all selects support */ trait SelectApi extends RefTreeApi { this: Select => @@ -447,28 +1391,132 @@ trait Trees extends base.Trees { self: Universe => val name: Name } - override type Ident >: Null <: RefTree with IdentApi + /** Identifier <name> */ + 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. + */ + implicit val IdentTag: ClassTag[Ident] + + /** The constructor/deconstructor for `Ident` instances. */ + val Ident: IdentExtractor + + /** An extractor class to create and pattern match with syntax `Ident(qual, name)`. + * This AST node corresponds to the following Scala code: + * + * name + * + * Type checker converts idents that refer to enclosing fields or methods to selects. + * For example, name ==> this.name + */ + abstract class IdentExtractor { + def apply(name: Name): Ident + def unapply(ident: Ident): Option[Name] + } /** The API that all idents support */ trait IdentApi extends RefTreeApi { this: Ident => val name: Name } - override type ReferenceToBoxed >: Null <: TermTree with ReferenceToBoxedApi + /** Marks underlying reference to id as boxed. + * @pre 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. + */ + 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. + */ + implicit val ReferenceToBoxedTag: ClassTag[ReferenceToBoxed] + + /** The constructor/deconstructor for `ReferenceToBoxed` instances. */ + val ReferenceToBoxed: ReferenceToBoxedExtractor + + /** An extractor class to create and pattern match with syntax `ReferenceToBoxed(ident)`. + * This AST node does not have direct correspondence to Scala code, + * and is emitted by macros to reference capture vars directly without going through `elem`. + * + * For example: + * + * var x = ... + * fun { x } + * + * Will emit: + * + * Ident(x) + * + * Which gets transformed to: + * + * Select(Ident(x), "elem") + * + * If `ReferenceToBoxed` were used instead of Ident, no transformation would be performed. + */ + abstract class ReferenceToBoxedExtractor { + def apply(ident: Ident): ReferenceToBoxed + def unapply(referenceToBoxed: ReferenceToBoxed): Option[Ident] + } /** The API that all references support */ trait ReferenceToBoxedApi extends TermTreeApi { this: ReferenceToBoxed => val ident: Tree } - override type Literal >: Null <: TermTree with LiteralApi + /** Literal */ + 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. + */ + implicit val LiteralTag: ClassTag[Literal] + + /** The constructor/deconstructor for `Literal` instances. */ + 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 + */ + abstract class LiteralExtractor { + def apply(value: Constant): Literal + def unapply(literal: Literal): Option[Constant] + } /** The API that all literals support */ trait LiteralApi extends TermTreeApi { this: Literal => val value: Constant } - override type Annotated >: Null <: Tree with AnnotatedApi + /** A tree that has an annotation attached to it. Only used for annotated types and + * annotation ascriptions, annotations on definitions are stored in the Modifiers. + * Eliminated by typechecker (typedAnnotated), the annotations are then stored in + * an AnnotatedType. + */ + 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. + */ + implicit val AnnotatedTag: ClassTag[Annotated] + + /** The constructor/deconstructor for `Annotated` instances. */ + val Annotated: AnnotatedExtractor + + /** An extractor class to create and pattern match with syntax `Annotated(annot, arg)`. + * This AST node corresponds to the following Scala code: + * + * arg @annot // for types + * arg: @annot // for exprs + */ + abstract class AnnotatedExtractor { + def apply(annot: Tree, arg: Tree): Annotated + def unapply(annotated: Annotated): Option[(Tree, Tree)] + } /** The API that all annotateds support */ trait AnnotatedApi extends TreeApi { this: Annotated => @@ -476,14 +1524,55 @@ trait Trees extends base.Trees { self: Universe => val arg: Tree } - override type SingletonTypeTree >: Null <: TypTree with SingletonTypeTreeApi + /** Singleton type, eliminated by RefCheck */ + 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. + */ + implicit val SingletonTypeTreeTag: ClassTag[SingletonTypeTree] + + /** The constructor/deconstructor for `SingletonTypeTree` instances. */ + 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 + */ + abstract class SingletonTypeTreeExtractor { + def apply(ref: Tree): SingletonTypeTree + def unapply(singletonTypeTree: SingletonTypeTree): Option[Tree] + } /** The API that all singleton type trees support */ trait SingletonTypeTreeApi extends TypTreeApi { this: SingletonTypeTree => val ref: Tree } - override type SelectFromTypeTree >: Null <: TypTree with RefTree with SelectFromTypeTreeApi + /** Type selection <qualifier> # <name>, eliminated by RefCheck */ + // [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. + */ + implicit val SelectFromTypeTreeTag: ClassTag[SelectFromTypeTree] + + /** The constructor/deconstructor for `SelectFromTypeTree` instances. */ + val SelectFromTypeTree: SelectFromTypeTreeExtractor + + /** An extractor class to create and pattern match with syntax `SelectFromTypeTree(qualifier, name)`. + * This AST node corresponds to the following Scala code: + * + * qualifier # selector + * + * Note: a path-dependent type p.T is expressed as p.type # T + */ + 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 */ trait SelectFromTypeTreeApi extends TypTreeApi with RefTreeApi { this: SelectFromTypeTree => @@ -491,14 +1580,52 @@ trait Trees extends base.Trees { self: Universe => val name: TypeName } - override type CompoundTypeTree >: Null <: TypTree with CompoundTypeTreeApi + /** Intersection type <parent1> with ... with <parentN> { <decls> }, eliminated by RefCheck */ + 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. + */ + implicit val CompoundTypeTreeTag: ClassTag[CompoundTypeTree] + + /** The constructor/deconstructor for `CompoundTypeTree` instances. */ + 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 } + */ + abstract class CompoundTypeTreeExtractor { + def apply(templ: Template): CompoundTypeTree + def unapply(compoundTypeTree: CompoundTypeTree): Option[Template] + } /** The API that all compound type trees support */ trait CompoundTypeTreeApi extends TypTreeApi { this: CompoundTypeTree => val templ: Template } - override type AppliedTypeTree >: Null <: TypTree with AppliedTypeTreeApi + /** Applied type <tpt> [ <args> ], eliminated by RefCheck */ + 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. + */ + implicit val AppliedTypeTreeTag: ClassTag[AppliedTypeTree] + + /** The constructor/deconstructor for `AppliedTypeTree` instances. */ + 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] + */ + 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 */ trait AppliedTypeTreeApi extends TypTreeApi { this: AppliedTypeTree => @@ -506,7 +1633,26 @@ trait Trees extends base.Trees { self: Universe => val args: List[Tree] } - override type TypeBoundsTree >: Null <: TypTree with TypeBoundsTreeApi + /** Document me! */ + 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. + */ + implicit val TypeBoundsTreeTag: ClassTag[TypeBoundsTree] + + /** The constructor/deconstructor for `TypeBoundsTree` instances. */ + 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 + */ + 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 */ trait TypeBoundsTreeApi extends TypTreeApi { this: TypeBoundsTree => @@ -514,7 +1660,26 @@ trait Trees extends base.Trees { self: Universe => val hi: Tree } - override type ExistentialTypeTree >: Null <: TypTree with ExistentialTypeTreeApi + /** Document me! */ + 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. + */ + implicit val ExistentialTypeTreeTag: ClassTag[ExistentialTypeTree] + + /** The constructor/deconstructor for `ExistentialTypeTree` instances. */ + 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 } + */ + 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 */ trait ExistentialTypeTreeApi extends TypTreeApi { this: ExistentialTypeTree => @@ -522,7 +1687,29 @@ trait Trees extends base.Trees { self: Universe => val whereClauses: List[Tree] } - override type TypeTree >: Null <: TypTree with TypeTreeApi + /** 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. */ + 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. + */ + implicit val TypeTreeTag: ClassTag[TypeTree] + + /** The constructor/deconstructor for `TypeTree` instances. */ + 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`. + */ + abstract class TypeTreeExtractor { + def apply(): TypeTree + def unapply(typeTree: TypeTree): Boolean + } /** The API that all type trees support */ trait TypeTreeApi extends TypTreeApi { this: TypeTree => @@ -536,6 +1723,83 @@ trait Trees extends base.Trees { self: Universe => */ val emptyValDef: ValDef +// ---------------------- factories ---------------------------------------------- + + /** @param sym the class symbol + * @param impl the implementation template + */ + def ClassDef(sym: Symbol, impl: Template): ClassDef + + /** + * @param sym the class symbol + * @param impl the implementation template + */ + def ModuleDef(sym: Symbol, impl: Template): ModuleDef + + def ValDef(sym: Symbol, rhs: Tree): ValDef + + def ValDef(sym: Symbol): ValDef + + def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef + + def DefDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef + + def DefDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef + + def DefDef(sym: Symbol, rhs: Tree): DefDef + + def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef + + /** A TypeDef node which defines given `sym` with given tight hand side `rhs`. */ + def TypeDef(sym: Symbol, rhs: Tree): TypeDef + + /** A TypeDef node which defines abstract type or type parameter for given `sym` */ + def TypeDef(sym: Symbol): TypeDef + + def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef + + /** Block factory that flattens directly nested blocks. + */ + def Block(stats: Tree*): Block + + /** casedef shorthand */ + def CaseDef(pat: Tree, body: Tree): CaseDef + + def Bind(sym: Symbol, body: Tree): Bind + + def Try(body: Tree, cases: (Tree, Tree)*): Try + + 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)` + */ + def New(tpt: Tree, argss: List[List[Tree]]): Tree + + /** 0-1 argument list new, based on a type. + */ + def New(tpe: Type, args: Tree*): Tree + + def New(sym: Symbol, args: Tree*): Tree + + def Apply(sym: Symbol, args: Tree*): Tree + + def ApplyConstructor(tpt: Tree, args: List[Tree]): Tree + + def Super(sym: Symbol, mix: TypeName): Tree + + def This(sym: Symbol): Tree + + def Select(qualifier: Tree, name: String): Select + + def Select(qualifier: Tree, sym: Symbol): Select + + def Ident(name: String): Ident + + def Ident(sym: Symbol): Ident + + def TypeTree(tp: Type): TypeTree + // ---------------------- copying ------------------------------------------------ /** The standard (lazy) tree copier @@ -565,7 +1829,6 @@ trait Trees extends base.Trees { self: Universe => def Star(tree: Tree, elem: Tree): Star def Bind(tree: Tree, name: Name, body: Tree): Bind def UnApply(tree: Tree, fun: Tree, args: List[Tree]): UnApply - def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]): ArrayValue def Function(tree: Tree, vparams: List[ValDef], body: Tree): Function def Assign(tree: Tree, lhs: Tree, rhs: Tree): Assign def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg @@ -682,9 +1945,35 @@ trait Trees extends base.Trees { self: Universe => protected def xtransform(transformer: Transformer, tree: Tree): Tree = throw new MatchError(tree) - type Modifiers >: Null <: ModifiersApi - abstract class ModifiersApi extends ModifiersBase + /** ... */ + 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. + */ + implicit val ModifiersTag: ClassTag[Modifiers] + + /** ... */ + abstract class ModifiersApi { + def flags: FlagSet // default: NoFlags + def hasFlag(flag: FlagSet): Boolean + def privateWithin: Name // default: EmptyTypeName + def annotations: List[Tree] // default: List() + def mapAnnotations(f: List[Tree] => List[Tree]): Modifiers = + Modifiers(flags, privateWithin, f(annotations)) + } + + val Modifiers: ModifiersCreator + abstract class ModifiersCreator { + def apply(): Modifiers = Modifiers(NoFlags, EmptyTypeName, List()) + def apply(flags: FlagSet, privateWithin: Name, annotations: List[Tree]): Modifiers + } + + def Modifiers(flags: FlagSet, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List()) + def Modifiers(flags: FlagSet): Modifiers = Modifiers(flags, EmptyTypeName) + + /** ... */ + lazy val NoMods = Modifiers() +} diff --git a/src/reflect/scala/reflect/api/TypeCreator.scala b/src/reflect/scala/reflect/api/TypeCreator.scala new file mode 100644 index 0000000000..cc6d38c548 --- /dev/null +++ b/src/reflect/scala/reflect/api/TypeCreator.scala @@ -0,0 +1,26 @@ +package scala.reflect +package api + +/** A mirror-aware factory for types. + * + * In the reflection API, artifacts are specific to universes and + * symbolic references used in artifacts (e.g. `scala.Int`) are resolved by mirrors. + * + * Therefore to build a type one needs to know a universe that the type is going to be bound to + * and a mirror that is going to resolve symbolic references (e.g. to determine that `scala.Int` + * points to a core class `Int` from scala-library.jar). + * + * `TypeCreator` implements this notion by providing a standalone type factory. + * + * This is immediately useful for type tags. When the compiler creates a type tag, + * the end result needs to make sense in any mirror. That's because the compiler knows + * the universe it's creating a type tag for (since `TypeTag` is path-dependent on a universe), + * but it cannot know in advance the mirror to instantiate the result in (e.g. on JVM + * it doesn't know what classloader use to resolve symbolic names in the type tag). + * + * Due to a typechecker restriction (no eta-expansion for dependent method types), + * `TypeCreator` can't have a functional type, so it's implemented as class with an apply method. + */ +abstract class TypeCreator { + def apply[U <: Universe with Singleton](m: MirrorOf[U]): U # Type +} diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala new file mode 100644 index 0000000000..a7e58d2bcb --- /dev/null +++ b/src/reflect/scala/reflect/api/TypeTags.scala @@ -0,0 +1,354 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2012 LAMP/EPFL + * @author Martin Odersky + */ + +package scala +package reflect +package api + +import java.lang.{ Class => jClass } +import scala.language.implicitConversions + +/* + * TODO + * add @see to docs about universes + * [Eugene++] also mention sensitivity to prefixes, i.e. that rb.TypeTag is different from ru.TypeTag + * [Chris++] tag.in(some mirror) or expr.in(some mirror) (does not work for tag and exprs in macros) + * Backwards compat item1: [Eugene++] it might be useful, though, to guard against abstractness of the incoming type. + */ +/** + * A type tag encapsulates a representation of type T. + * + * 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: + * + * {{{ + * 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) + * } + * }}} + * + * 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. + * + * 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. + * + * === Backward compatibility with Manifests === + * + * Type tags correspond loosely to 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, + * + * In Scala 2.10, manifests are deprecated, so it's advisable to migrate them to tags, + * because manifests will probably be removed in the next major release. + * + * In most cases it will be enough to replace ClassManifest with ClassTag and Manifest with TypeTag. + * There are however a few caveats: + * + * 1) The notion of OptManifest is no longer supported. Tags can reify arbitrary types, so they are always available. + * + * 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). + * + * 3) There's no replacement for factory methods defined in `ClassManifest` and `Manifest` companion objects. + * Consider assembling corresponding types using the reflection APIs provided by Java (for classes) and Scala (for types). + * + * 4) Certain manifest functions (such as `<:<`, `>:>` and `typeArguments`) weren't included in the tag API. + * Consider using the reflection APIs provided by Java (for classes) and Scala (for types) instead. + */ +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. + * + * @see [[scala.reflect.api.TypeTags]] + */ + @annotation.implicitNotFound(msg = "No WeakTypeTag available for ${T}") + trait WeakTypeTag[T] extends Equals with Serializable { + /** + * Mirror corresponding to the universe of this WeakTypeTag. + */ + val mirror: Mirror + /** + * Migrates type tag to another universe. + * + * Type tags are path dependent on their universe. This methods allows migration + * given the mirror corresponding to the target universe. + * + * Migration 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: MirrorOf[U]): U # WeakTypeTag[T] + + /** + * Reflective representation of type T. + */ + def tpe: Type + + // case class accessories + override def canEqual(x: Any) = x.isInstanceOf[WeakTypeTag[_]] + override def equals(x: Any) = x.isInstanceOf[WeakTypeTag[_]] && this.mirror == x.asInstanceOf[WeakTypeTag[_]].mirror && this.tpe == x.asInstanceOf[WeakTypeTag[_]].tpe + override def hashCode = mirror.hashCode * 31 + tpe.hashCode + override def toString = "WeakTypeTag[" + tpe + "]" + } + + /** + * Type tags corresponding to primitive types and constructor/extractor for WeakTypeTags. + */ + object WeakTypeTag { + val Byte : WeakTypeTag[scala.Byte] = TypeTag.Byte + val Short : WeakTypeTag[scala.Short] = TypeTag.Short + val Char : WeakTypeTag[scala.Char] = TypeTag.Char + val Int : WeakTypeTag[scala.Int] = TypeTag.Int + val Long : WeakTypeTag[scala.Long] = TypeTag.Long + val Float : WeakTypeTag[scala.Float] = TypeTag.Float + val Double : WeakTypeTag[scala.Double] = TypeTag.Double + val Boolean : WeakTypeTag[scala.Boolean] = TypeTag.Boolean + val Unit : WeakTypeTag[scala.Unit] = TypeTag.Unit + val Any : WeakTypeTag[scala.Any] = TypeTag.Any + val AnyVal : WeakTypeTag[scala.AnyVal] = TypeTag.AnyVal + val AnyRef : WeakTypeTag[scala.AnyRef] = TypeTag.AnyRef + val Object : WeakTypeTag[java.lang.Object] = TypeTag.Object + val Nothing : WeakTypeTag[scala.Nothing] = TypeTag.Nothing + val Null : WeakTypeTag[scala.Null] = TypeTag.Null + + + def apply[T](mirror1: MirrorOf[self.type], tpec1: TypeCreator): WeakTypeTag[T] = + tpec1(mirror1) match { + case ByteTpe => WeakTypeTag.Byte.asInstanceOf[WeakTypeTag[T]] + case ShortTpe => WeakTypeTag.Short.asInstanceOf[WeakTypeTag[T]] + case CharTpe => WeakTypeTag.Char.asInstanceOf[WeakTypeTag[T]] + case IntTpe => WeakTypeTag.Int.asInstanceOf[WeakTypeTag[T]] + case LongTpe => WeakTypeTag.Long.asInstanceOf[WeakTypeTag[T]] + case FloatTpe => WeakTypeTag.Float.asInstanceOf[WeakTypeTag[T]] + case DoubleTpe => WeakTypeTag.Double.asInstanceOf[WeakTypeTag[T]] + case BooleanTpe => WeakTypeTag.Boolean.asInstanceOf[WeakTypeTag[T]] + case UnitTpe => WeakTypeTag.Unit.asInstanceOf[WeakTypeTag[T]] + case AnyTpe => WeakTypeTag.Any.asInstanceOf[WeakTypeTag[T]] + case AnyValTpe => WeakTypeTag.AnyVal.asInstanceOf[WeakTypeTag[T]] + case AnyRefTpe => WeakTypeTag.AnyRef.asInstanceOf[WeakTypeTag[T]] + case ObjectTpe => WeakTypeTag.Object.asInstanceOf[WeakTypeTag[T]] + case NothingTpe => WeakTypeTag.Nothing.asInstanceOf[WeakTypeTag[T]] + case NullTpe => WeakTypeTag.Null.asInstanceOf[WeakTypeTag[T]] + case _ => new WeakTypeTagImpl[T](mirror1.asInstanceOf[Mirror], tpec1) + } + + def unapply[T](ttag: WeakTypeTag[T]): Option[Type] = Some(ttag.tpe) + } + + 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: MirrorOf[U]): U # WeakTypeTag[T] = { + val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]] + otherMirror.universe.WeakTypeTag[T](otherMirror1, tpec) + } + private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = false) + } + + /** + * A `TypeTag` is a [[scala.reflect.api.Universe#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]] + */ + @annotation.implicitNotFound(msg = "No TypeTag available for ${T}") + trait TypeTag[T] extends WeakTypeTag[T] with Equals with Serializable { + /** + * @inheritdoc + */ + override def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # TypeTag[T] + + // case class accessories + override def canEqual(x: Any) = x.isInstanceOf[TypeTag[_]] + override def equals(x: Any) = x.isInstanceOf[TypeTag[_]] && this.mirror == x.asInstanceOf[TypeTag[_]].mirror && this.tpe == x.asInstanceOf[TypeTag[_]].tpe + override def hashCode = mirror.hashCode * 31 + tpe.hashCode + override def toString = "TypeTag[" + tpe + "]" + } + + 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) + val Char: TypeTag[scala.Char] = new PredefTypeTag[scala.Char] (CharTpe, _.TypeTag.Char) + val Int: TypeTag[scala.Int] = new PredefTypeTag[scala.Int] (IntTpe, _.TypeTag.Int) + val Long: TypeTag[scala.Long] = new PredefTypeTag[scala.Long] (LongTpe, _.TypeTag.Long) + val Float: TypeTag[scala.Float] = new PredefTypeTag[scala.Float] (FloatTpe, _.TypeTag.Float) + val Double: TypeTag[scala.Double] = new PredefTypeTag[scala.Double] (DoubleTpe, _.TypeTag.Double) + val Boolean: TypeTag[scala.Boolean] = new PredefTypeTag[scala.Boolean] (BooleanTpe, _.TypeTag.Boolean) + val Unit: TypeTag[scala.Unit] = new PredefTypeTag[scala.Unit] (UnitTpe, _.TypeTag.Unit) + val Any: TypeTag[scala.Any] = new PredefTypeTag[scala.Any] (AnyTpe, _.TypeTag.Any) + val AnyVal: TypeTag[scala.AnyVal] = new PredefTypeTag[scala.AnyVal] (AnyValTpe, _.TypeTag.AnyVal) + val AnyRef: TypeTag[scala.AnyRef] = new PredefTypeTag[scala.AnyRef] (AnyRefTpe, _.TypeTag.AnyRef) + val Object: TypeTag[java.lang.Object] = new PredefTypeTag[java.lang.Object] (ObjectTpe, _.TypeTag.Object) + val Nothing: TypeTag[scala.Nothing] = new PredefTypeTag[scala.Nothing] (NothingTpe, _.TypeTag.Nothing) + val Null: TypeTag[scala.Null] = new PredefTypeTag[scala.Null] (NullTpe, _.TypeTag.Null) + + def apply[T](mirror1: MirrorOf[self.type], tpec1: TypeCreator): TypeTag[T] = + tpec1(mirror1) match { + case ByteTpe => TypeTag.Byte.asInstanceOf[TypeTag[T]] + case ShortTpe => TypeTag.Short.asInstanceOf[TypeTag[T]] + case CharTpe => TypeTag.Char.asInstanceOf[TypeTag[T]] + case IntTpe => TypeTag.Int.asInstanceOf[TypeTag[T]] + case LongTpe => TypeTag.Long.asInstanceOf[TypeTag[T]] + case FloatTpe => TypeTag.Float.asInstanceOf[TypeTag[T]] + case DoubleTpe => TypeTag.Double.asInstanceOf[TypeTag[T]] + case BooleanTpe => TypeTag.Boolean.asInstanceOf[TypeTag[T]] + case UnitTpe => TypeTag.Unit.asInstanceOf[TypeTag[T]] + case AnyTpe => TypeTag.Any.asInstanceOf[TypeTag[T]] + case AnyValTpe => TypeTag.AnyVal.asInstanceOf[TypeTag[T]] + case AnyRefTpe => TypeTag.AnyRef.asInstanceOf[TypeTag[T]] + case ObjectTpe => TypeTag.Object.asInstanceOf[TypeTag[T]] + case NothingTpe => TypeTag.Nothing.asInstanceOf[TypeTag[T]] + case NullTpe => TypeTag.Null.asInstanceOf[TypeTag[T]] + case _ => new TypeTagImpl[T](mirror1.asInstanceOf[Mirror], tpec1) + } + + def unapply[T](ttag: TypeTag[T]): Option[Type] = Some(ttag.tpe) + } + + private class TypeTagImpl[T](mirror: Mirror, tpec: TypeCreator) extends WeakTypeTagImpl[T](mirror, tpec) with TypeTag[T] { + override def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # TypeTag[T] = { + val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]] + otherMirror.universe.TypeTag[T](otherMirror1, tpec) + } + private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true) + } + + private class PredefTypeCreator[T](copyIn: Universe => Universe#TypeTag[T]) extends TypeCreator { + def apply[U <: Universe with Singleton](m: MirrorOf[U]): U # Type = { + copyIn(m.universe).asInstanceOf[U # TypeTag[T]].tpe + } + } + + 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) + } + + /** + * 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 + + // big thanks to Viktor Klang for this brilliant idea! + /** + * 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 +} + +private[scala] class SerializedTypeTag(var tpec: TypeCreator, var concrete: Boolean) extends Serializable { + private def writeObject(out: java.io.ObjectOutputStream): Unit = { + out.writeObject(tpec) + out.writeBoolean(concrete) + } + + private def readObject(in: java.io.ObjectInputStream): Unit = { + tpec = in.readObject().asInstanceOf[TypeCreator] + concrete = in.readBoolean() + } + + private def readResolve(): AnyRef = { + import scala.reflect.runtime.universe._ + if (concrete) TypeTag(rootMirror, tpec) + else WeakTypeTag(rootMirror, tpec) + } +} diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala index 1c79de02c3..af70c9e761 100644 --- a/src/reflect/scala/reflect/api/Types.scala +++ b/src/reflect/scala/reflect/api/Types.scala @@ -1,13 +1,39 @@ package scala.reflect package api -trait Types extends base.Types { self: Universe => +/** + * Defines the type hierachy for types. + * + * Note: Because of implementation details, some type factories have return type `Type` + * instead of a more precise type. + * + * @see [[scala.reflect]] for a description on how the class hierarchy is encoded here. + */ +trait Types { self: Universe => + + /** The type of Scala types, and also Scala type signatures. + * (No difference is internally made between the two). + */ + type Type >: Null <: TypeApi - override 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. + */ + implicit val TypeTagg: ClassTag[Type] - /** The extended API of types + /** This constant is used as a special value that indicates that no meaningful type exists. */ - abstract class TypeApi extends TypeBase { + 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`. + */ + val NoPrefix: Type + + /** The API of types + */ + abstract class TypeApi { /** The term symbol associated with the type, or `NoSymbol` for types * that do not refer to a term symbol. */ @@ -152,42 +178,177 @@ trait Types extends base.Types { self: Universe => def contains(sym: Symbol): Boolean } - /** .. */ - override type ThisType >: Null <: SingletonType with ThisTypeApi + /** The type of Scala singleton types, i.e., types that are inhabited + * by only one nun-null value. These include types of the forms + * {{{ + * C.this.type + * C.super.type + * x.type + * }}} + * as well as [[ConstantType constant 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. + */ + implicit val SingletonTypeTag: ClassTag[SingletonType] + + /** A singleton type that describes types of the form on the left with the + * corresponding `ThisType` representation to the right: + * {{{ + * C.this.type ThisType(C) + * }}} + */ + 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. + */ + implicit val ThisTypeTag: ClassTag[ThisType] + + /** The constructor/deconstructor for `ThisType` instances. */ + 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. + */ + abstract class ThisTypeExtractor { + /** + * Creates a ThisType from the given class symbol. + */ + def apply(sym: Symbol): Type + def unapply(tpe: ThisType): Option[Symbol] + } /** The API that all this types support */ trait ThisTypeApi extends TypeApi { this: ThisType => val sym: Symbol } - /** .. */ - override type SingleType >: Null <: SingletonType with SingleTypeApi + /** The `SingleType` type describes types of any of the forms on the left, + * with their TypeRef representations to the right. + * {{{ + * (T # x).type SingleType(T, x) + * p.x.type SingleType(p.type, x) + * x.type SingleType(NoPrefix, x) + * }}} + */ + 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. + */ + implicit val SingleTypeTag: ClassTag[SingleType] + + /** The constructor/deconstructor for `SingleType` instances. */ + 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. + */ + 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 */ trait SingleTypeApi extends TypeApi { this: SingleType => val pre: Type val sym: Symbol } + /** The `SuperType` type is not directly written, but arises when `C.super` is used + * as a prefix in a `TypeRef` or `SingleType`. It's internal presentation is + * {{{ + * SuperType(thistpe, supertpe) + * }}} + * 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`. + */ + type SuperType >: Null <: AnyRef with SingletonType with SuperTypeApi - /** .. */ - override type SuperType >: Null <: 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. + */ + implicit val SuperTypeTag: ClassTag[SuperType] + + /** The constructor/deconstructor for `SuperType` instances. */ + val SuperType: SuperTypeExtractor + + /** An extractor class to create and pattern match with syntax `SingleType(thistpe, supertpe)` + */ + 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 */ trait SuperTypeApi extends TypeApi { this: SuperType => val thistpe: Type val supertpe: Type } + /** The `ConstantType` type is not directly written in user programs, but arises as the type of a constant. + * The REPL expresses constant types like `Int(11)`. Here are some constants with their types: + * {{{ + * 1 ConstantType(Constant(1)) + * "abc" ConstantType(Constant("abc")) + * }}} + */ + 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. + */ + implicit val ConstantTypeTag: ClassTag[ConstantType] - /** .. */ - override type ConstantType >: Null <: SingletonType with ConstantTypeApi + /** The constructor/deconstructor for `ConstantType` instances. */ + 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. + */ + abstract class ConstantTypeExtractor { + def apply(value: Constant): ConstantType + def unapply(tpe: ConstantType): Option[Constant] + } /** The API that all constant types support */ trait ConstantTypeApi extends TypeApi { this: ConstantType => val value: Constant } - /** .. */ - override type TypeRef >: Null <: Type with TypeRefApi + /** The `TypeRef` type describes types of any of the forms on the left, + * with their TypeRef representations to the right. + * {{{ + * T # C[T_1, ..., T_n] TypeRef(T, C, List(T_1, ..., T_n)) + * p.C[T_1, ..., T_n] TypeRef(p.type, C, List(T_1, ..., T_n)) + * C[T_1, ..., T_n] TypeRef(NoPrefix, C, List(T_1, ..., T_n)) + * T # C TypeRef(T, C, Nil) + * p.C TypeRef(p.type, C, Nil) + * C TypeRef(NoPrefix, C, Nil) + * }}} + */ + 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. + */ + implicit val TypeRefTag: ClassTag[TypeRef] + + /** The constructor/deconstructor for `TypeRef` instances. */ + 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. + */ + 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 */ trait TypeRefApi extends TypeApi { this: TypeRef => @@ -196,8 +357,46 @@ trait Types extends base.Types { self: Universe => val args: List[Type] } - /** .. */ - override type RefinedType >: Null <: CompoundType with RefinedTypeApi + /** A subtype of Type representing refined types as well as `ClassInfo` signatures. + */ + 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. + */ + implicit val CompoundTypeTag: ClassTag[CompoundType] + + /** The `RefinedType` type defines types of any of the forms on the left, + * with their RefinedType representations to the right. + * {{{ + * P_1 with ... with P_m { D_1; ...; D_n} RefinedType(List(P_1, ..., P_m), Scope(D_1, ..., D_n)) + * 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)) + * }}} + */ + 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. + */ + implicit val RefinedTypeTag: ClassTag[RefinedType] + + /** The constructor/deconstructor for `RefinedType` instances. */ + 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. + */ + abstract class RefinedTypeExtractor { + def apply(parents: List[Type], decls: Scope): RefinedType + + /** An alternative constructor that passes in the synthetic classs symbol + * that backs the refined type. (Normally, a fresh class symbol is created automatically). + */ + def apply(parents: List[Type], decls: Scope, clazz: Symbol): RefinedType + def unapply(tpe: RefinedType): Option[(List[Type], Scope)] + } /** The API that all refined types support */ trait RefinedTypeApi extends TypeApi { this: RefinedType => @@ -205,8 +404,35 @@ trait Types extends base.Types { self: Universe => val decls: Scope } - /** .. */ - override type ClassInfoType >: Null <: CompoundType with ClassInfoTypeApi + /** The `ClassInfo` type signature is used to define parents and declarations + * of classes, traits, and objects. If a class, trait, or object C is declared like this + * {{{ + * C extends P_1 with ... with P_m { D_1; ...; D_n} + * }}} + * its `ClassInfo` type has the following form: + * {{{ + * ClassInfo(List(P_1, ..., P_m), Scope(D_1, ..., D_n), C) + * }}} + */ + 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. + */ + implicit val ClassInfoTypeTag: ClassTag[ClassInfoType] + + /** The constructor/deconstructor for `ClassInfoType` instances. */ + 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. + */ + 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 */ trait ClassInfoTypeApi extends TypeApi { this: ClassInfoType => @@ -215,8 +441,36 @@ trait Types extends base.Types { self: Universe => val typeSymbol: Symbol } - /** .. */ - override type MethodType >: Null <: Type with MethodTypeApi + /** The `MethodType` type signature is used to indicate parameters and result type of a method + */ + 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. + */ + implicit val MethodTypeTag: ClassTag[MethodType] + + /** The constructor/deconstructor for `MethodType` instances. */ + val MethodType: MethodTypeExtractor + + /** An extractor class to create and pattern match with syntax `MethodType(params, respte)` + * Here, `params` is a potentially empty list of parameter symbols of the method, + * and `restpe` is the result type of the method. If the method is curried, `restpe` would + * be another `MethodType`. + * Note: `MethodType(Nil, Int)` would be the type of a method defined with an empty parameter list. + * {{{ + * def f(): Int + * }}} + * If the method is completely parameterless, as in + * {{{ + * def f: Int + * }}} + * its type is a `NullaryMethodType`. + */ + 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 */ trait MethodTypeApi extends TypeApi { this: MethodType => @@ -224,16 +478,53 @@ trait Types extends base.Types { self: Universe => val resultType: Type } - /** .. */ - override type NullaryMethodType >: Null <: Type with NullaryMethodTypeApi + /** The `NullaryMethodType` type signature is used for parameterless methods + * with declarations of the form `def foo: T` + */ + 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. + */ + implicit val NullaryMethodTypeTag: ClassTag[NullaryMethodType] + + /** The constructor/deconstructor for `NullaryMethodType` instances. */ + 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. + */ + abstract class NullaryMethodTypeExtractor { + def apply(resultType: Type): NullaryMethodType + def unapply(tpe: NullaryMethodType): Option[(Type)] + } /** The API that all nullary method types support */ trait NullaryMethodTypeApi extends TypeApi { this: NullaryMethodType => val resultType: Type } - /** .. */ - override type PolyType >: Null <: Type with PolyTypeApi + /** The `PolyType` type signature is used for polymorphic methods + * that have at least one type parameter. + */ + 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. + */ + implicit val PolyTypeTag: ClassTag[PolyType] + + /** The constructor/deconstructor for `PolyType` instances. */ + 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. + */ + 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 */ trait PolyTypeApi extends TypeApi { this: PolyType => @@ -241,8 +532,28 @@ trait Types extends base.Types { self: Universe => val resultType: Type } - /** .. */ - override type ExistentialType >: Null <: Type with ExistentialTypeApi + /** The `ExistentialType` type signature is used for existential types and + * wildcard 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. + */ + implicit val ExistentialTypeTag: ClassTag[ExistentialType] + + /** The constructor/deconstructor for `ExistentialType` instances. */ + 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. + */ + 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 */ trait ExistentialTypeApi extends TypeApi { this: ExistentialType => @@ -250,8 +561,28 @@ trait Types extends base.Types { self: Universe => val underlying: Type } - /** .. */ - override type AnnotatedType >: Null <: Type with AnnotatedTypeApi + /** The `AnnotatedType` type signature is used for annotated types of the + * for `<type> @<annotation>`. + */ + 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. + */ + implicit val AnnotatedTypeTag: ClassTag[AnnotatedType] + + /** The constructor/deconstructor for `AnnotatedType` instances. */ + 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. + */ + 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 */ trait AnnotatedTypeApi extends TypeApi { this: AnnotatedType => @@ -260,8 +591,34 @@ trait Types extends base.Types { self: Universe => val selfsym: Symbol } - /** .. */ - override type TypeBounds >: Null <: Type with TypeBoundsApi + /** The `TypeBounds` type signature is used to indicate lower and upper type bounds + * of type parameters and abstract types. It is not a first-class type. + * If an abstract type or type parameter is declared with any of the forms + * on the left, its type signature is the TypeBounds type on the right. + * {{{ + * T >: L <: U TypeBounds(L, U) + * T >: L TypeBounds(L, Any) + * T <: U TypeBounds(Nothing, U) + * }}} + */ + 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. + */ + implicit val TypeBoundsTag: ClassTag[TypeBounds] + + /** The constructor/deconstructor for `TypeBounds` instances. */ + 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. + */ + abstract class TypeBoundsExtractor { + def apply(lo: Type, hi: Type): TypeBounds + def unapply(tpe: TypeBounds): Option[(Type, Type)] + } /** The API that all type bounds support */ trait TypeBoundsApi extends TypeApi { this: TypeBounds => @@ -269,8 +626,38 @@ trait Types extends base.Types { self: Universe => val hi: Type } - /** .. */ - override type BoundedWildcardType >: Null <: Type with BoundedWildcardTypeApi + /** An object representing an unknown type, used during type inference. + * If you see WildcardType outside of inference it is almost certainly a bug. + */ + val WildcardType: Type + + /** BoundedWildcardTypes, used only during type inference, are created in + * two places: + * + * 1. If the expected type of an expression is an existential type, + * its hidden symbols are replaced with bounded wildcards. + * 2. When an implicit conversion is being sought based in part on + * the name of a method in the converted type, a HasMethodMatching + * type is created: a MethodType with parameters typed as + * BoundedWildcardTypes. + */ + 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. + */ + implicit val BoundedWildcardTypeTag: ClassTag[BoundedWildcardType] + + /** The constructor/deconstructor for `BoundedWildcardType` instances. */ + val BoundedWildcardType: BoundedWildcardTypeExtractor + + /** An extractor class to create and pattern match with syntax `BoundedWildcardTypeExtractor(bounds)` + * with `bounds` denoting the type bounds. + */ + abstract class BoundedWildcardTypeExtractor { + def apply(bounds: TypeBounds): BoundedWildcardType + def unapply(tpe: BoundedWildcardType): Option[TypeBounds] + } /** The API that all this types support */ trait BoundedWildcardTypeApi extends TypeApi { this: BoundedWildcardType => diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index 3165f9abcd..7d0f6cf0d6 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -1,17 +1,82 @@ package scala.reflect package api -abstract class Universe extends base.Universe - with Symbols +abstract class Universe extends Symbols with Types with FlagSets + with Scopes with Names with Trees - with Printers with Constants + with Annotations with Positions - with Mirrors + with Exprs + with TypeTags + with TagInterop with StandardDefinitions with StandardNames + with BuildUtils + with Mirrors + with Printers with Importers - with Annotations +{ + /** Produce the abstract syntax tree representing the given Scala expression. + * + * 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)) ) ) + * }}} + * + * 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 + */ + // implementation is hardwired to `scala.reflect.reify.Taggers` + // using the mechanism implemented in `scala.tools.reflect.FastTrack` + def reify[T](expr: T): Expr[T] = ??? // macro +}
\ No newline at end of file diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala index d2fce7cf1d..0b2a43936e 100644 --- a/src/reflect/scala/reflect/api/package.scala +++ b/src/reflect/scala/reflect/api/package.scala @@ -1,12 +1,80 @@ package scala.reflect -package object api { +import scala.reflect.api.{Universe => ApiUniverse} - // type and value aliases for slices of the base Universe cake that are not - // repeated in api.Universe - type Scopes = base.Scopes - type BuildUtils = base.BuildUtils - type Attachments = base.Attachments +/** + * 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`. + */ +package object api { - type MirrorOf[U <: base.Universe with Singleton] = base.MirrorOf[U] -} + // anchors for materialization macros emitted during tag materialization in Implicits.scala + // implementation is hardwired into `scala.reflect.reify.Taggers` + // using the mechanism implemented in `scala.tools.reflect.FastTrack` + // todo. once we have implicit macros for tag generation, we can remove these anchors + private[scala] def materializeWeakTypeTag[T](u: ApiUniverse): u.WeakTypeTag[T] = ??? // macro + private[scala] def materializeTypeTag[T](u: ApiUniverse): u.TypeTag[T] = ??? // macro +}
\ No newline at end of file diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index f7371f4180..9f41f0336e 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -3,9 +3,9 @@ package internal import Flags._ -trait BuildUtils extends base.BuildUtils { self: SymbolTable => +trait BuildUtils { self: SymbolTable => - class BuildImpl extends BuildBase { + class BuildImpl extends BuildApi { def selectType(owner: Symbol, name: String): TypeSymbol = select(owner, newTypeName(name)).asType @@ -64,5 +64,5 @@ trait BuildUtils extends base.BuildUtils { self: SymbolTable => def setSymbol[T <: Tree](tree: T, sym: Symbol): T = { tree.setSymbol(sym); tree } } - val build: BuildBase = new BuildImpl + val build: BuildApi = new BuildImpl } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 48a658192b..2db8c29a63 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -10,7 +10,7 @@ import scala.annotation.{ switch, meta } import scala.collection.{ mutable, immutable } import Flags._ import PartialFunction._ -import scala.reflect.base.{Universe => BaseUniverse} +import scala.reflect.api.{Universe => ApiUniverse} trait Definitions extends api.StandardDefinitions { self: SymbolTable => @@ -484,7 +484,7 @@ trait Definitions extends api.StandardDefinitions { // scala.reflect lazy val ReflectPackage = requiredModule[scala.reflect.`package`.type] - def ReflectBasis = getMemberValue(ReflectPackage, nme.basis) + lazy val ReflectApiPackage = getPackageObjectIfDefined("scala.reflect.api") // defined in scala-reflect.jar, so we need to be careful lazy val ReflectRuntimePackage = getPackageObjectIfDefined("scala.reflect.runtime") // defined in scala-reflect.jar, so we need to be careful def ReflectRuntimeUniverse = if (ReflectRuntimePackage != NoSymbol) getMemberValue(ReflectRuntimePackage, nme.universe) else NoSymbol def ReflectRuntimeCurrentMirror = if (ReflectRuntimePackage != NoSymbol) getMemberMethod(ReflectRuntimePackage, nme.currentMirror) else NoSymbol @@ -496,28 +496,31 @@ trait Definitions extends api.StandardDefinitions { lazy val OptManifestClass = requiredClass[scala.reflect.OptManifest[_]] lazy val NoManifest = requiredModule[scala.reflect.NoManifest.type] - lazy val ExprsClass = requiredClass[scala.reflect.base.Exprs] - lazy val ExprClass = getMemberClass(ExprsClass, tpnme.Expr) - def ExprSplice = getMemberMethod(ExprClass, nme.splice) - def ExprValue = getMemberMethod(ExprClass, nme.value) - lazy val ExprModule = getMemberModule(ExprsClass, nme.Expr) - - lazy val ClassTagModule = requiredModule[scala.reflect.ClassTag[_]] - lazy val ClassTagClass = requiredClass[scala.reflect.ClassTag[_]] - lazy val TypeTagsClass = requiredClass[scala.reflect.base.TypeTags] - lazy val WeakTypeTagClass = getMemberClass(TypeTagsClass, tpnme.WeakTypeTag) - lazy val WeakTypeTagModule = getMemberModule(TypeTagsClass, nme.WeakTypeTag) - lazy val TypeTagClass = getMemberClass(TypeTagsClass, tpnme.TypeTag) - lazy val TypeTagModule = getMemberModule(TypeTagsClass, nme.TypeTag) - - lazy val BaseUniverseClass = requiredClass[scala.reflect.base.Universe] - def BaseUniverseReify = getMemberMethod(BaseUniverseClass, nme.reify) + lazy val ExprsClass = getClassIfDefined("scala.reflect.api.Exprs") // defined in scala-reflect.jar, so we need to be careful + lazy val ExprClass = if (ExprsClass != NoSymbol) getMemberClass(ExprsClass, tpnme.Expr) else NoSymbol + def ExprSplice = if (ExprsClass != NoSymbol) getMemberMethod(ExprClass, nme.splice) else NoSymbol + def ExprValue = if (ExprsClass != NoSymbol) getMemberMethod(ExprClass, nme.value) else NoSymbol + lazy val ExprModule = if (ExprsClass != NoSymbol) getMemberModule(ExprsClass, nme.Expr) else NoSymbol + + lazy val ClassTagModule = requiredModule[scala.reflect.ClassTag[_]] + lazy val ClassTagClass = requiredClass[scala.reflect.ClassTag[_]] + lazy val TypeTagsClass = getClassIfDefined("scala.reflect.api.TypeTags") // defined in scala-reflect.jar, so we need to be careful + lazy val WeakTypeTagClass = if (TypeTagsClass != NoSymbol) getMemberClass(TypeTagsClass, tpnme.WeakTypeTag) else NoSymbol + lazy val WeakTypeTagModule = if (TypeTagsClass != NoSymbol) getMemberModule(TypeTagsClass, nme.WeakTypeTag) else NoSymbol + lazy val TypeTagClass = if (TypeTagsClass != NoSymbol) getMemberClass(TypeTagsClass, tpnme.TypeTag) else NoSymbol + lazy val TypeTagModule = if (TypeTagsClass != NoSymbol) getMemberModule(TypeTagsClass, nme.TypeTag) else NoSymbol + def materializeClassTag = getMemberMethod(ReflectPackage, nme.materializeClassTag) + def materializeWeakTypeTag = if (ReflectApiPackage != NoSymbol) getMemberMethod(ReflectApiPackage, nme.materializeWeakTypeTag) else NoSymbol + def materializeTypeTag = if (ReflectApiPackage != NoSymbol) getMemberMethod(ReflectApiPackage, nme.materializeTypeTag) else NoSymbol + + lazy val ApiUniverseClass = getClassIfDefined("scala.reflect.api.Universe") // defined in scala-reflect.jar, so we need to be careful + def ApiUniverseReify = if (ApiUniverseClass != NoSymbol) getMemberMethod(ApiUniverseClass, nme.reify) else NoSymbol lazy val JavaUniverseClass = getClassIfDefined("scala.reflect.api.JavaUniverse") // defined in scala-reflect.jar, so we need to be careful - lazy val MirrorOfClass = requiredClass[scala.reflect.base.MirrorOf[_]] + lazy val MirrorOfClass = getClassIfDefined("scala.reflect.api.MirrorOf") // defined in scala-reflect.jar, so we need to be careful - lazy val TypeCreatorClass = requiredClass[scala.reflect.base.TypeCreator] - lazy val TreeCreatorClass = requiredClass[scala.reflect.base.TreeCreator] + lazy val TypeCreatorClass = getClassIfDefined("scala.reflect.api.TypeCreator") // defined in scala-reflect.jar, so we need to be careful + lazy val TreeCreatorClass = getClassIfDefined("scala.reflect.api.TreeCreator") // defined in scala-reflect.jar, so we need to be careful lazy val MacroContextClass = getClassIfDefined("scala.reflect.macros.Context") // defined in scala-reflect.jar, so we need to be careful def MacroContextPrefix = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.prefix) else NoSymbol @@ -525,10 +528,6 @@ trait Definitions extends api.StandardDefinitions { def MacroContextUniverse = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.universe) else NoSymbol def MacroContextMirror = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.mirror) else NoSymbol lazy val MacroImplAnnotation = requiredClass[scala.reflect.macros.internal.macroImpl] - lazy val MacroInternalPackage = getPackageObject("scala.reflect.macros.internal") - def MacroInternal_materializeClassTag = getMemberMethod(MacroInternalPackage, nme.materializeClassTag) - def MacroInternal_materializeWeakTypeTag = getMemberMethod(MacroInternalPackage, nme.materializeWeakTypeTag) - def MacroInternal_materializeTypeTag = getMemberMethod(MacroInternalPackage, nme.materializeTypeTag) lazy val StringContextClass = requiredClass[scala.StringContext] def StringContext_f = getMemberMethod(StringContextClass, nme.f) @@ -542,8 +541,8 @@ trait Definitions extends api.StandardDefinitions { lazy val NoneModule: ModuleSymbol = requiredModule[scala.None.type] lazy val SomeModule: ModuleSymbol = requiredModule[scala.Some.type] - def compilerTypeFromTag(tt: BaseUniverse # WeakTypeTag[_]): Type = tt.in(rootMirror).tpe - def compilerSymbolFromTag(tt: BaseUniverse # WeakTypeTag[_]): Symbol = tt.in(rootMirror).tpe.typeSymbol + def compilerTypeFromTag(tt: ApiUniverse # WeakTypeTag[_]): Type = tt.in(rootMirror).tpe + def compilerSymbolFromTag(tt: ApiUniverse # WeakTypeTag[_]): Symbol = tt.in(rootMirror).tpe.typeSymbol // The given symbol represents either String.+ or StringAdd.+ def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+ diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala index 385e45997b..89332d0ae5 100644 --- a/src/reflect/scala/reflect/internal/Scopes.scala +++ b/src/reflect/scala/reflect/internal/Scopes.scala @@ -41,7 +41,7 @@ trait Scopes extends api.Scopes { self: SymbolTable => * This is necessary because when run from reflection every scope needs to have a * SynchronizedScope as mixin. */ - class Scope protected[Scopes] (initElems: ScopeEntry = null, initFingerPrints: Long = 0L) extends ScopeBase with MemberScopeBase { + class Scope protected[Scopes] (initElems: ScopeEntry = null, initFingerPrints: Long = 0L) extends ScopeApi with MemberScopeApi { protected[Scopes] def this(base: Scope) = { this(base.elems) diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 5f6a3bf777..5c4d1f7e28 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: base.Attachments { type Pos = Position } = NoPosition + protected var rawatt: scala.reflect.api.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/StdCreators.scala b/src/reflect/scala/reflect/internal/StdCreators.scala index 3e6b7c1ab4..eba583d4b5 100644 --- a/src/reflect/scala/reflect/internal/StdCreators.scala +++ b/src/reflect/scala/reflect/internal/StdCreators.scala @@ -1,20 +1,20 @@ package scala.reflect package internal -import scala.reflect.base.{TreeCreator, TypeCreator} -import scala.reflect.base.{Universe => BaseUniverse} +import scala.reflect.api.{TreeCreator, TypeCreator} +import scala.reflect.api.{Universe => ApiUniverse} trait StdCreators { self: SymbolTable => case class FixedMirrorTreeCreator(mirror: MirrorOf[StdCreators.this.type], tree: Tree) extends TreeCreator { - def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Tree = + def apply[U <: ApiUniverse with Singleton](m: MirrorOf[U]): U # Tree = if (m eq mirror) tree.asInstanceOf[U # Tree] else throw new IllegalArgumentException(s"Expr defined in $mirror cannot be migrated to other mirrors.") } case class FixedMirrorTypeCreator(mirror: MirrorOf[StdCreators.this.type], tpe: Type) extends TypeCreator { - def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type = + def apply[U <: ApiUniverse with Singleton](m: MirrorOf[U]): U # Type = if (m eq mirror) tpe.asInstanceOf[U # Type] else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.") } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 2f305296f5..2cdfb05e77 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -206,7 +206,6 @@ trait StdNames { } abstract class TypeNames extends Keywords with TypeNamesApi { - type NameType = TypeName protected implicit def createNameType(name: String): TypeName = newTypeNameCached(name) final val BYNAME_PARAM_CLASS_NAME: NameType = "<byname>" @@ -273,7 +272,6 @@ trait StdNames { } abstract class TermNames extends Keywords with TermNamesApi { - type NameType = TermName protected implicit def createNameType(name: String): TermName = newTermNameCached(name) /** Base strings from which synthetic names are derived. */ @@ -635,7 +633,6 @@ trait StdNames { val asInstanceOf_Ob : NameType = "$asInstanceOf" val assert_ : NameType = "assert" val assume_ : NameType = "assume" - val basis : NameType = "basis" val box: NameType = "box" val build : NameType = "build" val bytes: NameType = "bytes" diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 7d28b273f6..50e5afd21e 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -10,7 +10,6 @@ import scala.collection.{ mutable, immutable } import scala.collection.mutable.ListBuffer import util.Statistics import Flags._ -import base.Attachments import scala.annotation.tailrec import scala.tools.nsc.io.AbstractFile diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index f953e9b757..ebf0998573 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -272,9 +272,6 @@ abstract class TreeGen extends macros.TreeBuilder { def mkOr(tree1: Tree, tree2: Tree): Tree = Apply(Select(tree1, Boolean_or), List(tree2)) - def mkBasisUniverseRef: Tree = - mkAttributedRef(ReflectBasis) setType singleType(ReflectBasis.owner.thisPrefix, ReflectBasis) - def mkRuntimeUniverseRef: Tree = { assert(ReflectRuntimeUniverse != NoSymbol) mkAttributedRef(ReflectRuntimeUniverse) setType singleType(ReflectRuntimeUniverse.owner.thisPrefix, ReflectRuntimeUniverse) diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 6540d4a7c1..7ec9f7086d 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -7,7 +7,6 @@ package scala.reflect package internal import Flags._ -import base.Attachments import scala.collection.mutable.{ListBuffer, LinkedHashSet} import util.Statistics @@ -328,9 +327,23 @@ trait Trees extends api.Trees { self: SymbolTable => extends TermTree with UnApplyApi object UnApply extends UnApplyExtractor - case class ArrayValue(elemtpt: Tree, elems: List[Tree]) - extends TermTree with ArrayValueApi - object ArrayValue extends ArrayValueExtractor + /** An array of expressions. This AST node needs to be translated in backend. + * It is used to pass arguments to vararg arguments. + * Introduced by compiler phase uncurry. + * + * This AST node does not have direct correspondence to Scala code, + * and is used to pass arguments to vararg arguments. For instance: + * + * printf("%s%d", foo, 42) + * + * Is translated to after compiler phase uncurry to: + * + * Apply( + * Ident("printf"), + * Literal("%s%d"), + * ArrayValue(<Any>, List(Ident("foo"), Literal(42)))) + */ + case class ArrayValue(elemtpt: Tree, elems: List[Tree]) extends TermTree case class Function(vparams: List[ValDef], body: Tree) extends SymTree with TermTree with FunctionApi @@ -497,6 +510,7 @@ trait Trees extends api.Trees { self: SymbolTable => override type TreeCopier <: InternalTreeCopierOps abstract class InternalTreeCopierOps extends TreeCopierOps { def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]): ApplyDynamic + def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]): ArrayValue } class StrictTreeCopier extends InternalTreeCopierOps { @@ -1574,7 +1588,6 @@ trait Trees extends api.Trees { self: SymbolTable => implicit val StarTag = ClassTag[Star](classOf[Star]) implicit val BindTag = ClassTag[Bind](classOf[Bind]) implicit val UnApplyTag = ClassTag[UnApply](classOf[UnApply]) - implicit val ArrayValueTag = ClassTag[ArrayValue](classOf[ArrayValue]) implicit val FunctionTag = ClassTag[Function](classOf[Function]) implicit val AssignTag = ClassTag[Assign](classOf[Assign]) implicit val AssignOrNamedArgTag = ClassTag[AssignOrNamedArg](classOf[AssignOrNamedArg]) diff --git a/src/reflect/scala/reflect/internal/package.scala b/src/reflect/scala/reflect/internal/package.scala index 99b837152d..63568f6a6b 100644 --- a/src/reflect/scala/reflect/internal/package.scala +++ b/src/reflect/scala/reflect/internal/package.scala @@ -2,5 +2,5 @@ package scala.reflect package object internal { - type MirrorOf[U <: base.Universe with Singleton] = base.MirrorOf[U] + type MirrorOf[U <: scala.reflect.api.Universe with Singleton] = scala.reflect.api.MirrorOf[U] } diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala index 0268881be7..1621fb84d4 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.base.Attachments +import scala.reflect.api.Attachments import scala.reflect.api.PositionApi object Position { diff --git a/src/reflect/scala/reflect/macros/Reifiers.scala b/src/reflect/scala/reflect/macros/Reifiers.scala index bdc6687edc..c2a6c5be05 100644 --- a/src/reflect/scala/reflect/macros/Reifiers.scala +++ b/src/reflect/scala/reflect/macros/Reifiers.scala @@ -6,11 +6,6 @@ import scala.reflect.api.PositionApi trait Reifiers { self: Context => - /** Reification prefix that refers to the base reflexive universe, ``scala.reflect.basis''. - * Providing it for the ``prefix'' parameter of ``reifyTree'' or ``reifyType'' will create a tree that can be inspected at runtime. - */ - val basisUniverse: Tree - /** Reification prefix that refers to the runtime reflexive universe, ``scala.reflect.runtime.universe''. * Providing it for the ``prefix'' parameter of ``reifyTree'' or ``reifyType'' will create a full-fledged tree that can be inspected at runtime. */ @@ -20,7 +15,7 @@ trait Reifiers { * For more information and examples see the documentation for ``Universe.reify''. * * The produced tree will be bound to the specified ``universe'' and ``mirror''. - * Possible values for ``universe'' include ``basisUniverse'' and ``runtimeUniverse''. + * Possible values for ``universe'' include ``runtimeUniverse''. * Possible values for ``mirror'' include ``EmptyTree'' (in that case the reifier will automatically pick an appropriate mirror). * * This function is deeply connected to ``Universe.reify'', a macro that reifies arbitrary expressions into runtime trees. diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index 7fa2e7cbae..f84c11ee63 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -7,7 +7,7 @@ abstract class Universe extends scala.reflect.api.Universe { trait AttachableApi { /** ... */ - def attachments: base.Attachments { type Pos = Position } + def attachments: scala.reflect.api.Attachments { type Pos = Position } /** ... */ def updateAttachment[T: ClassTag](attachment: T): AttachableApi.this.type diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala index 06ce0b3244..df93785d40 100644 --- a/src/reflect/scala/reflect/macros/package.scala +++ b/src/reflect/scala/reflect/macros/package.scala @@ -2,5 +2,5 @@ package scala.reflect package object macros { - type MirrorOf[U <: base.Universe with Singleton] = base.MirrorOf[U] + type MirrorOf[U <: scala.reflect.api.Universe with Singleton] = scala.reflect.api.MirrorOf[U] } |