aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-04-19 14:41:11 +0200
committerMartin Odersky <odersky@gmail.com>2013-04-19 14:41:11 +0200
commit6b58c275293b2c2b0bf3390eaee94ec31bcbdab9 (patch)
tree74c264e1483b9a346821c53ad09df10c69e5f8bd /src/dotty/tools/dotc
parent344450ffcde551af8406fa1b873a6cb9dd430eb0 (diff)
downloaddotty-6b58c275293b2c2b0bf3390eaee94ec31bcbdab9.tar.gz
dotty-6b58c275293b2c2b0bf3390eaee94ec31bcbdab9.tar.bz2
dotty-6b58c275293b2c2b0bf3390eaee94ec31bcbdab9.zip
Added TreeBuilder and TreeInfo classes.
Also changed Untyped from Nothing to Null, because it avoids type inference problems.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/Printers.scala8
-rw-r--r--src/dotty/tools/dotc/core/TreeInfo.scala479
-rw-r--r--src/dotty/tools/dotc/core/Trees.scala338
-rw-r--r--src/dotty/tools/dotc/core/Types.scala7
-rw-r--r--src/dotty/tools/dotc/core/UntypedTrees.scala5
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala2
-rw-r--r--src/dotty/tools/dotc/parsing/TreeBuilder.scala548
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala5
-rw-r--r--src/dotty/tools/dotc/util/Positions.scala2
9 files changed, 1239 insertions, 155 deletions
diff --git a/src/dotty/tools/dotc/core/Printers.scala b/src/dotty/tools/dotc/core/Printers.scala
index 6255a79da..2828ade46 100644
--- a/src/dotty/tools/dotc/core/Printers.scala
+++ b/src/dotty/tools/dotc/core/Printers.scala
@@ -85,7 +85,7 @@ object Printers {
def toText(sc: Scope): Text
/** Textual representation of tree */
- def toText[T](tree: Tree[T]): Text
+ def toText[T >: Untyped](tree: Tree[T]): Text
}
class PlainPrinter(_ctx: Context) extends Printer {
@@ -403,7 +403,7 @@ object Printers {
def toText(sc: Scope): Text =
("Scope{" ~ dclsText(sc.toList) ~ "}").close
- def toText[T](tree: Tree[T]): Text = {
+ def toText[T >: Untyped](tree: Tree[T]): Text = {
tree match {
case node: Product =>
def toTextElem(elem: Any): Text = elem match {
@@ -431,10 +431,10 @@ object Printers {
override def nameString(name: Name): String = name.toString
- override protected def simpleNameString(sym: Symbol) = {
+ override protected def simpleNameString(sym: Symbol): String = {
var name = sym.originalName
if (sym is ModuleClass) name = name.stripModuleClassSuffix
- name.decode
+ name.decode.toString
}
override def toTextPrefix(tp: Type): Text = controlled {
diff --git a/src/dotty/tools/dotc/core/TreeInfo.scala b/src/dotty/tools/dotc/core/TreeInfo.scala
new file mode 100644
index 000000000..cb621164c
--- /dev/null
+++ b/src/dotty/tools/dotc/core/TreeInfo.scala
@@ -0,0 +1,479 @@
+package dotty.tools
+package dotc
+package core
+
+import Flags._, Trees._, UntypedTrees._, TypedTrees._, Types._, Contexts._
+import Names._, StdNames._, NameOps._, Decorators._, Symbols._
+import util.HashSet
+
+/** This class ...
+ *
+ * @author Martin Odersky
+ * @version 1.0
+ */
+abstract class TreeInfo {
+
+ def isDeclarationOrTypeDef(tree: Tree[_ >: Untyped]): Boolean = tree match {
+ case DefDef(_, _, _, _, _, EmptyTree())
+ | ValDef(_, _, _, EmptyTree())
+ | TypeDef(_, _, _) => true
+ case _ => false
+ }
+
+ /** Is tree legal as a member definition of an interface?
+ */
+ def isInterfaceMember(tree: Tree[_ >: Untyped]): Boolean = tree match {
+ case EmptyTree() => true
+ case Import(_, _) => true
+ case TypeDef(_, _, _) => true
+ case DefDef(mods, _, _, _, _, __) => mods.flags is Deferred
+ case ValDef(mods, _, _, _) => mods is Deferred
+ case _ => false
+ }
+
+ /** Is tree a definition that has no side effects when
+ * evaluated as part of a block after the first time?
+ */
+ def isIdempotentDef(tree: Tree[Type])(implicit ctx: Context): Boolean = tree match {
+ case EmptyTree()
+ | ClassDef(_, _, _, _)
+ | TypeDef(_, _, _)
+ | Import(_, _)
+ | DefDef(_, _, _, _, _, _) =>
+ true
+ case ValDef(mods, _, _, rhs) =>
+ !(mods is Mutable) && isIdempotentExpr(rhs)
+ case _ =>
+ false
+ }
+
+ /** Is tree an expression which can be inlined without affecting program semantics?
+ *
+ * Note that this is not called "isExprPure" since purity (lack of side-effects)
+ * is not the litmus test. References to modules and lazy vals are side-effecting,
+ * both because side-effecting code may be executed and because the first reference
+ * takes a different code path than all to follow; but they are safe to inline
+ * because the expression result from evaluating them is always the same.
+ */
+ def isIdempotentExpr(tree: Tree[Type])(implicit ctx: Context): Boolean = tree match {
+ case EmptyTree()
+ | This(_)
+ | Super(_, _)
+ | Literal(_) =>
+ true
+ case Ident(_) =>
+ tree.symbol is Stable
+ case Select(qual, _) =>
+ tree.symbol.isStable && isIdempotentExpr(qual)
+ case TypeApply(fn, _) =>
+ isIdempotentExpr(fn)
+/*
+ * Not sure we'll need that. Comment out until we find out
+ case Apply(Select(free @ Ident(_), nme.apply), _) if free.symbol.name endsWith nme.REIFY_FREE_VALUE_SUFFIX =>
+ // see a detailed explanation of this trick in `GenSymbols.reifyFreeTerm`
+ free.symbol.hasStableFlag && isIdempotentExpr(free)
+*/
+ case Apply(fn, Nil) =>
+ // Note: After uncurry, field accesses are represented as Apply(getter, Nil),
+ // so an Apply can also be pure.
+ // However, before typing, applications of nullary functional values are also
+ // Apply(function, Nil) trees. To prevent them from being treated as pure,
+ // we check that the callee is a method.
+ // The callee might also be a Block, which has a null symbol, so we guard against that (SI-7185)
+ fn.symbol != null && (fn.symbol is (Method, butNot = Lazy)) && isIdempotentExpr(fn)
+ case Typed(expr, _) =>
+ isIdempotentExpr(expr)
+ case Block(stats, expr) =>
+ (stats forall isIdempotentDef) && isIdempotentExpr(expr)
+ case _ =>
+ false
+ }
+
+ class MatchingArgs[T >: Untyped](params: List[Symbol], args: List[Tree[T]])(implicit ctx: Context) {
+ def foreach(f: (Symbol, Tree[T]) => Unit): Boolean = {
+ def recur(params: List[Symbol], args: List[Tree[T]]): Boolean = params match {
+ case Nil => args.isEmpty
+ case param :: params1 =>
+ if (defn.RepeatedParamClasses contains param.info.typeSymbol) {
+ for (arg <- args) f(param, arg)
+ true
+ } else args match {
+ case Nil => false
+ case arg :: args1 =>
+ f(param, args.head)
+ recur(params1, args1)
+ }
+ }
+ recur(params, args)
+ }
+ def zipped: List[(Symbol, Tree[T])] = map((_, _))
+ def map[R](f: (Symbol, Tree[T]) => R): List[R] = {
+ val b = List.newBuilder[R]
+ foreach(b += f(_, _))
+ b.result
+ }
+ }
+
+ /** The method part of an application node, possibly enclosed in a block
+ * with only valdefs as statements. the reason for also considering blocks
+ * is that named arguments can transform a call into a block, e.g.
+ * <init>(b = foo, a = bar)
+ * is transformed to
+ * { val x$1 = foo
+ * val x$2 = bar
+ * <init>(x$2, x$1)
+ * }
+ */
+ def methPart[T >: Untyped](tree: Tree[T]): Tree[T] = tree match {
+ case Apply(fn, _) => methPart(fn)
+ case TypeApply(fn, _) => methPart(fn)
+ case AppliedTypeTree(fn, _) => methPart(fn)
+ case Block(stats, expr) if stats forall (_.isInstanceOf[ValDef[_]]) => methPart(expr)
+ case _ => tree
+ }
+
+ /** Is symbol potentially a getter of a mutable variable?
+ */
+ def mayBeVarGetter(sym: Symbol)(implicit ctx: Context): Boolean = {
+ def maybeGetterType(tpe: Type): Boolean = tpe match {
+ case _: ExprType | _: ImplicitMethodType => true
+ case tpe: PolyType => maybeGetterType(tpe.resultType)
+ case _ => false
+ }
+ sym.owner.isClass && !sym.isStable && maybeGetterType(sym.info)
+ }
+
+ /** Is tree a reference to a mutable variable, or to a potential getter
+ * that has a setter in the same class?
+ */
+ def isVariableOrGetter(tree: Tree[Type])(implicit ctx: Context) = {
+ def sym = tree.symbol
+ def isVar = sym is Mutable
+ def isGetter =
+ mayBeVarGetter(sym) && sym.owner.info.member(sym.name.asTermName.getterToSetter).exists
+
+ tree match {
+ case Ident(_) => isVar
+ case Select(_, _) => isVar || isGetter
+ case Apply(_, _) =>
+ methPart(tree) match {
+ case Select(qual, nme.apply) => qual.tpe.member(nme.update).exists
+ case _ => false
+ }
+ case _ => false
+ }
+ }
+
+ /** Is tree a self constructor call this(...)? I.e. a call to a constructor of the
+ * same object?
+ */
+ def isSelfConstrCall(tree: Tree[_ >: Untyped]): Boolean = methPart(tree) match {
+ case Ident(nme.CONSTRUCTOR) | Select(This(_), nme.CONSTRUCTOR) => true
+ case _ => false
+ }
+
+ /** Is tree a super constructor call?
+ */
+ def isSuperConstrCall(tree: Tree[_ >: Untyped]): Boolean = methPart(tree) match {
+ case Select(Super(_, _), nme.CONSTRUCTOR) => true
+ case _ => false
+ }
+
+ def isSelfOrSuperConstrCall(tree: Tree[_ >: Untyped]): Boolean = methPart(tree) match {
+ case Ident(nme.CONSTRUCTOR)
+ | Select(This(_), nme.CONSTRUCTOR)
+ | Select(Super(_, _), nme.CONSTRUCTOR) => true
+ case _ => false
+ }
+
+ /** Strips layers of `.asInstanceOf[T]` / `_.$asInstanceOf[T]()` from an expression */
+ def stripCast(tree: Tree[Type])(implicit ctx: Context): Tree[Type] = {
+ def isCast(sel: Tree[Type]) = defn.asInstanceOfMethods contains sel.symbol
+ tree match {
+ case TypeApply(sel @ Select(inner, _), _) if isCast(sel) =>
+ stripCast(inner)
+ case Apply(TypeApply(sel @ Select(inner, _), _), Nil) if isCast(sel) =>
+ stripCast(inner)
+ case t =>
+ t
+ }
+ }
+
+ /** Is tree a variable pattern? */
+ def isVarPattern[T >: Untyped](pat: Tree[T]): Boolean = pat match {
+ case x: BackquotedIdent[_] => false
+ case x: Ident[_] => x.name.isVariableName
+ case _ => false
+ }
+
+ /** The first constructor definition in `stats` */
+ def firstConstructor[T >: Untyped](stats: List[Tree[T]]): Tree[T] = stats match {
+ case (meth: DefDef[_]) :: _ if meth.name.isConstructorName => meth
+ case stat :: stats => firstConstructor(stats)
+ case nil => EmptyTree()
+ }
+
+ /** The arguments to the first constructor in `stats`. */
+ def firstConstructorArgs[T >: Untyped](stats: List[Tree[T]]): List[Tree[T]] = firstConstructor(stats) match {
+ case DefDef(_, _, _, args :: _, _, _) => args
+ case _ => Nil
+ }
+
+ /** The value definitions marked PRESUPER in this statement sequence */
+ def preSuperFields[T >: Untyped](stats: List[Tree[T]]): List[ValDef[T]] =
+ (stats filter isEarlyValDef).asInstanceOf[List[ValDef[T]]]
+
+ def isEarlyDef(tree: Tree[_ >: Untyped]) = isEarlyValDef(tree) || isEarlyTypeDef(tree)
+
+ def isEarlyValDef(tree: Tree[_ >: Untyped]) = tree match {
+ case ValDef(mods, _, _, _) => mods is Scala2PreSuper
+ case _ => false
+ }
+
+ def isEarlyTypeDef(tree: Tree[_ >: Untyped]) = tree match {
+ case TypeDef(mods, _, _) => mods is Scala2PreSuper
+ case _ => false
+ }
+
+ /** Is tpt a vararg type of the form T* ? */
+ def isRepeatedParamType(tpt: Tree[_ >: Untyped])(implicit ctx: Context) = tpt match {
+ case tpt: TypeTree[_] => defn.RepeatedParamClasses contains tpt.typeOpt.typeSymbol
+ case AppliedTypeTree(Select(_, tpnme.REPEATED_PARAM_CLASS), _) => true
+ case AppliedTypeTree(Select(_, tpnme.JAVA_REPEATED_PARAM_CLASS), _) => true
+ case _ => false
+ }
+
+ /** Is tpt a by-name parameter type of the form => T? */
+ def isByNameParamType(tpt: Tree[_ >: Untyped])(implicit ctx: Context) = tpt match {
+ case tpt: TypeTree[_] => tpt.typeOpt.typeSymbol == defn.ByNameParamClass
+ case AppliedTypeTree(Select(_, tpnme.BYNAME_PARAM_CLASS), _) => true
+ case _ => false
+ }
+
+ /** Is name a left-associative operator? */
+ def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.last != ':')
+
+ /** Is tree a `this` node which belongs to `enclClass`? */
+ def isSelf(tree: Tree[_ >: Untyped], enclClass: Symbol)(implicit ctx: Context): Boolean = tree match {
+ case This(_) => tree.symbol == enclClass
+ case _ => false
+ }
+
+ /** a Match(Typed(_, tpt), _) must be translated into a switch if isSwitchAnnotation(tpt.tpe)
+ def isSwitchAnnotation(tpe: Type) = tpe hasAnnotation defn.SwitchClass
+ */
+
+ /** can this type be a type pattern? */
+ def mayBeTypePat(tree: Tree[Untyped]): Boolean = tree match {
+ case AndTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2)
+ case OrTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2)
+ case RefineTypeTree(tpt, refinements) => mayBeTypePat(tpt) || refinements.exists(_.isInstanceOf[Bind[_]])
+ case AppliedTypeTree(tpt, args) => mayBeTypePat(tpt) || args.exists(_.isInstanceOf[Bind[_]])
+ case SelectFromTypeTree(tpt, _) => mayBeTypePat(tpt)
+ case Annotated(_, tpt) => mayBeTypePat(tpt)
+ case _ => false
+ }
+
+ /** Is this argument node of the form <expr> : _* ?
+ */
+ def isWildcardStarArg(tree: Tree[_ >: Untyped]): Boolean = tree match {
+ case Typed(_, Ident(tpnme.WILDCARD_STAR)) => true
+ case _ => false
+ }
+
+ /** If this tree has type parameters, those. Otherwise Nil.
+ def typeParameters(tree: Tree[_]): List[TypeDef] = tree match {
+ case DefDef(_, _, tparams, _, _, _) => tparams
+ case ClassDef(_, _, tparams, _) => tparams
+ case TypeDef(_, _, tparams, _) => tparams
+ case _ => Nil
+ }*/
+
+ /** Does this argument list end with an argument of the form <expr> : _* ? */
+ def isWildcardStarArgList(trees: List[Tree[_ >: Untyped]]) =
+ trees.nonEmpty && isWildcardStarArg(trees.last)
+
+ /** Is the argument a wildcard argument of the form `_` or `x @ _`?
+ */
+ def isWildcardArg(tree: Tree[_ >: Untyped]): Boolean = unbind(tree) match {
+ case Ident(nme.WILDCARD) => true
+ case _ => false
+ }
+
+ /** Is the argument a wildcard star type of the form `_*`?
+ */
+ def isWildcardStarType(tree: Tree[_ >: Untyped]): Boolean = tree match {
+ case Ident(tpnme.WILDCARD_STAR) => true
+ case _ => false
+ }
+
+ /** Is this pattern node a catch-all (wildcard or variable) pattern? */
+ def isDefaultCase(cdef: CaseDef[_ >: Untyped]) = cdef match {
+ case CaseDef(pat, EmptyTree(), _) => isWildcardArg(pat)
+ case _ => false
+ }
+
+ /** Is this pattern node a synthetic catch-all case, added during PartialFuction synthesis before we know
+ * whether the user provided cases are exhaustive. */
+ def isSyntheticDefaultCase(cdef: CaseDef[_ >: Untyped]) = cdef match {
+ case CaseDef(Bind(nme.DEFAULT_CASE, _), EmptyTree(), _) => true
+ case _ => false
+ }
+
+ /** Does this CaseDef catch Throwable? */
+ def catchesThrowable(cdef: CaseDef[_ >: Untyped])(implicit ctx: Context) =
+ catchesAllOf(cdef, defn.ThrowableClass.typeConstructor)
+
+ /** Does this CaseDef catch everything of a certain Type? */
+ def catchesAllOf(cdef: CaseDef[_ >: Untyped], threshold: Type)(implicit ctx: Context) =
+ isDefaultCase(cdef) ||
+ cdef.guard.isEmpty && {
+ unbind(cdef.pat) match {
+ case Typed(Ident(nme.WILDCARD), tpt) => threshold <:< tpt.typeOpt
+ case _ => false
+ }
+ }
+
+ /** Is this pattern node a catch-all or type-test pattern? */
+ def isCatchCase(cdef: CaseDef[Type])(implicit ctx: Context) = cdef match {
+ case CaseDef(Typed(Ident(nme.WILDCARD), tpt), EmptyTree(), _) =>
+ isSimpleThrowable(tpt.tpe)
+ case CaseDef(Bind(_, Typed(Ident(nme.WILDCARD), tpt)), EmptyTree(), _) =>
+ isSimpleThrowable(tpt.tpe)
+ case _ =>
+ isDefaultCase(cdef)
+ }
+
+ private def isSimpleThrowable(tp: Type)(implicit ctx: Context): Boolean = tp match {
+ case tp @ TypeRef(pre, _) =>
+ (pre == NoPrefix || pre.widen.typeSymbol.isStatic) &&
+ (tp.symbol derivesFrom defn.ThrowableClass) && !(tp.symbol is Trait)
+ case _ =>
+ false
+ }
+
+ /** Is this case guarded? */
+ def isGuardedCase(cdef: CaseDef[_ >: Untyped]) = cdef.guard != EmptyTree()
+
+ /** Is this pattern node a sequence-valued pattern? */
+ def isSequenceValued(tree: Tree[_ >: Untyped]): Boolean = unbind(tree) match {
+ case Alternative(ts) => ts exists isSequenceValued
+ case SeqLiteral(_, _) => true
+ case _ => false
+ }
+
+ /** The underlying pattern ignoring any bindings */
+ def unbind[T >: Untyped](x: Tree[T]): Tree[T] = x match {
+ case Bind(_, y) => unbind(y)
+ case y => y
+ }
+
+
+ /** Does list of trees start with a definition of
+ * a class of module with given name (ignoring imports)
+ def firstDefinesClassOrObject(trees: List[Tree], name: Name): Boolean = trees match {
+ case Import(_, _) :: xs => firstDefinesClassOrObject(xs, name)
+ case Annotated(_, tree1) :: Nil => firstDefinesClassOrObject(List(tree1), name)
+ case ModuleDef(_, `name`, _) :: Nil => true
+ case ClassDef(_, `name`, _, _) :: Nil => true
+ case _ => false
+ }
+
+
+ /** Is this file the body of a compilation unit which should not
+ * have Predef imported?
+ */
+ def noPredefImportForUnit(body: Tree) = {
+ // Top-level definition whose leading imports include Predef.
+ def isLeadingPredefImport(defn: Tree): Boolean = defn match {
+ case PackageDef(_, defs1) => defs1 exists isLeadingPredefImport
+ case Import(expr, _) => isReferenceToPredef(expr)
+ case _ => false
+ }
+ // Compilation unit is class or object 'name' in package 'scala'
+ def isUnitInScala(tree: Tree, name: Name) = tree match {
+ case PackageDef(Ident(nme.scala_), defs) => firstDefinesClassOrObject(defs, name)
+ case _ => false
+ }
+
+ isUnitInScala(body, nme.Predef) || isLeadingPredefImport(body)
+ }
+ */
+
+ /*
+ def isAbsTypeDef(tree: Tree) = tree match {
+ case TypeDef(_, _, _, TypeBoundsTree(_, _)) => true
+ case TypeDef(_, _, _, rhs) => rhs.tpe.isInstanceOf[TypeBounds]
+ case _ => false
+ }
+
+ def isAliasTypeDef(tree: Tree) = tree match {
+ case TypeDef(_, _, _, _) => !isAbsTypeDef(tree)
+ case _ => false
+ }
+
+ /** Some handy extractors for spotting trees through the
+ * the haze of irrelevant braces: i.e. Block(Nil, SomeTree)
+ * should not keep us from seeing SomeTree.
+ */
+ abstract class SeeThroughBlocks[T] {
+ protected def unapplyImpl(x: Tree): T
+ def unapply(x: Tree): T = x match {
+ case Block(Nil, expr) => unapply(expr)
+ case _ => unapplyImpl(x)
+ }
+ }
+ object IsTrue extends SeeThroughBlocks[Boolean] {
+ protected def unapplyImpl(x: Tree): Boolean = x match {
+ case Literal(Constant(true)) => true
+ case _ => false
+ }
+ }
+ object IsFalse extends SeeThroughBlocks[Boolean] {
+ protected def unapplyImpl(x: Tree): Boolean = x match {
+ case Literal(Constant(false)) => true
+ case _ => false
+ }
+ }
+ object IsIf extends SeeThroughBlocks[Option[(Tree, Tree, Tree)]] {
+ protected def unapplyImpl(x: Tree) = x match {
+ case If(cond, thenp, elsep) => Some((cond, thenp, elsep))
+ case _ => None
+ }
+ }
+
+ def isApplyDynamicName(name: Name) = (name == nme.updateDynamic) || (name == nme.selectDynamic) || (name == nme.applyDynamic) || (name == nme.applyDynamicNamed)
+
+ class DynamicApplicationExtractor(nameTest: Name => Boolean) {
+ def unapply(tree: Tree) = tree match {
+ case Apply(TypeApply(Select(qual, oper), _), List(Literal(Constant(name)))) if nameTest(oper) => Some((qual, name))
+ case Apply(Select(qual, oper), List(Literal(Constant(name)))) if nameTest(oper) => Some((qual, name))
+ case Apply(Ident(oper), List(Literal(Constant(name)))) if nameTest(oper) => Some((EmptyTree(), name))
+ case _ => None
+ }
+ }
+ object DynamicUpdate extends DynamicApplicationExtractor(_ == nme.updateDynamic)
+ object DynamicApplication extends DynamicApplicationExtractor(isApplyDynamicName)
+ object DynamicApplicationNamed extends DynamicApplicationExtractor(_ == nme.applyDynamicNamed)
+
+ object MacroImplReference {
+ private def refPart(tree: Tree): Tree = tree match {
+ case TypeApply(fun, _) => refPart(fun)
+ case ref: RefTree => ref
+ case _ => EmptyTree()
+ }
+
+ def unapply(tree: Tree) = refPart(tree) match {
+ case ref: RefTree => Some((ref.qualifier.symbol, ref.symbol, dissectApplied(tree).targs))
+ case _ => None
+ }
+ }
+
+ def isNullaryInvocation(tree: Tree): Boolean =
+ tree.symbol != null && tree.symbol.isMethod && (tree match {
+ case TypeApply(fun, _) => isNullaryInvocation(fun)
+ case tree: RefTree => true
+ case _ => false
+ })*/
+}
+object treeInfo extends TreeInfo \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/Trees.scala b/src/dotty/tools/dotc/core/Trees.scala
index c485eddc1..664b7f41b 100644
--- a/src/dotty/tools/dotc/core/Trees.scala
+++ b/src/dotty/tools/dotc/core/Trees.scala
@@ -5,17 +5,40 @@ import Types._, Names._, Flags._, util.Positions._, Contexts._, Constants._, Sym
import Denotations._, StdNames._
import annotation.tailrec
import language.higherKinds
+import collection.mutable
object Trees {
- case class Modifiers[T](
- flags: FlagSet,
+ // Note: it would be more logical to make Untyped = Nothing.
+ // However, this interacts in a bad way with Scala's current type inference.
+ // In fact, we cannot write soemthing like Select(pre, name), where pre is
+ // of type Tree[Nothing]; type inference will treat the Nothing as an uninstantited
+ // value and will not infer Nothing as the type parameter for Select.
+ // We should come back to this issue once type inference is changed.
+ type Untyped = Null
+ type TypedTree = Tree[Type]
+ type UntypedTree = Tree[Untyped]
+
+ case class Modifiers[T >: Untyped](
+ flags: FlagSet = EmptyFlags,
privateWithin: TypeName = tpnme.EMPTY,
- annotations: List[Tree[T]] = Nil)
+ annotations: List[Tree[T]] = Nil) {
+
+ def | (fs: FlagSet) = copy(flags = flags | fs)
+ def & (fs: FlagSet) = copy(flags = flags & fs)
+ def &~(fs: FlagSet) = copy(flags = flags &~ fs)
+ def is(fs: FlagSet) = flags is fs
+ def is(fc: FlagConjunction) = flags is fc
+ }
+
+ private val modCache = mutable.Map[FlagSet, Modifiers[Untyped]]()
+
+ def apply[T >: Untyped](flags: FlagSet = EmptyFlags): Modifiers[T] =
+ modCache.getOrElseUpdate(flags, Modifiers(flags, tpnme.EMPTY, Nil)).asInstanceOf[Modifiers[T]]
/** Trees take a parameter indicating what the type of their `tpe` field
- * is. Two choices: `Type` or `Nothing`.
- * Untyped trees have type `Tree[Nothing]`.
+ * is. Two choices: `Type` or `Untyped`.
+ * Untyped trees have type `Tree[Untyped]`.
*
* Tree typing uses a copy-on-write implementation:
*
@@ -29,7 +52,7 @@ object Trees {
* - Type checking an untyped tree should remove all embedded `TypedSplice`
* nodes.
*/
- abstract class Tree[T] extends DotClass with Showable with Cloneable {
+ abstract class Tree[T >: Untyped] extends DotClass with Showable with Cloneable {
/** The tree's position. Except
* for SharedTree nodes, it is always ensured that a tree's position
@@ -38,7 +61,7 @@ object Trees {
def pos: Position
/** The type constructor at the root of the tree */
- type ThisTree[T] <: Tree[T]
+ type ThisTree[T >: Untyped] <: Tree[T]
private var _tpe: T = _
@@ -77,6 +100,11 @@ object Trees {
*/
final def hasType: Boolean = _tpe != null
+ final def typeOpt: Type = _tpe match {
+ case tp: Type => tp
+ case _ => NoType
+ }
+
/** The denotation referred to by this tree.
* Defined for `DenotingTree`s and `ProxyTree`s, NoDenotation for other
* kinds of trees
@@ -107,43 +135,39 @@ object Trees {
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
}
- class UnAssignedTypeException[T](tree: Tree[T]) extends RuntimeException {
+ class UnAssignedTypeException[T >: Untyped](tree: Tree[T]) extends RuntimeException {
override def getMessage: String = s"type of $tree is not assigned"
}
- type Untyped = Null
- type TypedTree = Tree[Type]
- type UntypedTree = Tree[Nothing]
-
// ------ Categories of trees -----------------------------------
/** Instances of this class are trees for which isType is definitely true.
* Note that some trees have isType = true without being TypTrees (e.g. Ident, AnnotatedTree)
*/
- trait TypTree[T] extends Tree[T] {
- type ThisTree[T] <: TypTree[T]
+ trait TypTree[T >: Untyped] extends Tree[T] {
+ type ThisTree[T >: Untyped] <: TypTree[T]
override def isType = true
}
/** Instances of this class are trees for which isTerm is definitely true.
* Note that some trees have isTerm = true without being TermTrees (e.g. Ident, AnnotatedTree)
*/
- trait TermTree[T] extends Tree[T] {
- type ThisTree[T] <: TermTree[T]
+ trait TermTree[T >: Untyped] extends Tree[T] {
+ type ThisTree[T >: Untyped] <: TermTree[T]
override def isTerm = true
}
/** Instances of this class are trees which are not terms but are legal
* parts of patterns.
*/
- trait PatternTree[T] extends Tree[T] {
- type ThisTree[T] <: PatternTree[T]
+ trait PatternTree[T >: Untyped] extends Tree[T] {
+ type ThisTree[T >: Untyped] <: PatternTree[T]
override def isPattern = true
}
/** Tree's denotation can be derived from its type */
- abstract class DenotingTree[T] extends Tree[T] {
- type ThisTree[T] <: DenotingTree[T]
+ abstract class DenotingTree[T >: Untyped] extends Tree[T] {
+ type ThisTree[T >: Untyped] <: DenotingTree[T]
override def denot(implicit ctx: Context) = tpe match {
case tpe: NamedType => tpe.denot
case _ => NoDenotation
@@ -153,8 +177,8 @@ object Trees {
/** Tree's denot/isType/isTerm properties come from a subtree
* identified by `forwardTo`.
*/
- abstract class ProxyTree[T] extends Tree[T] {
- type ThisTree[T] <: ProxyTree[T]
+ abstract class ProxyTree[T >: Untyped] extends Tree[T] {
+ type ThisTree[T >: Untyped] <: ProxyTree[T]
def forwardTo: Tree[T]
override def denot(implicit ctx: Context): Denotation = forwardTo.denot
override def isTerm = forwardTo.isTerm
@@ -162,146 +186,152 @@ object Trees {
}
/** Tree has a name */
- abstract class NameTree[T] extends DenotingTree[T] {
- type ThisTree[T] <: NameTree[T]
+ abstract class NameTree[T >: Untyped] extends DenotingTree[T] {
+ type ThisTree[T >: Untyped] <: NameTree[T]
def name: Name
}
/** Tree refers by name to a denotation */
- abstract class RefTree[T] extends NameTree[T] {
- type ThisTree[T] <: RefTree[T]
+ abstract class RefTree[T >: Untyped] extends NameTree[T] {
+ type ThisTree[T >: Untyped] <: RefTree[T]
def qualifier: Tree[T]
override def isType = name.isTypeName
override def isTerm = name.isTermName
}
/** Tree defines a new symbol */
- trait DefTree[T] extends DenotingTree[T] {
- type ThisTree[T] <: DefTree[T]
+ trait DefTree[T >: Untyped] extends DenotingTree[T] {
+ type ThisTree[T >: Untyped] <: DefTree[T]
override def isDef = true
}
// ----------- Tree case classes ------------------------------------
/** name */
- case class Ident[T](name: Name)(implicit cpos: Position)
+ case class Ident[T >: Untyped](name: Name)(implicit cpos: Position)
extends RefTree[T] {
- type ThisTree[T] = Ident[T]
+ type ThisTree[T >: Untyped] = Ident[T]
val pos = cpos
def qualifier: Tree[T] = EmptyTree[T]
}
+ class BackquotedIdent[T >: Untyped](name: Name)(implicit cpos: Position)
+ extends Ident[T](name)
+
/** qualifier.name */
- case class Select[T](qualifier: Tree[T], name: Name)(implicit cpos: Position)
+ case class Select[T >: Untyped](qualifier: Tree[T], name: Name)(implicit cpos: Position)
extends RefTree[T] {
- type ThisTree[T] = Select[T]
+ type ThisTree[T >: Untyped] = Select[T]
val pos = cpos union qualifier.pos
}
/** qual.this */
- case class This[T](qual: TypeName)(implicit cpos: Position)
+ case class This[T >: Untyped](qual: TypeName)(implicit cpos: Position)
extends DenotingTree[T] with TermTree[T] {
- type ThisTree[T] = This[T]
+ type ThisTree[T >: Untyped] = This[T]
val pos = cpos
}
/** C.super[mix], where qual = C.this */
- case class Super[T](qual: Tree[T], mix: TypeName)(implicit cpos: Position)
+ case class Super[T >: Untyped](qual: Tree[T], mix: TypeName)(implicit cpos: Position)
extends ProxyTree[T] with TermTree[T] {
- type ThisTree[T] = Super[T]
+ type ThisTree[T >: Untyped] = Super[T]
val pos = cpos union qual.pos
def forwardTo = qual
}
- abstract class GenericApply[T] extends ProxyTree[T] with TermTree[T] {
- type ThisTree[T] <: GenericApply[T]
+ abstract class GenericApply[T >: Untyped] extends ProxyTree[T] with TermTree[T] {
+ type ThisTree[T >: Untyped] <: GenericApply[T]
val fun: Tree[T]
val args: List[Tree[T]]
def forwardTo = fun
}
/** fun(args) */
- case class Apply[T](fun: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
+ case class Apply[T >: Untyped](fun: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
extends GenericApply[T] {
- type ThisTree[T] = Apply[T]
+ type ThisTree[T >: Untyped] = Apply[T]
val pos = unionPos(cpos union fun.pos, args)
}
/** fun[args] */
- case class TypeApply[T](fun: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
+ case class TypeApply[T >: Untyped](fun: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
extends GenericApply[T] {
- type ThisTree[T] = TypeApply[T]
+ type ThisTree[T >: Untyped] = TypeApply[T]
val pos = unionPos(cpos union fun.pos, args)
}
/** const */
- case class Literal[T](const: Constant)(implicit cpos: Position)
+ case class Literal[T >: Untyped](const: Constant)(implicit cpos: Position)
extends TermTree[T] {
- type ThisTree[T] = Literal[T]
+ type ThisTree[T >: Untyped] = Literal[T]
val pos = cpos
}
/** new tpt, but no constructor call */
- case class New[T](tpt: Tree[T])(implicit cpos: Position)
+ case class New[T >: Untyped](tpt: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
- type ThisTree[T] = New[T]
+ type ThisTree[T >: Untyped] = New[T]
val pos = cpos union tpt.pos
}
/** (left, right) */
- case class Pair[T](left: Tree[T], right: Tree[T])(implicit cpos: Position)
+ case class Pair[T >: Untyped](left: Tree[T], right: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
- type ThisTree[T] = Pair[T]
+ type ThisTree[T >: Untyped] = Pair[T]
val pos = cpos union left.pos union right.pos
+ override def isTerm = left.isTerm && right.isTerm
+ override def isType = left.isType && right.isType
+ override def isPattern = !isTerm && (left.isPattern || left.isTerm) && (right.isPattern || right.isTerm)
}
/** expr : tpt */
- case class Typed[T](expr: Tree[T], tpt: Tree[T])(implicit cpos: Position)
+ case class Typed[T >: Untyped](expr: Tree[T], tpt: Tree[T])(implicit cpos: Position)
extends ProxyTree[T] with TermTree[T] {
- type ThisTree[T] = Typed[T]
+ type ThisTree[T >: Untyped] = Typed[T]
val pos = cpos union expr.pos union tpt.pos
def forwardTo = expr
}
/** name = arg, in a parameter list */
- case class NamedArg[T](name: Name, arg: Tree[T])(implicit cpos: Position)
+ case class NamedArg[T >: Untyped](name: Name, arg: Tree[T])(implicit cpos: Position)
extends Tree[T] {
- type ThisTree[T] = NamedArg[T]
+ type ThisTree[T >: Untyped] = NamedArg[T]
val pos = cpos union arg.pos
}
/** name = arg, outside a parameter list */
- case class Assign[T](lhs: Tree[T], rhs: Tree[T])(implicit cpos: Position)
+ case class Assign[T >: Untyped](lhs: Tree[T], rhs: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
- type ThisTree[T] = Assign[T]
+ type ThisTree[T >: Untyped] = Assign[T]
val pos = cpos union lhs.pos union rhs.pos
}
/** { stats; expr } */
- case class Block[T](stats: List[Tree[T]], expr: Tree[T])(implicit cpos: Position)
+ case class Block[T >: Untyped](stats: List[Tree[T]], expr: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
- type ThisTree[T] = Block[T]
+ type ThisTree[T >: Untyped] = Block[T]
val pos = unionPos(cpos union expr.pos, stats)
}
/** if cond then thenp else elsep */
- case class If[T](cond: Tree[T], thenp: Tree[T], elsep: Tree[T])(implicit cpos: Position)
+ case class If[T >: Untyped](cond: Tree[T], thenp: Tree[T], elsep: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
- type ThisTree[T] = If[T]
+ type ThisTree[T >: Untyped] = If[T]
val pos = cpos union cond.pos union thenp.pos union elsep.pos
}
/** selector match { cases } */
- case class Match[T](selector: Tree[T], cases: List[CaseDef[T]])(implicit cpos: Position)
+ case class Match[T >: Untyped](selector: Tree[T], cases: List[CaseDef[T]])(implicit cpos: Position)
extends TermTree[T] {
- type ThisTree[T] = Match[T]
+ type ThisTree[T >: Untyped] = Match[T]
val pos = unionPos(cpos union selector.pos, cases)
}
/** case pat if guard => body */
- case class CaseDef[T](pat: Tree[T], guard: Tree[T], body: Tree[T])(implicit cpos: Position)
+ case class CaseDef[T >: Untyped](pat: Tree[T], guard: Tree[T], body: Tree[T])(implicit cpos: Position)
extends Tree[T] {
- type ThisTree[T] = CaseDef[T]
+ type ThisTree[T >: Untyped] = CaseDef[T]
val pos = cpos union pat.pos union guard.pos union body.pos
}
@@ -310,151 +340,151 @@ object Trees {
* After program transformations this is not necessarily the enclosing method, because
* closures can intervene.
*/
- case class Return[T](expr: Tree[T], from: Ident[T])(implicit cpos: Position)
+ case class Return[T >: Untyped](expr: Tree[T], from: Ident[T])(implicit cpos: Position)
extends TermTree[T] {
- type ThisTree[T] = Return[T]
+ type ThisTree[T >: Untyped] = Return[T]
val pos = cpos union expr.pos // from is synthetic, does not influence pos
}
/** try block catch { catches } */
- case class Try[T](block: Tree[T], catches: List[CaseDef[T]], finalizer: Tree[T])(implicit cpos: Position)
+ case class Try[T >: Untyped](block: Tree[T], catches: List[CaseDef[T]], finalizer: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
- type ThisTree[T] = Try[T]
+ type ThisTree[T >: Untyped] = Try[T]
val pos = unionPos(cpos union block.pos union finalizer.pos, catches)
}
/** throw expr */
- case class Throw[T](expr: Tree[T])(implicit cpos: Position)
+ case class Throw[T >: Untyped](expr: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
- type ThisTree[T] = Throw[T]
+ type ThisTree[T >: Untyped] = Throw[T]
val pos = cpos union expr.pos
}
/** Array[elemtpt](elems) */
- case class SeqLiteral[T](elemtpt: Tree[T], elems: List[Tree[T]])(implicit cpos: Position)
+ case class SeqLiteral[T >: Untyped](elemtpt: Tree[T], elems: List[Tree[T]])(implicit cpos: Position)
extends Tree[T] {
- type ThisTree[T] = SeqLiteral[T]
+ type ThisTree[T >: Untyped] = SeqLiteral[T]
val pos = unionPos(cpos union elemtpt.pos, elems)
}
/** A type tree that represents an existing or inferred type */
- case class TypeTree[T](original: Tree[T] = EmptyTree[T])(implicit cpos: Position)
+ case class TypeTree[T >: Untyped](original: Tree[T] = EmptyTree[T])(implicit cpos: Position)
extends DenotingTree[T] with TypTree[T] {
- type ThisTree[T] = TypeTree[T]
- val pos = cpos union original.pos
+ type ThisTree[T >: Untyped] = TypeTree[T]
+ val pos = if (original.pos.exists) original.pos else cpos.focus
}
/** ref.type */
- case class SingletonTypeTree[T](ref: Tree[T])(implicit cpos: Position)
+ case class SingletonTypeTree[T >: Untyped](ref: Tree[T])(implicit cpos: Position)
extends DenotingTree[T] with TypTree[T] {
- type ThisTree[T] = SingletonTypeTree[T]
+ type ThisTree[T >: Untyped] = SingletonTypeTree[T]
val pos = cpos union ref.pos
}
/** qualifier # name */
- case class SelectFromTypeTree[T](qualifier: Tree[T], name: Name)(implicit cpos: Position)
+ case class SelectFromTypeTree[T >: Untyped](qualifier: Tree[T], name: Name)(implicit cpos: Position)
extends RefTree[T] {
- type ThisTree[T] = SelectFromTypeTree[T]
+ type ThisTree[T >: Untyped] = SelectFromTypeTree[T]
val pos = cpos union qualifier.pos
}
/** left & right */
- case class AndTypeTree[T](left: Tree[T], right: Tree[T])(implicit cpos: Position)
+ case class AndTypeTree[T >: Untyped](left: Tree[T], right: Tree[T])(implicit cpos: Position)
extends TypTree[T] {
- type ThisTree[T] = AndTypeTree[T]
+ type ThisTree[T >: Untyped] = AndTypeTree[T]
val pos = cpos union left.pos union right.pos
}
/** left | right */
- case class OrTypeTree[T](left: Tree[T], right: Tree[T])(implicit cpos: Position)
+ case class OrTypeTree[T >: Untyped](left: Tree[T], right: Tree[T])(implicit cpos: Position)
extends TypTree[T] {
- type ThisTree[T] = OrTypeTree[T]
+ type ThisTree[T >: Untyped] = OrTypeTree[T]
val pos = cpos union left.pos union right.pos
}
/** tpt { refinements } */
- case class RefineTypeTree[T](tpt: Tree[T], refinements: List[DefTree[T]])(implicit cpos: Position)
+ case class RefineTypeTree[T >: Untyped](tpt: Tree[T], refinements: List[DefTree[T]])(implicit cpos: Position)
extends ProxyTree[T] with TypTree[T] {
- type ThisTree[T] = RefineTypeTree[T]
+ type ThisTree[T >: Untyped] = RefineTypeTree[T]
val pos = unionPos(cpos union tpt.pos, refinements)
def forwardTo = tpt
}
/** tpt[args] */
- case class AppliedTypeTree[T](tpt: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
+ case class AppliedTypeTree[T >: Untyped](tpt: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
extends ProxyTree[T] with TypTree[T] {
- type ThisTree[T] = AppliedTypeTree[T]
+ type ThisTree[T >: Untyped] = AppliedTypeTree[T]
val pos = unionPos(cpos union tpt.pos, args)
def forwardTo = tpt
}
/** >: lo <: hi */
- case class TypeBoundsTree[T](lo: Tree[T], hi: Tree[T])(implicit cpos: Position)
+ case class TypeBoundsTree[T >: Untyped](lo: Tree[T], hi: Tree[T])(implicit cpos: Position)
extends Tree[T] {
- type ThisTree[T] = TypeBoundsTree[T]
+ type ThisTree[T >: Untyped] = TypeBoundsTree[T]
val pos = cpos union lo.pos union hi.pos
}
/** name @ body */
- case class Bind[T](name: Name, body: Tree[T])(implicit cpos: Position)
+ case class Bind[T >: Untyped](name: Name, body: Tree[T])(implicit cpos: Position)
extends NameTree[T] with DefTree[T] with PatternTree[T] {
- type ThisTree[T] = Bind[T]
+ type ThisTree[T >: Untyped] = Bind[T]
val pos = cpos union body.pos
}
/** tree_1 | ... | tree_n */
- case class Alternative[T](trees: List[Tree[T]])(implicit cpos: Position)
+ case class Alternative[T >: Untyped](trees: List[Tree[T]])(implicit cpos: Position)
extends PatternTree[T] {
- type ThisTree[T] = Alternative[T]
+ type ThisTree[T >: Untyped] = Alternative[T]
val pos = unionPos(cpos, trees)
}
/** fun(args) in a pattern, if fun is an extractor */
- case class UnApply[T](fun: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
+ case class UnApply[T >: Untyped](fun: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
extends PatternTree[T] {
- type ThisTree[T] = UnApply[T]
+ type ThisTree[T >: Untyped] = UnApply[T]
val pos = unionPos(cpos union fun.pos, args)
}
/** mods val name: tpt = rhs */
- case class ValDef[T](mods: Modifiers[T], name: TermName, tpt: Tree[T], rhs: Tree[T])(implicit cpos: Position)
+ case class ValDef[T >: Untyped](mods: Modifiers[T], name: TermName, tpt: Tree[T], rhs: Tree[T])(implicit cpos: Position)
extends NameTree[T] with DefTree[T] {
- type ThisTree[T] = ValDef[T]
+ type ThisTree[T >: Untyped] = ValDef[T]
val pos = cpos union tpt.pos union rhs.pos
}
/** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */
- case class DefDef[T](mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T])(implicit cpos: Position)
+ case class DefDef[T >: Untyped](mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T])(implicit cpos: Position)
extends NameTree[T] with DefTree[T] {
- type ThisTree[T] = DefDef[T]
+ type ThisTree[T >: Untyped] = DefDef[T]
val pos = (unionPos(cpos union tpt.pos union rhs.pos, tparams) /: vparamss)(unionPos)
}
- class ImplicitDefDef[T](mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T])(implicit pos: Position) extends DefDef[T](mods, name, tparams, vparamss, tpt, rhs) {
- override def copy[T](mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T])(implicit pos: Position) =
+ class ImplicitDefDef[T >: Untyped](mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T])(implicit pos: Position) extends DefDef[T](mods, name, tparams, vparamss, tpt, rhs) {
+ override def copy[T >: Untyped](mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T])(implicit pos: Position) =
new ImplicitDefDef[T](mods, name, tparams, vparamss, tpt, rhs)
}
/** mods type name = rhs or
* mods type name >: lo <: hi, if rhs = TypeBoundsTree(lo, hi)
*/
- case class TypeDef[T](mods: Modifiers[T], name: TypeName, rhs: Tree[T])(implicit cpos: Position)
+ case class TypeDef[T >: Untyped](mods: Modifiers[T], name: TypeName, rhs: Tree[T])(implicit cpos: Position)
extends NameTree[T] with DefTree[T] {
- type ThisTree[T] = TypeDef[T]
+ type ThisTree[T >: Untyped] = TypeDef[T]
val pos = cpos union rhs.pos
}
/** extends parents { self => body } */
- case class Template[T](parents: List[Tree[T]], self: ValDef[T], body: List[Tree[T]])(implicit cpos: Position)
+ case class Template[T >: Untyped](parents: List[Tree[T]], self: ValDef[T], body: List[Tree[T]])(implicit cpos: Position)
extends DefTree[T] {
- type ThisTree[T] = Template[T]
+ type ThisTree[T >: Untyped] = Template[T]
val pos = unionPos(unionPos(cpos union self.pos, parents), body)
}
/** mods class name[tparams] impl */
- case class ClassDef[T](mods: Modifiers[T], name: TypeName, tparams: List[TypeDef[T]], impl: Template[T])(implicit cpos: Position)
+ case class ClassDef[T >: Untyped](mods: Modifiers[T], name: TypeName, tparams: List[TypeDef[T]], impl: Template[T])(implicit cpos: Position)
extends NameTree[T] with DefTree[T] {
- type ThisTree[T] = ClassDef[T]
+ type ThisTree[T >: Untyped] = ClassDef[T]
val pos = unionPos(cpos union impl.pos, tparams)
}
@@ -462,29 +492,29 @@ object Trees {
* where a selector is either an untyped `Ident`, `name` or
* an untyped `Pair` `name => rename`
*/
- case class Import[T](expr: Tree[T], selectors: List[UntypedTree])(implicit cpos: Position)
+ case class Import[T >: Untyped](expr: Tree[T], selectors: List[UntypedTree])(implicit cpos: Position)
extends DenotingTree[T] {
- type ThisTree[T] = Import[T]
+ type ThisTree[T >: Untyped] = Import[T]
val pos = unionPos(cpos union expr.pos, selectors)
}
/** package pid { stats } */
- case class PackageDef[T](pid: RefTree[T], stats: List[Tree[T]])(implicit cpos: Position)
+ case class PackageDef[T >: Untyped](pid: RefTree[T], stats: List[Tree[T]])(implicit cpos: Position)
extends ProxyTree[T] {
- type ThisTree[T] = PackageDef[T]
+ type ThisTree[T >: Untyped] = PackageDef[T]
val pos = unionPos(cpos union pid.pos, stats)
def forwardTo = pid
}
/** arg @annot */
- case class Annotated[T](annot: Tree[T], arg: Tree[T])(implicit cpos: Position)
+ case class Annotated[T >: Untyped](annot: Tree[T], arg: Tree[T])(implicit cpos: Position)
extends ProxyTree[T] {
- type ThisTree[T] = Annotated[T]
+ type ThisTree[T >: Untyped] = Annotated[T]
val pos = cpos union annot.pos union arg.pos
def forwardTo = arg
}
- trait AlwaysEmpty[T] extends Tree[T] {
+ trait AlwaysEmpty[T >: Untyped] extends Tree[T] {
override val pos = NoPosition
override def tpe = unsupported("tpe")
override def withType(tpe: Type) = unsupported("withType")
@@ -492,32 +522,32 @@ object Trees {
}
/** A missing tree */
- abstract case class EmptyTree[T]()
+ abstract case class EmptyTree[T >: Untyped]()
extends Tree[T] with AlwaysEmpty[T] {
- type ThisTree[T] = EmptyTree[T]
+ type ThisTree[T >: Untyped] = EmptyTree[T]
}
- private object theEmptyTree extends EmptyTree[Nothing]
+ private object theEmptyTree extends EmptyTree[Untyped]
object EmptyTree {
- def apply[T]: EmptyTree[T] = theEmptyTree.asInstanceOf[EmptyTree[T]]
+ def apply[T >: Untyped](): EmptyTree[T] = theEmptyTree.asInstanceOf[EmptyTree[T]]
}
- class EmptyValDef[T] extends ValDef[T](
+ class EmptyValDef[T >: Untyped] extends ValDef[T](
Modifiers[T](Private), nme.WILDCARD, EmptyTree[T], EmptyTree[T])(NoPosition) with AlwaysEmpty[T]
- private object theEmptyValDef extends EmptyValDef[Nothing]
+ private object theEmptyValDef extends EmptyValDef[Untyped]
object EmptyValDef {
- def apply[T]: EmptyValDef[T] = theEmptyValDef.asInstanceOf[EmptyValDef[T]]
+ def apply[T >: Untyped](): EmptyValDef[T] = theEmptyValDef.asInstanceOf[EmptyValDef[T]]
}
/** A tree that can be shared without its position
* polluting containing trees. Accumulators and tranformers
* memoize results of shared subtrees
*/
- case class SharedTree[T](shared: Tree[T]) extends ProxyTree[T] {
- type ThisTree[T] = SharedTree[T]
+ case class SharedTree[T >: Untyped](shared: Tree[T]) extends ProxyTree[T] {
+ type ThisTree[T >: Untyped] = SharedTree[T]
def forwardTo: Tree[T] = shared
val pos = NoPosition
}
@@ -525,36 +555,47 @@ object Trees {
// ----- Tree cases that exist in untyped form only ------------------
/** A typed subtree of an untyped tree needs to be wrapped in a TypedSlice */
- class TypedSplice(tree: TypedTree) extends UntypedTree {
+ case class TypedSplice(tree: TypedTree) extends UntypedTree {
val pos = tree.pos
}
/** mods object name impl */
- case class ModuleDef(mods: Modifiers[Nothing], name: TermName, impl: Template[Nothing])(implicit cpos: Position)
- extends NameTree[Nothing] with DefTree[Nothing] {
- type ThisTree[T] <: NameTree[T] with DefTree[T] with ModuleDef
+ case class ModuleDef(mods: Modifiers[Untyped], name: TermName, impl: Template[Untyped])(implicit cpos: Position)
+ extends NameTree[Untyped] with DefTree[Untyped] {
+ type ThisTree[T >: Untyped] <: NameTree[T] with DefTree[T] with ModuleDef
val pos = cpos union impl.pos
- def derivedModuleDef(mods: Modifiers[Nothing], name: TermName, impl: Template[Nothing]) =
+ def derivedModuleDef(mods: Modifiers[Untyped], name: TermName, impl: Template[Untyped]) =
if (mods == this.mods && name == this.name && (impl eq this.impl)) this
else ModuleDef(mods, name, impl)
}
/** (vparams) => body */
- case class Function(vparams: List[ValDef[Nothing]], body: Tree[Nothing])(implicit cpos: Position)
- extends TermTree[Nothing] {
- type ThisTree[T] <: TermTree[T] with Function
+ case class Function(vparams: List[ValDef[Untyped]], body: Tree[Untyped])(implicit cpos: Position)
+ extends TermTree[Untyped] {
+ type ThisTree[T >: Untyped] <: TermTree[T] with Function
val pos = unionPos(cpos union body.pos, vparams)
}
/** Something in parentheses */
- case class Parens(trees: List[Tree[Nothing]])(implicit cpos: Position) extends Tree[Nothing] {
- type ThisType[T] <: Parens
+ case class Parens(trees: List[Tree[Untyped]])(implicit cpos: Position) extends Tree[Untyped] {
+ type ThisTree[T >: Untyped] <: Tree[T] with Parens
val pos = unionPos(cpos, trees)
}
+ // ----- Auxiliary creation methods ------------------
+
+ def Block[T >: Untyped](stat: Tree[T], expr: Tree[T])(implicit cpos: Position): Block[T] =
+ Block(stat :: Nil, expr)
+
+ def Apply[T >: Untyped](fn: Tree[T], arg: Tree[T])(implicit cpos: Position): Apply[T] =
+ Apply(fn, arg :: Nil)
+
+ def Function(vparam: ValDef[Untyped], body: Tree[Untyped])(implicit cpos: Position): Function =
+ Function(vparam :: Nil, body)
+
// ----- Generic Tree Instances, inherited from `tpt` and `untpd`.
- abstract class Instance[T] {
+ abstract class Instance[T >: Untyped] {
type Modifiers = Trees.Modifiers[T]
type Tree = Trees.Tree[T]
@@ -625,11 +666,14 @@ object Trees {
case nil => base
}
- implicit class TreeCopier[T](val tree: Tree[T]) extends AnyVal {
+ implicit class TreeCopier[T >: Untyped](val tree: Tree[T]) extends AnyVal {
implicit def cpos = tree.pos
def derivedIdent(name: Name): Ident[T] = tree match {
+ case tree: BackquotedIdent[_] =>
+ if (name == tree.name) tree
+ else new BackquotedIdent[T](name).copyAttr(tree)
case tree: Ident[_] if (name == tree.name) => tree
- case _ => Ident(name).copyAttr(tree)
+ case _ => Ident[T](name).copyAttr(tree)
}
def derivedSelect(qualifier: Tree[T], name: Name): Select[T] = tree match {
case tree: Select[_] if (qualifier eq tree.qualifier) && (name == tree.name) => tree
@@ -637,7 +681,7 @@ object Trees {
}
def derivedThis(qual: TypeName): This[T] = tree match {
case tree: This[_] if (qual == tree.qual) => tree
- case _ => This(qual).copyAttr(tree)
+ case _ => This[T](qual).copyAttr(tree)
}
def derivedSuper(qual: Tree[T], mix: TypeName): Super[T] = tree match {
case tree: Super[_] if (qual eq tree.qual) && (mix == tree.mix) => tree
@@ -653,7 +697,7 @@ object Trees {
}
def derivedLiteral(const: Constant): Literal[T] = tree match {
case tree: Literal[_] if (const == tree.const) => tree
- case _ => Literal(const).copyAttr(tree)
+ case _ => Literal[T](const).copyAttr(tree)
}
def derivedNew(tpt: Tree[T]): New[T] = tree match {
case tree: New[_] if (tpt eq tree.tpt) => tree
@@ -789,7 +833,7 @@ object Trees {
}
}
- abstract class FullTreeTransformer[T, C] {
+ abstract class FullTreeTransformer[T >: Untyped, C] {
var sharedMemo: Map[SharedTree[T], SharedTree[T]] = Map()
def transform(tree: Tree[T], c: C): Tree[T] = tree match {
@@ -938,7 +982,7 @@ object Trees {
def finishSharedTree(tree: Tree[T], old: Tree[T], c: C, plugins: Plugins) = tree
}
- abstract class TreeTransformer[T] {
+ abstract class TreeTransformer[T >: Untyped] {
var sharedMemo: Map[SharedTree[T], SharedTree[T]] = Map()
def transform(tree: Tree[T]): Tree[T] = tree match {
@@ -1039,11 +1083,11 @@ object Trees {
transform(trees).asInstanceOf[List[TT]]
}
- abstract class TreeAccumulator[T, U] extends ((T, Tree[U]) => T) {
- var sharedMemo: Map[SharedTree[U], T] = Map()
- def apply(x: T, tree: Tree[U]): T
- def apply(x: T, trees: List[Tree[U]]): T = (x /: trees)(apply)
- def foldOver(x: T, tree: Tree[U]): T = tree match {
+ abstract class TreeAccumulator[X, T >: Untyped] extends ((X, Tree[T]) => X) {
+ var sharedMemo: Map[SharedTree[T], X] = Map()
+ def apply(x: X, tree: Tree[T]): X
+ def apply(x: X, trees: List[Tree[T]]): X = (x /: trees)(apply)
+ def foldOver(x: X, tree: Tree[T]): X = tree match {
case Ident(name) =>
x
case Select(qualifier, name) =>
@@ -1136,15 +1180,15 @@ object Trees {
}
/** Fold `f` over all tree nodes, in depth-first, prefix order */
- class DeepFolder[T, U](f: (T, Tree[U]) => T) extends TreeAccumulator[T, U] {
- def apply(x: T, tree: Tree[U]): T = foldOver(f(x, tree), tree)
+ class DeepFolder[X, T >: Untyped](f: (X, Tree[T]) => X) extends TreeAccumulator[X, T] {
+ def apply(x: X, tree: Tree[T]): X = foldOver(f(x, tree), tree)
}
/** Fold `f` over all tree nodes, in depth-first, prefix order, but don't visit
* subtrees where `f` returns a different result for the root, i.e. `f(x, root) ne x`.
*/
- class ShallowFolder[T, U](f: (T, Tree[U]) => T) extends TreeAccumulator[T, U] {
- def apply(x: T, tree: Tree[U]): T = {
+ class ShallowFolder[X, T >: Untyped](f: (X, Tree[T]) => X) extends TreeAccumulator[X, T] {
+ def apply(x: X, tree: Tree[T]): X = {
val x1 = f(x, tree)
if (x1.asInstanceOf[AnyRef] ne x1.asInstanceOf[AnyRef]) x1
else foldOver(x1, tree)
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 133018a96..dc61195b5 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -139,6 +139,11 @@ object Types {
final def isVolatile(implicit ctx: Context): Boolean =
ctx.isVolatile(this)
+ final def hasAnnotation(cls: ClassSymbol)(implicit ctx: Context): Boolean = this match {
+ case AnnotatedType(annot, tp) => annot.symbol == cls || tp.hasAnnotation(cls)
+ case _ => false
+ }
+
// ----- Higher-order combinators -----------------------------------
/** Returns true if there is a part of this type that satisfies predicate `p`.
@@ -1293,6 +1298,8 @@ object Types {
def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType
def apply(paramNames: List[TermName], paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType =
apply(paramNames, paramTypes)(_ => resultType)
+ def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType =
+ apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType)
def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = {
def transformResult(mt: MethodType) =
resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _)))
diff --git a/src/dotty/tools/dotc/core/UntypedTrees.scala b/src/dotty/tools/dotc/core/UntypedTrees.scala
index c882b4982..2b1d6a0d6 100644
--- a/src/dotty/tools/dotc/core/UntypedTrees.scala
+++ b/src/dotty/tools/dotc/core/UntypedTrees.scala
@@ -2,11 +2,12 @@ package dotty.tools.dotc
package core
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
-import SymDenotations._, Symbols._, StdNames._, Annotations._
+import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
object UntypedTrees {
- object untpd extends Trees.Instance[Nothing] {
+ object untpd extends Trees.Instance[Untyped] {
+
}
}
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index ee8d9de83..f817cf9b9 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -946,7 +946,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
val toName = readNameRef()
val from = Trees.Ident(fromName)
val to = Trees.Ident(toName)
- if (toName.isEmpty) from else Trees.Pair[Nothing](from, Trees.Ident(toName))
+ if (toName.isEmpty) from else Trees.Pair(from, Trees.Ident(toName))
})
Import(expr, selectors)
diff --git a/src/dotty/tools/dotc/parsing/TreeBuilder.scala b/src/dotty/tools/dotc/parsing/TreeBuilder.scala
new file mode 100644
index 000000000..2f415e6a5
--- /dev/null
+++ b/src/dotty/tools/dotc/parsing/TreeBuilder.scala
@@ -0,0 +1,548 @@
+package dotty.tools
+package dotc
+package parsing
+
+import core._
+import Flags._, Trees._, TypedTrees._, UntypedTrees._, Names._, StdNames._, NameOps._, Contexts._
+import scala.collection.mutable.ListBuffer
+import util.Positions._, Symbols._, Decorators._, Flags._, Constants._
+
+/** Methods for building trees, used in the parser. All the trees
+ * returned by this class must be untyped.
+ */
+abstract class TreeBuilder(implicit ctx: Context) {
+
+ import untpd._
+
+ def o2p(offset: Int): Position
+ def r2p(start: Int, point: Int, end: Int): Position
+
+ def scalaDot(name: Name)(implicit cpos: Position): Select =
+ Select(new TypedSplice(tpd.Ident(defn.ScalaPackageVal.termRef)), name)
+
+ def scalaAnyRefConstr(implicit cpos: Position) = scalaDot(tpnme.AnyRef)
+ def scalaAnyValConstr(implicit cpos: Position) = scalaDot(tpnme.AnyVal)
+ def scalaAnyConstr(implicit cpos: Position) = scalaDot(tpnme.Any)
+ def scalaUnitConstr(implicit cpos: Position) = scalaDot(tpnme.Unit)
+ def productConstr(implicit cpos: Position) = scalaDot(tpnme.Product)
+ def productConstrN(n: Int)(implicit cpos: Position) = scalaDot(("Product" + n).toTypeName)
+ def serializableConstr(implicit cpos: Position) = scalaDot(tpnme.Serializable)
+
+ def convertToTypeName(t: Tree) = ???
+
+ implicit val cpos = NoPosition
+
+ /** Convert all occurrences of (lower-case) variables in a pattern as follows:
+ * x becomes x @ _
+ * x: T becomes x @ (_: T)
+ */
+ private object patvarTransformer extends TreeTransformer {
+ override def transform(tree: Tree): Tree = tree match {
+ case Ident(name) if (treeInfo.isVarPattern(tree) && name != nme.WILDCARD) =>
+ Bind(
+ name, Ident(nme.WILDCARD)(tree.pos.focus)
+ )(tree.pos)
+ case Typed(id @ Ident(name), tpt) if (treeInfo.isVarPattern(id) && name != nme.WILDCARD) =>
+ Bind(
+ name,
+ Typed(
+ Ident(nme.WILDCARD)(tree.pos.focus),
+ tpt
+ )(tree.pos.withStart(tree.pos.point))
+ )(tree.pos.withPoint(id.pos.point))
+ case Apply(fn @ Apply(_, _), args) =>
+ tree.derivedApply(transform(fn), transform(args))
+ case Apply(fn, args) =>
+ tree.derivedApply(fn, transform(args))
+ case Typed(expr, tpt) =>
+ tree.derivedTyped(transform(expr), tpt)
+ case Bind(name, body) =>
+ tree.derivedBind(name, transform(body))
+ case Alternative(_) =>
+ super.transform(tree)
+ case _ =>
+ tree
+ }
+ }
+
+case class VariableInfo(name: Name, tree: Tree, pos: Position)
+
+ /** Traverse pattern and collect all variable names with their types in buffer
+ * The variables keep their positions; whereas the pattern is converted to be
+ * synthetic for all nodes that contain a variable position.
+ */
+ object getVars extends TreeAccumulator[ListBuffer[VariableInfo]] {
+
+ def namePos(tree: Tree, name: Name): Position =
+ if (name contains '$') tree.pos.focus
+ else {
+ val start = tree.pos.start
+ val end = start + name.decode.length
+ Position(start, end)
+ }
+
+ override def apply(buf: ListBuffer[VariableInfo], tree: Tree): ListBuffer[VariableInfo] = {
+ def seenName(name: Name) = buf exists (_.name == name)
+ def add(name: Name, t: Tree): ListBuffer[VariableInfo] =
+ if (seenName(name)) buf else buf += VariableInfo(name, t, namePos(tree, name))
+
+ tree match {
+ case Bind(nme.WILDCARD, _) =>
+ foldOver(buf, tree)
+ case Bind(name, Typed(tree1, tpt)) if !treeInfo.mayBeTypePat(tpt) =>
+ apply(add(name, tpt), tree1)
+ case Bind(name, tree1) =>
+ apply(add(name, TypeTree()), tree1)
+ case _ =>
+ foldOver(buf, tree)
+ }
+ }
+ }
+
+ /** Returns list of all pattern variables, possibly with their types,
+ * without duplicates
+ */
+ private def getVariables(tree: Tree): List[VariableInfo] =
+ getVars(new ListBuffer[VariableInfo], tree).toList
+
+ def byNameApplication(tpe: Tree)(implicit cpos: Position): Tree =
+ AppliedTypeTree(scalaDot(tpnme.BYNAME_PARAM_CLASS), List(tpe))
+ def repeatedApplication(tpe: Tree)(implicit cpos: Position): Tree =
+ AppliedTypeTree(scalaDot(tpnme.REPEATED_PARAM_CLASS), List(tpe))
+
+ private def makeTuple(trees: List[Tree])(implicit cpos: Position): Tree = {
+ def mkPair(t1: Tree, t2: Tree) = Pair(t1, t2)(Position(t1.pos.start, cpos.end))
+ trees reduce mkPair
+ }
+
+ def stripParens(t: Tree) = t match {
+ case Parens(ts) => makeTuple(ts)(t.pos)
+ case _ => t
+ }
+
+ def makeSelfDef(name: TermName, tpt: Tree)(implicit cpos: Position): ValDef =
+ ValDef(Modifiers(Private), name, tpt, EmptyTree())
+
+ /** If tree is a variable pattern, return Some("its name and type").
+ * Otherwise return none */
+ private def matchVarPattern(tree: Tree): Option[(Name, Tree)] = {
+ def wildType(t: Tree): Option[Tree] = t match {
+ case Ident(x) if x.toTermName == nme.WILDCARD => Some(TypeTree())
+ case Typed(Ident(x), tpt) if x.toTermName == nme.WILDCARD => Some(tpt)
+ case _ => None
+ }
+ tree match {
+ case Ident(name) => Some((name, TypeTree()))
+ case Bind(name, body) => wildType(body) map (x => (name, x))
+ case Typed(Ident(name), tpt) => Some((name, tpt))
+ case _ => None
+ }
+ }
+
+ /** Create tree representing (unencoded) binary operation expression or pattern. */
+ def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position): Tree = {
+ def mkNamed(args: List[Tree]) =
+ if (isExpr) args map {
+ case arg @ Assign(Ident(name), rhs) => NamedArg(name, rhs)(arg.pos)
+ case arg => arg
+ } else args
+ val arguments = right match {
+ case Parens(args) => mkNamed(args)
+ case _ => right :: Nil
+ }
+ if (isExpr) {
+ if (treeInfo.isLeftAssoc(op)) {
+ Apply(Select(stripParens(left), op.encode)(opPos), arguments)
+ } else {
+ val x = ctx.freshName().toTermName
+ Block(
+ List(ValDef(Modifiers(Synthetic), x, TypeTree(), stripParens(left))),
+ Apply(Select(stripParens(right), op.encode)(opPos), List(Ident(x)(left.pos))))
+ }
+ } else {
+ Apply(Ident(op.encode)(opPos), stripParens(left) :: arguments)
+ }
+ }
+
+ /** Creates a tree representing new Object { stats }.
+ * To make sure an anonymous subclass of Object is created,
+ * if there are no stats, a () is added.
+ */
+ def makeAnonymousNew(stats: List[Tree])(implicit cpos: Position): Tree = {
+ val stats1 = if (stats.isEmpty) Literal(Constant(())) :: Nil else stats
+ makeNew(Nil, EmptyValDef(), stats1)
+ }
+
+ /** tpt.<init> */
+ def SelectConstructor(tpt: Tree)(implicit cpos: Position): Tree =
+ Select(tpt, nme.CONSTRUCTOR)
+
+ def splitArgss(constr: Tree, outerArgss: List[List[Tree]]): (Tree, List[List[Tree]]) = constr match {
+ case Apply(tree, args) => splitArgss(tree, args :: outerArgss)
+ case _ => (constr, if (outerArgss.isEmpty) ListOfNil else outerArgss)
+ }
+
+ /** new tpt(argss_1)...(argss_n)
+ * @param npos the position spanning <new tpt>, without any arguments
+ */
+ def makeNew(parentConstr: Tree, npos: Position) = {
+ val (tpt, argss1) = splitArgss(parentConstr, Nil)
+ (SelectConstructor(tpt)(npos) /: argss1)(Apply(_, _))
+ }
+
+ /** Create positioned tree representing an object creation <new parents { self => stats }
+ * @param pos the position of the new, focus should be the first parent's start.
+ */
+ def makeNew(parents: List[Tree], self: ValDef, stats: List[Tree])(implicit cpos: Position): Tree = {
+ val newPos = Position(cpos.start, cpos.point)
+ val clsPos = Position(cpos.point, cpos.end)
+ if (parents.isEmpty)
+ makeNew(List(scalaAnyRefConstr(cpos.startPos)), self, stats)
+ else if (parents.tail.isEmpty && stats.isEmpty)
+ makeNew(parents.head, newPos)
+ else {
+ val x = tpnme.ANON_CLASS
+ val nu = makeNew(Ident(x)(newPos), newPos)
+ val clsDef = {
+ implicit val cpos = clsPos
+ ClassDef(Modifiers(Final), x, Nil, Template(parents, self, stats))
+ }
+ Block(clsDef, nu)
+ }
+ }
+
+ /** Create a tree representing an assignment <lhs = rhs> */
+ def makeAssign(lhs: Tree, rhs: Tree): Tree = lhs match {
+ case Apply(fn, args) =>
+ Apply(Select(fn, nme.update), args :+ rhs)
+ case _ =>
+ Assign(lhs, rhs)
+ }
+
+ /** A type tree corresponding to (possibly unary) intersection type
+ def makeIntersectionTypeTree(tps: List[Tree]): Tree =
+ if (tps.tail.isEmpty) tps.head
+ else CompoundTypeTree(Template(tps, emptyValDef, Nil))*/
+
+ private def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree)(implicit cpos: Position) = {
+ val ldef = DefDef(Modifiers(Label), lname, Nil, ListOfNil, TypeTree(), rhs)
+ Block(ldef, call)
+ }
+
+ private def labelCall(lname: TermName)(implicit cpos: Position): Apply =
+ Apply(Ident(lname), Nil)
+
+ /** Create tree representing a while loop */
+ def makeWhile(lname: TermName, cond: Tree, body: Tree)(implicit cpos: Position): Tree = {
+ val continu = labelCall(lname)((cond.pos union body.pos).endPos)
+ val rhs = {
+ implicit val cpos = NoPosition
+ If(cond, Block(body, continu), Literal(Constant())(continu.pos))
+ }
+ labelDefAndCall(lname, rhs, continu)
+ }
+
+ /** Create tree representing a do-while loop */
+ def makeDoWhile(lname: TermName, body: Tree, cond: Tree)(implicit cpos: Position): Tree = {
+ val continu = labelCall(lname)((cond.pos union body.pos).endPos)
+ val rhs = Block(body, If(cond, continu, Literal(Constant())(continu.pos)))
+ labelDefAndCall(lname, rhs, continu)
+ }
+
+ /** Create block of statements `stats` */
+ def makeBlock(stats: List[Tree])(implicit cpos: Position): Tree =
+ if (stats.isEmpty) Literal(Constant())
+ else if (!stats.last.isTerm) Block(stats, Literal(Constant())(cpos.endPos))
+ else if (stats.length == 1) stats.head
+ else Block(stats.init, stats.last)
+
+ def makeFilter(tree: Tree, condition: Tree, canDrop: Boolean): Tree = {
+ val cases = List(
+ CaseDef(condition, EmptyTree(), Literal(Constant(true))),
+ CaseDef(Ident(nme.WILDCARD), EmptyTree(), Literal(Constant(false)))
+ )
+ val matchTree = makeVisitor(cases, checkExhaustive = false, canDrop)
+ locally {
+ implicit val cpos = tree.pos
+ Apply(Select(tree, nme.withFilter), matchTree :: Nil)
+ }
+ }
+
+ /** Create tree for for-comprehension generator <pat <- rhs> or <pat = rhs> */
+ def makeGenerator(pat: Tree, valeq: Boolean, rhs: Tree)(implicit cpos: Position): Enumerator = {
+ val pat1 = patvarTransformer.transform(pat)
+ if (valeq) ValEq(pat1, rhs)(cpos)
+ else ValFrom(pat1, makeFilter(rhs, pat1, canDrop = true))(cpos)
+ }
+
+ def makeParam(pname: TermName, tpe: Tree)(implicit cpos: Position) =
+ ValDef(Modifiers(Param), pname, tpe, EmptyTree())
+
+ def makeSyntheticParam(pname: TermName)(implicit cpos: Position) =
+ ValDef(Modifiers(SyntheticTermParam), pname, TypeTree(), EmptyTree())
+/*
+ def makeSyntheticTypeParam(pname: TypeName, bounds: Tree) =
+ TypeDef(Modifiers(DEFERRED | SYNTHETIC), pname, Nil, bounds)
+*/
+ abstract class Enumerator { def pos: Position }
+ case class ValFrom(pat: Tree, rhs: Tree)(implicit cpos: Position) extends Enumerator {
+ val pos = cpos union pat.pos union rhs.pos
+ }
+ case class ValEq(pat: Tree, rhs: Tree)(implicit cpos: Position) extends Enumerator {
+ val pos = cpos union pat.pos union rhs.pos
+ }
+ case class Filter(test: Tree)(implicit cpos: Position) extends Enumerator {
+ val pos = cpos union test.pos
+ }
+
+ /** Create tree for for-comprehension <for (enums) do body> or
+ * <for (enums) yield body> where mapName and flatMapName are chosen
+ * corresponding to whether this is a for-do or a for-yield.
+ * The creation performs the following rewrite rules:
+ *
+ * 1.
+ *
+ * for (P <- G) E ==> G.foreach (P => E)
+ *
+ * Here and in the following (P => E) is interpreted as the function (P => E)
+ * if P is a variable pattern and as the partial function { case P => E } otherwise.
+ *
+ * 2.
+ *
+ * for (P <- G) yield E ==> G.map (P => E)
+ *
+ * 3.
+ *
+ * for (P_1 <- G_1; P_2 <- G_2; ...) ...
+ * ==>
+ * G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
+ *
+ * 4.
+ *
+ * for (P <- G; E; ...) ...
+ * =>
+ * for (P <- G.filter (P => E); ...) ...
+ *
+ * 5. For any N:
+ *
+ * for (P_1 <- G; P_2 = E_2; val P_N = E_N; ...)
+ * ==>
+ * for (TupleN(P_1, P_2, ... P_N) <-
+ * for (x_1 @ P_1 <- G) yield {
+ * val x_2 @ P_2 = E_2
+ * ...
+ * val x_N & P_N = E_N
+ * TupleN(x_1, ..., x_N)
+ * } ...)
+ *
+ * If any of the P_i are variable patterns, the corresponding `x_i @ P_i' is not generated
+ * and the variable constituting P_i is used instead of x_i
+ *
+ * @param mapName The name to be used for maps (either map or foreach)
+ * @param flatMapName The name to be used for flatMaps (either flatMap or foreach)
+ * @param enums The enumerators in the for expression
+ * @param body The body of the for expression
+ */
+ private def makeFor(mapName: TermName, flatMapName: TermName, enums: List[Enumerator], body: Tree): Tree = {
+
+ /** make a closure pat => body.
+ * The closure is assigned a transparent position with the point at pos.point and
+ * the limits given by pat and body.
+ */
+ def makeClosure(pat: Tree, body: Tree)(implicit cpos: Position): Tree =
+ matchVarPattern(pat) match {
+ case Some((name, tpt)) =>
+ Function(ValDef(Modifiers(Param), name.toTermName, tpt, EmptyTree())(pat.pos), body)
+ case None =>
+ makeVisitor(List(CaseDef(pat, EmptyTree(), body)), checkExhaustive = false)
+ }
+
+ /** Make an application qual.meth(pat => body) positioned at `pos`.
+ */
+ def makeCombination(meth: TermName, qual: Tree, pat: Tree, body: Tree)(implicit cpos: Position): Tree =
+ Apply(Select(qual, meth)(NoPosition), makeClosure(pat, body))
+
+ /** Optionally, if pattern is a `Bind`, the bound name, otherwise None.
+ */
+ def patternVar(pat: Tree): Option[Name] = pat match {
+ case Bind(name, _) => Some(name)
+ case _ => None
+ }
+
+ /** If `pat` is not yet a `Bind` wrap it in one with a fresh name
+ */
+ def makeBind(pat: Tree): Tree = pat match {
+ case Bind(_, _) => pat
+ case _ => Bind(ctx.freshName().toTermName, pat)
+ }
+
+ /** A reference to the name bound in Bind `pat`.
+ */
+ def makeValue(pat: Tree): Tree = pat match {
+ case Bind(name, _) => Ident(name)(pat.pos.focus)
+ }
+
+ enums match {
+ case (enum @ ValFrom(pat, rhs)) :: Nil =>
+ makeCombination(mapName, rhs, pat, body)(enum.pos)
+ case ValFrom(pat, rhs) :: (rest @ (ValFrom( _, _) :: _)) =>
+ makeCombination(flatMapName, rhs, pat,
+ makeFor(mapName, flatMapName, rest, body))
+ case (enum @ ValFrom(pat, rhs)) :: Filter(test) :: rest =>
+ makeFor(mapName, flatMapName,
+ ValFrom(pat, makeCombination(nme.withFilter, rhs, pat, test))(enum.pos) :: rest,
+ body)
+ case (enum @ ValFrom(pat, rhs)) :: rest =>
+ val (valeqs, rest1) = rest.span(_.isInstanceOf[ValEq])
+ assert(!valeqs.isEmpty)
+ val pats = valeqs map { case ValEq(pat, _) => pat }
+ val rhss = valeqs map { case ValEq(_, rhs) => rhs }
+ val defpat1 = makeBind(pat)
+ val defpats = pats map makeBind
+ val pdefs = (defpats, rhss).zipped flatMap makePatDef
+ val ids = (defpat1 :: defpats) map makeValue
+ val rhs1 = makeForYield(ValFrom(defpat1, rhs) :: Nil, Block(pdefs, makeTuple(ids)))
+ val allpats = pat :: pats
+ val vfrom1 = ValFrom(makeTuple(allpats), rhs1)(enum.pos)
+ makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
+ case _ =>
+ EmptyTree() //may happen for erroneous input
+ }
+ }
+
+ /** Create tree for for-do comprehension <for (enums) body> */
+ def makeFor(enums: List[Enumerator], body: Tree): Tree =
+ makeFor(nme.foreach, nme.foreach, enums, body)
+
+ /** Create tree for for-yield comprehension <for (enums) yield body> */
+ def makeForYield(enums: List[Enumerator], body: Tree): Tree =
+ makeFor(nme.map, nme.flatMap, enums, body)
+
+ /** Create tree for a pattern alternative */
+ def makeAlternative(ts: List[Tree]): Tree = {
+ def alternatives(t: Tree): List[Tree] = t match {
+ case Alternative(ts) => ts
+ case _ => List(t)
+ }
+ Alternative(ts flatMap alternatives)
+ }
+
+ def mkAnnotated(cls: Symbol, tree: Tree) =
+ Annotated(TypedSplice(tpd.New(cls.typeConstructor)), tree)
+
+ /** Create visitor <x => x match cases> */
+ def makeVisitor(cases: List[CaseDef], checkExhaustive: Boolean, canDrop: Boolean = false): Tree = {
+ val x = ctx.freshName().toTermName
+ val id = Ident(x)
+ val sel =
+ if (canDrop) mkAnnotated(defn.DropIfRedundantAnnot, id)
+ else if (!checkExhaustive) mkAnnotated(defn.UncheckedAnnot, id)
+ else id
+ Function(List(makeSyntheticParam(x)), Match(sel, cases))
+ }
+
+ /** Create tree for case definition <case pat if guard => rhs> */
+ def makeCaseDef(pat: Tree, guard: Tree, rhs: Tree): CaseDef =
+ CaseDef(patvarTransformer.transform(pat), guard, rhs)
+
+ /** Creates tree representing:
+ * { case x: Throwable =>
+ * val catchFn = catchExpr
+ * if (catchFn isDefinedAt x) catchFn(x) else throw x
+ * }
+ */
+ def makeCatchFromExpr(catchExpr: Tree): CaseDef = {
+ implicit val cpos = catchExpr.pos.startPos
+ val binder = ctx.freshName("x").toTermName
+ val pat = Bind(binder, Typed(Ident(nme.WILDCARD), Ident(tpnme.Throwable)))
+ val catchDef = ValDef(Modifiers(), ctx.freshName("catchExpr").toTermName, TypeTree(), catchExpr)
+ val catchFn = Ident(catchDef.name)
+ val cond = Apply(Select(catchFn, nme.isDefinedAt), Ident(binder))
+ val app = Apply(Select(catchFn, nme.apply), List(Ident(binder)))
+ val thro = Throw(Ident(binder))
+ val body = Block(catchDef, If(cond, app, thro))
+ makeCaseDef(pat, EmptyTree(), body)
+ }
+
+ /** Create tree for pattern definition <val pat0 = rhs> */
+ def makePatDef(pat: Tree, rhs: Tree): List[Tree] =
+ makePatDef(Modifiers(), pat, rhs)
+
+ /** Create tree for pattern definition <mods val pat0 = rhs> */
+ def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree, varsArePatterns: Boolean = false): List[Tree] = matchVarPattern(pat) match {
+ case Some((name, tpt)) if varsArePatterns =>
+ ValDef(mods, name.toTermName, tpt, rhs) :: Nil
+
+ case _ =>
+ // in case there is exactly one variable x_1 in pattern
+ // val/var p = e ==> val/var x_1 = e.match (case p => (x_1))
+ //
+ // in case there are zero or more than one variables in pattern
+ // val/var p = e ==> private synthetic val t$ = e.match (case p => (x_1, ..., x_N))
+ // val/var x_1 = t$._1
+ // ...
+ // val/var x_N = t$._N
+
+ val rhsUnchecked = mkAnnotated(defn.UncheckedAnnot, rhs)
+
+ // TODO: clean this up -- there is too much information packed into makePatDef's `pat` argument
+ // when it's a simple identifier (case Some((name, tpt)) -- above),
+ // pat should have the type ascription that was specified by the user
+ // however, in `case None` (here), we must be careful not to generate illegal pattern trees (such as `(a, b): Tuple2[Int, String]`)
+ // i.e., this must hold: pat1 match { case Typed(expr, tp) => assert(expr.isInstanceOf[Ident]) case _ => }
+ // if we encounter such an erroneous pattern, we strip off the type ascription from pat and propagate the type information to rhs
+ val (pat1, rhs1) = patvarTransformer.transform(pat) match {
+ // move the Typed ascription to the rhs
+ case Typed(expr, tpt) if !expr.isInstanceOf[Ident] =>
+ val rhsTypedUnchecked =
+ if (tpt.isEmpty) rhsUnchecked else Typed(rhsUnchecked, tpt)
+ (expr, rhsTypedUnchecked)
+ case ok =>
+ (ok, rhsUnchecked)
+ }
+ val vars = getVariables(pat1)
+ val ids = vars map (v => Ident(v.name)(v.pos))
+ val caseDef = CaseDef(pat1, EmptyTree(), makeTuple(ids))
+ val matchExpr = Match(rhs1, caseDef :: Nil)
+ vars match {
+ case List(VariableInfo(vname, tpt, pos)) =>
+ ValDef(mods, vname.toTermName, tpt, matchExpr) :: Nil
+ case _ =>
+ val tmpName = ctx.freshName().toTermName
+ val patMods = Modifiers(PrivateLocal | Synthetic | (mods.flags & Lazy))
+ val firstDef = ValDef(patMods, tmpName, TypeTree(), matchExpr)
+ val restDefs = for {
+ (VariableInfo(vname, tpt, pos), n) <- vars.zipWithIndex
+ } yield {
+ val rhs = {
+ implicit val cpos = pos.focus
+ Select(Ident(tmpName), ("_" + n).toTermName)
+ }
+ ValDef(mods, vname.toTermName, tpt, rhs)(pos)
+ }
+ firstDef :: restDefs
+ }
+ }
+
+ /** Create a tree representing the function type (argtpes) => restpe */
+ def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree =
+ AppliedTypeTree(scalaDot(("Function" + argtpes.length).toTypeName), argtpes ::: List(restpe))
+
+ /** Append implicit parameter section if `contextBounds` nonempty */
+ def addEvidenceParams(owner: Name, vparamss: List[List[ValDef]], contextBounds: List[Tree]): List[List[ValDef]] = {
+ if (contextBounds.isEmpty) vparamss
+ else {
+ val mods = Modifiers(if (owner.isTypeName) PrivateLocal | ParamAccessor else Param)
+ val evidenceParams = for (tpt <- contextBounds) yield {
+ val pname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX.toString).toTermName
+ ValDef(mods | Implicit | Synthetic, pname, tpt, EmptyTree())
+ }
+ vparamss.reverse match {
+ case (vparams @ (vparam :: _)) :: _ if vparam.mods is Implicit =>
+ vparamss.init :+ (evidenceParams ++ vparams)
+ case _ =>
+ vparamss :+ evidenceParams
+ }
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index 3e7eaecde..86dfb96d8 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -30,13 +30,16 @@ trait Reporting { this: Context =>
" in " + (currentTimeMillis - start) + "ms"
def informProgress(msg: => String) =
- if (ctx.settings.verbose.value) inform("[" + msg + "]")
+ if (this.settings.verbose.value) inform("[" + msg + "]")
def trace[T](msg: => String)(value: T) = {
log(msg + " " + value)
value
}
+ def debugwarn(msg: String, pos: SourcePosition = NoSourcePosition): Unit =
+ if (this.settings.debug.value) warning(msg, pos)
+
def debugTraceIndented[T](question: => String)(op: => T): T =
if (this.settings.debugTrace.value) traceIndented(question)(op)
else op
diff --git a/src/dotty/tools/dotc/util/Positions.scala b/src/dotty/tools/dotc/util/Positions.scala
index 31eb2ff0d..bf7bc7414 100644
--- a/src/dotty/tools/dotc/util/Positions.scala
+++ b/src/dotty/tools/dotc/util/Positions.scala
@@ -40,6 +40,8 @@ object Positions {
else this
def focus = Position(point)
+ def startPos = Position(start)
+ def endPos = Position(end)
def withStart(start: Int) = Position(start, this.end, this.point - start)
def withEnd(end: Int) = Position(this.start, end, this.point - this.start)