From 60b3469ac70052b762cc7bf0d36bf2ec37e8e6dc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 27 Jul 2013 19:48:30 +0200 Subject: Redesign of trees. 1) Trees are now contravariant. 2) All creation ops, transformers, copiers are pushed into Instance. 3) Still to do: integrate TreeMappers and tpd.TreeTransformers. --- src/dotty/tools/dotc/ast/CheckTrees.scala | 14 +- src/dotty/tools/dotc/ast/Desugar.scala | 53 +- src/dotty/tools/dotc/ast/TreeInfo.scala | 356 +++--- src/dotty/tools/dotc/ast/Trees.scala | 1232 +++++++++++--------- src/dotty/tools/dotc/ast/TypedTrees.scala | 225 ++-- src/dotty/tools/dotc/ast/UntypedTrees.scala | 152 +-- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 12 +- src/dotty/tools/dotc/parsing/MarkupParsers.scala | 1 - src/dotty/tools/dotc/parsing/Parsers.scala | 44 +- src/dotty/tools/dotc/printing/RefinedPrinter.scala | 2 +- src/dotty/tools/dotc/typer/Applications.scala | 65 +- src/dotty/tools/dotc/typer/EtaExpansion.scala | 8 +- src/dotty/tools/dotc/typer/Namer.scala | 6 +- src/dotty/tools/dotc/typer/Typer.scala | 39 +- test/test/ContravariantTrees.scala | 65 ++ test/test/DeSugarTest.scala | 36 +- test/test/DottyTest.scala | 1 - test/test/parsePackage.scala | 5 +- 18 files changed, 1244 insertions(+), 1072 deletions(-) create mode 100644 test/test/ContravariantTrees.scala diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala index 502b2eea3..a004789e6 100644 --- a/src/dotty/tools/dotc/ast/CheckTrees.scala +++ b/src/dotty/tools/dotc/ast/CheckTrees.scala @@ -8,16 +8,16 @@ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ object CheckTrees { - import tpd.{TreeMapper, localSyms, TreeOps} + import tpd._ def check(p: Boolean, msg: => String = "")(implicit ctx: Context): Unit = assert(p, msg) - def checkTypeArg(arg: tpd.Tree, bounds: TypeBounds)(implicit ctx: Context): Unit = { + def checkTypeArg(arg: Tree, bounds: TypeBounds)(implicit ctx: Context): Unit = { check(arg.isValueType) check(bounds contains arg.tpe) } - def checkType(tree: tpd.Tree)(implicit ctx: Context): Unit = tree match { + def checkType(tree: Tree)(implicit ctx: Context): Unit = tree match { case Ident(name) => case Select(qualifier, name) => check(qualifier.isValue) @@ -31,7 +31,7 @@ object CheckTrees { val cls = qual.tpe.typeSymbol check(cls.isClass) case Apply(fn, args) => - def checkArg(arg: tpd.Tree, name: Name, formal: Type): Unit = { + def checkArg(arg: Tree, name: Name, formal: Type): Unit = { arg match { case NamedArg(argName, _) => check(argName == name) @@ -147,7 +147,7 @@ object CheckTrees { check(left.isValueType); check(right.isValueType) case RefinedTypeTree(tpt, refinements) => check(tpt.isValueType) - def checkRefinements(forbidden: Set[Symbol], rs: List[tpd.Tree]): Unit = rs match { + def checkRefinements(forbidden: Set[Symbol], rs: List[Tree]): Unit = rs match { case r :: rs1 => val rsym = r.symbol check(rsym.isTerm || rsym.isAbstractOrAliasType) @@ -185,7 +185,7 @@ object CheckTrees { case nme.unapplySeq => // args need to be wrapped in (...: _*) check(args.length == 1) - check(args.head.isInstanceOf[tpd.SeqLiteral]) + check(args.head.isInstanceOf[SeqLiteral]) case nme.unapply => val rtp = funtpe.resultType val rsym = rtp.dealias.typeSymbol @@ -221,7 +221,7 @@ object CheckTrees { check(rhs.tpe <:< tpt.tpe) } case TypeDef(mods, name, tpt) => - check(tpt.isInstanceOf[Template[_]] || tpt.tpe.isInstanceOf[TypeBounds]) + check(tpt.isInstanceOf[Template] || tpt.tpe.isInstanceOf[TypeBounds]) case Template(constr, parents, selfType, body) => case Import(expr, selectors) => check(expr.isValue) diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 0a0638fa1..9f91d3143 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -5,7 +5,6 @@ package ast import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ -import TreeInfo._ import Decorators._ import language.higherKinds import collection.mutable.ListBuffer @@ -22,19 +21,19 @@ object desugar { if (!ctx.owner.isClass || (mods is Private)) vdef else { val lname = name.toLocalName - val field = vdef.derivedValDef(mods, lname, tpt, rhs) - val getter = vdef.derivedDefDef(mods, name, Nil, Nil, tpt, Ident(lname)) + val field = cpy.ValDef(vdef, mods, lname, tpt, rhs) + val getter = cpy.DefDef(vdef, mods, name, Nil, Nil, tpt, Ident(lname)) if (!(mods is Mutable)) Thicket(field, getter) else { val setterParam = makeSyntheticParameter(tpt = TypeTree(field)) - val setter = vdef.derivedDefDef( + val setter = cpy.DefDef(vdef, mods, name.getterToSetter, Nil, (setterParam :: Nil) :: Nil, EmptyTree, refOfDef(setterParam)) Thicket(field, getter, setter) } } } - def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false): Tree = { + def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = { val DefDef(mods, name, tparams, vparamss, tpt, rhs) = meth val epbuf = new ListBuffer[ValDef] val tparams1 = tparams mapConserve { @@ -45,7 +44,7 @@ object desugar { epbuf += ValDef(Modifiers(paramFlags | Implicit), epname, cxbound, EmptyTree) } - tparam.derivedTypeDef(mods, name, tbounds, tparam.tparams) + cpy.TypeDef(tparam, mods, name, tbounds, tparam.tparams) case tparam => tparam } @@ -60,7 +59,7 @@ object desugar { case _ => vparamss :+ evidenceParams } - meth.derivedDefDef(mods, name, tparams1, vparamss1, tpt, rhs) + cpy.DefDef(meth, mods, name, tparams1, vparamss1, tpt, rhs) } def take(vparamss: List[List[ValDef]], n: Int): List[List[ValDef]] = vparamss match { @@ -94,8 +93,8 @@ object desugar { else { val mods1 = meth1.mods | DefaultParameterized val vparamss1 = vparamss map (_ map (vparam => - vparam.derivedValDef(vparam.mods, vparam.name, vparam.tpt, EmptyTree))) - val meth2 = meth1.derivedDefDef(mods1, meth1.name, meth1.tparams, vparamss1, meth1.tpt, meth1.rhs) + cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt, EmptyTree))) + val meth2 = cpy.DefDef(meth1, mods1, meth1.name, meth1.tparams, vparamss1, meth1.tpt, meth1.rhs) Thicket(meth2 :: defGetters) } } @@ -103,9 +102,9 @@ object desugar { def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = { val TypeDef(mods, name, rhs) = tdef if (mods is PrivateLocalParamAccessor) { - val tparam = tdef.derivedTypeDef( + val tparam = cpy.TypeDef(tdef, tdef.mods &~ PrivateLocal | ExpandedName, tdef.name.expandedName(ctx.owner), tdef.rhs, tdef.tparams) - val alias = tdef.derivedTypeDef( + val alias = cpy.TypeDef(tdef, Modifiers(PrivateLocal | Synthetic), tdef.name, refOfDef(tparam)) Thicket(tparam, alias) } @@ -123,7 +122,7 @@ object desugar { case Thicket((meth: DefDef) :: defaults) => (meth, defaults) } - val tparams = constr1.tparams.map(tparam => tparam.derivedTypeDef( + val tparams = constr1.tparams.map(tparam => cpy.TypeDef(tparam, Modifiers(Param), tparam.name, tparam.rhs, tparam.tparams)) // ensure parameter list is non-empty @@ -133,10 +132,10 @@ object desugar { ctx.error("case class needs to have at least one parameter list", cdef.pos) ListOfNil } else - constr1.vparamss.nestedMap(vparam => vparam.derivedValDef( + constr1.vparamss.nestedMap(vparam => cpy.ValDef(vparam, Modifiers(Param), vparam.name, vparam.tpt, vparam.rhs)) - val constr = constr1.derivedDefDef( + val constr = cpy.DefDef(constr1, constr1.mods, constr1.name, tparams, vparamss, constr1.tpt, constr1.rhs) val classTypeRef = { @@ -160,9 +159,9 @@ object desugar { if (mods is Abstract) Nil else { val copyFirstParams = vparamss.head.map(vparam => - vparam.derivedValDef(vparam.mods, vparam.name, vparam.tpt, refOfDef(vparam))) + cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt, refOfDef(vparam))) val copyRestParamss = vparamss.tail.nestedMap(vparam => - vparam.derivedValDef(vparam.mods, vparam.name, vparam.tpt, EmptyTree)) + cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt, EmptyTree)) DefDef(synthetic, nme.copy, tparams, copyFirstParams :: copyRestParamss, EmptyTree, creatorExpr) :: Nil } copyMeths ::: isDefinedMeth :: productArityMeth :: productElemMeths.toList @@ -176,7 +175,7 @@ object desugar { moduleDef( ModuleDef( Modifiers(Synthetic), name.toTermName, - Template(emptyConstructor, parentConstr :: Nil, EmptyValDef(), defs))).toList + Template(emptyConstructor, parentConstr :: Nil, EmptyValDef, defs))).toList } val companions = @@ -209,10 +208,10 @@ object desugar { } else Nil - val cdef1 = cdef.derivedTypeDef(mods, name, - impl.derivedTemplate(constr, parents, self, + val cdef1 = cpy.TypeDef(cdef, mods, name, + cpy.Template(impl, constr, parents, self, constr1.tparams ::: constr1.vparamss.flatten ::: body ::: caseClassMeths)) - Thicket.make(cdef1 :: companions ::: implicitWrappers) + flatTree(cdef1 :: companions ::: implicitWrappers) } /** Expand to: @@ -224,8 +223,8 @@ object desugar { val clsName = name.moduleClassName val clsRef = Ident(clsName) val modul = ValDef(mods | ModuleCreationFlags, name, clsRef, New(clsRef, Nil)) - val clsSelf = self.derivedValDef(self.mods, self.name, SingletonTypeTree(Ident(name)), self.rhs) - val clsTmpl = tmpl.derivedTemplate(constr, parents, clsSelf, body) + val clsSelf = cpy.ValDef(self, self.mods, self.name, SingletonTypeTree(Ident(name)), self.rhs) + val clsTmpl = cpy.Template(tmpl, constr, parents, clsSelf, body) val cls = TypeDef(mods.toTypeFlags & AccessFlags | ModuleClassCreationFlags, clsName, clsTmpl) Thicket(cls, valDef(modul)) } @@ -251,7 +250,7 @@ object desugar { */ def makeBinop(left: Tree, op: Name, right: Tree): Tree = { def assignToNamedArg(arg: Tree) = arg match { - case Assign(Ident(name), rhs) => arg.derivedNamedArg(name, rhs) + case Assign(Ident(name), rhs) => cpy.NamedArg(arg, name, rhs) case _ => arg } if (isLeftAssoc(op)) { @@ -456,7 +455,7 @@ object desugar { val restDefs = for (((named, tpt), n) <- vars.zipWithIndex) yield derivedValDef(mods, named, tpt, selector(n)) - Thicket.make(firstDef :: restDefs) + flatTree(firstDef :: restDefs) } } @@ -536,7 +535,7 @@ object desugar { makeFor(nme.map, nme.flatMap, enums, body) orElse tree case PatDef(mods, pats, tpt, rhs) => val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt)) - Thicket.make(pats1 map (makePatDef(mods, _, rhs))) + flatTree(pats1 map (makePatDef(mods, _, rhs))) case _ => tree } @@ -549,7 +548,7 @@ object desugar { /** If tree is a variable pattern, return its name and type, otherwise return None. */ private object VarPattern { - def unapply(tree: Tree): Option[VarInfo] = tree match { + def unapply(tree: Tree)(implicit ctx: Context): Option[VarInfo] = tree match { case id: Ident => Some(id, TypeTree()) case Typed(id: Ident, tpt) => Some((id, tpt)) case _ => None @@ -560,7 +559,7 @@ object desugar { * Works for expanded as well as unexpanded patterns * */ - private object getVars extends TreeAccumulator[ListBuffer[VarInfo]] { + private object getVars extends UntypedTreeAccumulator[ListBuffer[VarInfo]] { override def apply(buf: ListBuffer[VarInfo], tree: Tree): ListBuffer[VarInfo] = { def seenName(name: Name) = buf exists (_._1.name == name) def add(named: NameTree, t: Tree): ListBuffer[VarInfo] = diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index cde8c10b0..de00cee7e 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -7,14 +7,9 @@ import Flags._, Trees._, 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 { +trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => + + def isDeclarationOrTypeDef(tree: Tree): Boolean = tree match { case DefDef(_, _, _, _, _, EmptyTree) | ValDef(_, _, _, EmptyTree) | TypeDef(_, _, _) => true @@ -23,7 +18,7 @@ abstract class TreeInfo { /** Is tree legal as a member definition of an interface? */ - def isInterfaceMember(tree: Tree[_ >: Untyped]): Boolean = tree match { + def isInterfaceMember(tree: Tree): Boolean = tree match { case EmptyTree => true case Import(_, _) => true case TypeDef(_, _, _) => true @@ -32,71 +27,14 @@ abstract class TreeInfo { 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 - | TypeDef(_, _, _) - | Import(_, _) - | DefDef(_, _, _, _, _, _) => - true - case ValDef(mods, _, _, rhs) => - !(mods is Mutable) && isIdempotentExpr(rhs) - case _ => - false - } - - def isOpAssign(tree: untpd.Tree) = tree match { + def isOpAssign(tree: Tree) = tree match { case Apply(Select(_, name), _ :: Nil) if name.isOpAssignmentName => true 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 { + class MatchingArgs(params: List[Symbol], args: List[Tree])(implicit ctx: Context) { + def foreach(f: (Symbol, Tree) => Unit): Boolean = { + def recur(params: List[Symbol], args: List[Tree]): Boolean = params match { case Nil => args.isEmpty case param :: params1 => if (param.info.isRepeatedParam) { @@ -111,8 +49,8 @@ abstract class TreeInfo { } recur(params, args) } - def zipped: List[(Symbol, Tree[T])] = map((_, _)) - def map[R](f: (Symbol, Tree[T]) => R): List[R] = { + def zipped: List[(Symbol, Tree)] = map((_, _)) + def map[R](f: (Symbol, Tree) => R): List[R] = { val b = List.newBuilder[R] foreach(b += f(_, _)) b.result @@ -129,7 +67,7 @@ abstract class TreeInfo { * (x$2, x$1) * } */ - def methPart[T >: Untyped](tree: Tree[T]): Tree[T] = tree match { + def methPart(tree: Tree): Tree = tree match { case Apply(fn, _) => methPart(fn) case TypeApply(fn, _) => methPart(fn) case AppliedTypeTree(fn, _) => methPart(fn) @@ -138,7 +76,7 @@ abstract class TreeInfo { } /** The number of arguments in an application */ - def numArgs[T >: Untyped](tree: Tree[T]): Int = tree match { + def numArgs(tree: Tree): Int = tree match { case Apply(fn, args) => numArgs(fn) + args.length case TypeApply(fn, args) => numArgs(fn) + args.length case AppliedTypeTree(fn, args) => numArgs(fn) + args.length @@ -146,120 +84,75 @@ abstract class TreeInfo { case _ => 0 } - /** 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 { + def isSelfConstrCall(tree: Tree): 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 { + def isSuperConstrCall(tree: Tree): Boolean = methPart(tree) match { case Select(Super(_, _), nme.CONSTRUCTOR) => true case _ => false } - def isSelfOrSuperConstrCall(tree: Tree[_ >: Untyped]): Boolean = methPart(tree) match { + def isSelfOrSuperConstrCall(tree: Tree): 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 + def isVarPattern(pat: Tree): 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 + def firstConstructor(stats: List[Tree]): Tree = stats match { + case (meth: DefDef) :: _ if meth.name.isConstructorName => meth case stat :: stats => firstConstructor(stats) - case nil => emptyTree() + 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 { + def firstConstructorArgs(stats: List[Tree]): List[Tree] = 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 preSuperFields(stats: List[Tree]): List[ValDef] = + (stats filter isEarlyValDef).asInstanceOf[List[ValDef]] - def isEarlyDef(tree: Tree[_ >: Untyped]) = isEarlyValDef(tree) || isEarlyTypeDef(tree) + def isEarlyDef(tree: Tree) = isEarlyValDef(tree) || isEarlyTypeDef(tree) - def isEarlyValDef(tree: Tree[_ >: Untyped]) = tree match { + def isEarlyValDef(tree: Tree) = tree match { case ValDef(mods, _, _, _) => mods is Scala2PreSuper case _ => false } - def isEarlyTypeDef(tree: Tree[_ >: Untyped]) = tree match { + def isEarlyTypeDef(tree: Tree) = 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[_] => tpt.typeOpt.isRepeatedParam + def isRepeatedParamType(tpt: Tree)(implicit ctx: Context) = tpt match { + case tpt: TypeTree => tpt.typeOpt.isRepeatedParam 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 + def isByNameParamType(tpt: Tree)(implicit ctx: Context) = tpt match { + case tpt: TypeTree => tpt.typeOpt.typeSymbol == defn.ByNameParamClass case AppliedTypeTree(Select(_, tpnme.BYNAME_PARAM_CLASS), _) => true case _ => false } @@ -267,22 +160,12 @@ abstract class TreeInfo { /** 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 { + def mayBeTypePat(tree: untpd.Tree): Boolean = tree match { case AndTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2) case OrTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2) - case RefinedTypeTree(tpt, refinements) => mayBeTypePat(tpt) || refinements.exists(_.isInstanceOf[Bind[_]]) - case AppliedTypeTree(tpt, args) => mayBeTypePat(tpt) || args.exists(_.isInstanceOf[Bind[_]]) + case RefinedTypeTree(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 @@ -290,13 +173,13 @@ abstract class TreeInfo { /** Is this argument node of the form : _* ? */ - def isWildcardStarArg(tree: Tree[_ >: Untyped]): Boolean = tree match { + def isWildcardStarArg(tree: untpd.Tree): 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 { + def typeParameters(tree: Tree): List[TypeDef] = tree match { case DefDef(_, _, tparams, _, _, _) => tparams case ClassDef(_, _, tparams, _) => tparams case TypeDef(_, _, tparams, _) => tparams @@ -304,42 +187,42 @@ abstract class TreeInfo { }*/ /** Does this argument list end with an argument of the form : _* ? */ - def isWildcardStarArgList(trees: List[Tree[_ >: Untyped]]) = + def isWildcardStarArgList(trees: List[Tree]) = 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 { + def isWildcardArg(tree: Tree): 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 { + def isWildcardStarType(tree: Tree): 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 { + def isDefaultCase(cdef: CaseDef) = 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 { + def isSyntheticDefaultCase(cdef: CaseDef) = 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) = + def catchesThrowable(cdef: CaseDef)(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) = + def catchesAllOf(cdef: CaseDef, threshold: Type)(implicit ctx: Context) = isDefaultCase(cdef) || cdef.guard.isEmpty && { unbind(cdef.pat) match { @@ -348,8 +231,135 @@ abstract class TreeInfo { } } + /** Is this case guarded? */ + def isGuardedCase(cdef: CaseDef) = cdef.guard ne EmptyTree + + /** Is this pattern node a sequence-valued pattern? */ + def isSequenceValued(tree: Tree): Boolean = unbind(tree) match { + case Alternative(ts) => ts exists isSequenceValued + case SeqLiteral(_) => true + case _ => false + } + + /** The underlying pattern ignoring any bindings */ + def unbind(x: Tree): Tree = x match { + case Bind(_, y) => unbind(y) + case y => y + } +} + +trait TypedTreeInfo extends TreeInfo[Type] {self: Trees.Instance[Type] => + + /** Is tree a definition that has no side effects when + * evaluated as part of a block after the first time? + */ + def isIdempotentDef(tree: tpd.Tree)(implicit ctx: Context): Boolean = tree match { + case EmptyTree + | 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: tpd.Tree)(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 + } + + /** 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: tpd.Tree)(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 `this` node which belongs to `enclClass`? */ + def isSelf(tree: Tree, enclClass: Symbol)(implicit ctx: Context): Boolean = tree match { + case This(_) => tree.symbol == enclClass + case _ => false + } + + /** Strips layers of `.asInstanceOf[T]` / `_.$asInstanceOf[T]()` from an expression */ + def stripCast(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = { + def isCast(sel: tpd.Tree) = 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 this pattern node a catch-all or type-test pattern? */ - def isCatchCase(cdef: CaseDef[Type])(implicit ctx: Context) = cdef match { + def isCatchCase(cdef: CaseDef)(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, _) => @@ -366,21 +376,10 @@ abstract class TreeInfo { false } - /** Is this case guarded? */ - def isGuardedCase(cdef: CaseDef[_ >: Untyped]) = cdef.guard ne 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 - } + /** a Match(Typed(_, tpt), _) must be translated into a switch if isSwitchAnnotation(tpt.tpe) + def isSwitchAnnotation(tpe: Type) = tpe hasAnnotation defn.SwitchClass + */ +} /** Does list of trees start with a definition of @@ -489,5 +488,6 @@ abstract class TreeInfo { case tree: RefTree => true case _ => false })*/ -} -object TreeInfo extends TreeInfo \ No newline at end of file + + + diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 2ae474d15..5836b0863 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -12,6 +12,7 @@ import collection.mutable.ListBuffer import parsing.Tokens.Token import printing.Printer import util.Stats +import annotation.unchecked.uncheckedVariance object Trees { @@ -96,7 +97,7 @@ object Trees { * It should have as end the end of the opening keywords(s). * If there is no opening keyword, point should equal end. */ - case class Modifiers[T >: Untyped] ( + case class Modifiers[-T >: Untyped] ( flags: FlagSet = EmptyFlags, privateWithin: TypeName = tpnme.EMPTY, annotations: List[Tree[T]] = Nil) extends Positioned with Cloneable { @@ -115,7 +116,7 @@ object Trees { if (this.flags == flags) this else copy(flags = flags) - def withAnnotations(annots: List[Tree[T]]) = + def withAnnotations[U >: Untyped <: T](annots: List[Tree[U]]): Modifiers[U] = if (annots.isEmpty) this else copy(annotations = annotations ++ annots) @@ -146,19 +147,21 @@ object Trees { * - Type checking an untyped tree should remove all embedded `TypedSplice` * nodes. */ - abstract class Tree[T >: Untyped] extends Positioned with Product with printing.Showable with Cloneable { + abstract class Tree[-T >: Untyped] extends Positioned with Product with printing.Showable with Cloneable { if (Stats.enabled) ntrees += 1 /** The type constructor at the root of the tree */ type ThisTree[T >: Untyped] <: Tree[T] - private var myTpe: T = _ + private[this] var myTpe: T = _ + + private def setMyTpe(tpe: T) = myTpe = tpe /** The type of the tree. In case of an untyped tree, * an UnAssignedTypeException is thrown. (Overridden by empty trees) */ - def tpe: T = { + def tpe: T @uncheckedVariance = { if (myTpe == null) throw new UnAssignedTypeException(this) myTpe } @@ -182,7 +185,7 @@ object Trees { (if (myTpe == null || (myTpe.asInstanceOf[AnyRef] eq tpe.asInstanceOf[AnyRef])) this else clone).asInstanceOf[Tree[Type]] - tree.myTpe = tpe + tree setMyTpe tpe tree.asInstanceOf[ThisTree[Type]] } @@ -228,8 +231,8 @@ object Trees { def toList: List[Tree[T]] = this :: Nil /** if this tree is the empty tree, the alternative, else this tree */ - def orElse(that: => Tree[T]): Tree[T] = - if (this eq EmptyTree) that else this + def orElse[U >: Untyped <: T](that: => Tree[U]): Tree[U] = + if (this eq genericEmptyTree) that else this override def toText(printer: Printer) = printer.toText(this) @@ -246,30 +249,30 @@ object 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 >: Untyped] extends Tree[T] { - type ThisTree[T >: Untyped] <: 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 >: Untyped] extends Tree[T] { - type ThisTree[T >: Untyped] <: 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 >: Untyped] extends Tree[T] { - type ThisTree[T >: Untyped] <: 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 >: Untyped] extends Tree[T] { - type ThisTree[T >: Untyped] <: 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 @@ -279,8 +282,8 @@ object Trees { /** Tree's denot/isType/isTerm properties come from a subtree * identified by `forwardTo`. */ - abstract class ProxyTree[T >: Untyped] extends Tree[T] { - type ThisTree[T >: Untyped] <: 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 @@ -288,23 +291,23 @@ object Trees { } /** Tree has a name */ - abstract class NameTree[T >: Untyped] extends DenotingTree[T] { - type ThisTree[T >: Untyped] <: NameTree[T] + abstract class NameTree[-T >: Untyped] extends DenotingTree[T] { + type ThisTree[-T >: Untyped] <: NameTree[T] def name: Name - def withName(name1: Name): NameTree[T] + def withName(name1: Name)(implicit ctx: Context): untpd.NameTree } /** Tree refers by name to a denotation */ - abstract class RefTree[T >: Untyped] extends NameTree[T] { - type ThisTree[T >: Untyped] <: 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 >: Untyped] extends DenotingTree[T] { - type ThisTree[T >: Untyped] <: DefTree[T] + trait DefTree[-T >: Untyped] extends DenotingTree[T] { + type ThisTree[-T >: Untyped] <: DefTree[T] override def isDef = true } @@ -313,14 +316,14 @@ object Trees { * The envelope of a MemberDef contains the whole definition and his its point * on the opening keyword (or the next token after that if keyword is missing). */ - trait MemberDef[T >: Untyped] extends NameTree[T] with DefTree[T] { - type ThisTree[T >: Untyped] <: MemberDef[T] + trait MemberDef[-T >: Untyped] extends NameTree[T] with DefTree[T] { + type ThisTree[-T >: Untyped] <: MemberDef[T] def mods: Modifiers[T] override def envelope: Position = mods.pos union pos union initialPos } /** A ValDef or DefDef tree */ - trait ValOrDefDef[T >: Untyped] extends MemberDef[T] { + trait ValOrDefDef[-T >: Untyped] extends MemberDef[T] { def tpt: Tree[T] def rhs: Tree[T] } @@ -328,128 +331,126 @@ object Trees { // ----------- Tree case classes ------------------------------------ /** name */ - case class Ident[T >: Untyped](name: Name) + case class Ident[-T >: Untyped] private[ast] (name: Name) extends RefTree[T] { - type ThisTree[T >: Untyped] = Ident[T] - def withName(name: Name) = this.derivedIdent(name) - def qualifier: Tree[T] = emptyTree[T] + type ThisTree[-T >: Untyped] = Ident[T] + def withName(name: Name)(implicit ctx: Context): untpd.Ident = untpd.cpy.Ident(this, name) + def qualifier: Tree[T] = genericEmptyTree } - class BackquotedIdent[T >: Untyped](name: Name) + class BackquotedIdent[-T >: Untyped] private[ast] (name: Name) extends Ident[T](name) /** qualifier.name */ - case class Select[T >: Untyped](qualifier: Tree[T], name: Name) + case class Select[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name) extends RefTree[T] { - type ThisTree[T >: Untyped] = Select[T] - def withName(name: Name) = this.derivedSelect(qualifier, name) + type ThisTree[-T >: Untyped] = Select[T] + def withName(name: Name)(implicit ctx: Context): untpd.Select = untpd.cpy.Select(this, qualifier, name) } + class SelectWithSig[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name, val sig: Signature) + extends Select[T](qualifier, name) + /** qual.this */ - case class This[T >: Untyped](qual: TypeName) + case class This[-T >: Untyped] private[ast] (qual: TypeName) extends DenotingTree[T] with TermTree[T] { - type ThisTree[T >: Untyped] = This[T] + type ThisTree[-T >: Untyped] = This[T] } /** C.super[mix], where qual = C.this */ - case class Super[T >: Untyped](qual: Tree[T], mix: TypeName) + case class Super[-T >: Untyped] private[ast] (qual: Tree[T], mix: TypeName) extends ProxyTree[T] with TermTree[T] { - type ThisTree[T >: Untyped] = Super[T] + type ThisTree[-T >: Untyped] = Super[T] def forwardTo = qual } - abstract class GenericApply[T >: Untyped] extends ProxyTree[T] with TermTree[T] { - type ThisTree[T >: Untyped] <: 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 >: Untyped](fun: Tree[T], args: List[Tree[T]]) + case class Apply[-T >: Untyped] private[ast] (fun: Tree[T], args: List[Tree[T]]) extends GenericApply[T] { - type ThisTree[T >: Untyped] = Apply[T] + type ThisTree[-T >: Untyped] = Apply[T] } /** fun[args] */ - case class TypeApply[T >: Untyped](fun: Tree[T], args: List[Tree[T]]) + case class TypeApply[-T >: Untyped] private[ast] (fun: Tree[T], args: List[Tree[T]]) extends GenericApply[T] { - type ThisTree[T >: Untyped] = TypeApply[T] + type ThisTree[-T >: Untyped] = TypeApply[T] } /** const */ - case class Literal[T >: Untyped](const: Constant) + case class Literal[-T >: Untyped] private[ast] (const: Constant) extends TermTree[T] { - type ThisTree[T >: Untyped] = Literal[T] + type ThisTree[-T >: Untyped] = Literal[T] } /** new tpt, but no constructor call */ - case class New[T >: Untyped](tpt: Tree[T]) + case class New[-T >: Untyped] private[ast] (tpt: Tree[T]) extends TermTree[T] { - type ThisTree[T >: Untyped] = New[T] + type ThisTree[-T >: Untyped] = New[T] } - /** new tpt(args1)...(args_n) - */ - def New[T >: Untyped](tpt: Tree[T], argss: List[List[Tree[T]]]): Tree[T] = - ((Select(New(tpt), nme.CONSTRUCTOR): Tree[T]) /: argss)(Apply(_, _)) - /** (left, right) */ - case class Pair[T >: Untyped](left: Tree[T], right: Tree[T]) + case class Pair[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T]) extends TermTree[T] { - type ThisTree[T >: Untyped] = Pair[T] + type ThisTree[-T >: Untyped] = Pair[T] 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 >: Untyped](expr: Tree[T], tpt: Tree[T]) + case class Typed[-T >: Untyped] private[ast] (expr: Tree[T], tpt: Tree[T]) extends ProxyTree[T] with TermTree[T] { - type ThisTree[T >: Untyped] = Typed[T] + type ThisTree[-T >: Untyped] = Typed[T] def forwardTo = expr } /** name = arg, in a parameter list */ - case class NamedArg[T >: Untyped](name: Name, arg: Tree[T]) + case class NamedArg[-T >: Untyped] private[ast] (name: Name, arg: Tree[T]) extends Tree[T] { - type ThisTree[T >: Untyped] = NamedArg[T] + type ThisTree[-T >: Untyped] = NamedArg[T] } /** name = arg, outside a parameter list */ - case class Assign[T >: Untyped](lhs: Tree[T], rhs: Tree[T]) + case class Assign[-T >: Untyped] private[ast] (lhs: Tree[T], rhs: Tree[T]) extends TermTree[T] { - type ThisTree[T >: Untyped] = Assign[T] + type ThisTree[-T >: Untyped] = Assign[T] } /** { stats; expr } */ - case class Block[T >: Untyped](stats: List[Tree[T]], expr: Tree[T]) + case class Block[-T >: Untyped] private[ast] (stats: List[Tree[T]], expr: Tree[T]) extends TermTree[T] { - type ThisTree[T >: Untyped] = Block[T] + type ThisTree[-T >: Untyped] = Block[T] } /** if cond then thenp else elsep */ - case class If[T >: Untyped](cond: Tree[T], thenp: Tree[T], elsep: Tree[T]) + case class If[-T >: Untyped] private[ast] (cond: Tree[T], thenp: Tree[T], elsep: Tree[T]) extends TermTree[T] { - type ThisTree[T >: Untyped] = If[T] + type ThisTree[-T >: Untyped] = If[T] } /** A closure with an environment and a reference to a method */ - case class Closure[T >: Untyped](env: List[Tree[T]], meth: RefTree[T]) + case class Closure[-T >: Untyped] private[ast] (env: List[Tree[T]], meth: RefTree[T]) extends TermTree[T] { - type ThisTree[T >: Untyped] = Closure[T] + type ThisTree[-T >: Untyped] = Closure[T] } /** selector match { cases } */ - case class Match[T >: Untyped](selector: Tree[T], cases: List[CaseDef[T]]) + case class Match[-T >: Untyped] private[ast] (selector: Tree[T], cases: List[CaseDef[T]]) extends TermTree[T] { - type ThisTree[T >: Untyped] = Match[T] + type ThisTree[-T >: Untyped] = Match[T] } /** case pat if guard => body */ - case class CaseDef[T >: Untyped](pat: Tree[T], guard: Tree[T], body: Tree[T]) + case class CaseDef[-T >: Untyped] private[ast] (pat: Tree[T], guard: Tree[T], body: Tree[T]) extends Tree[T] { - type ThisTree[T >: Untyped] = CaseDef[T] + type ThisTree[-T >: Untyped] = CaseDef[T] } /** return expr @@ -457,121 +458,114 @@ object Trees { * After program transformations this is not necessarily the enclosing method, because * closures can intervene. */ - case class Return[T >: Untyped](expr: Tree[T], from: Tree[T] = emptyTree[T]()) + case class Return[-T >: Untyped] private[ast] (expr: Tree[T], from: Tree[T] = genericEmptyTree) extends TermTree[T] { - type ThisTree[T >: Untyped] = Return[T] + type ThisTree[-T >: Untyped] = Return[T] } /** try block catch handler finally finalizer */ - case class Try[T >: Untyped](expr: Tree[T], handler: Tree[T], finalizer: Tree[T]) + case class Try[-T >: Untyped] private[ast] (expr: Tree[T], handler: Tree[T], finalizer: Tree[T]) extends TermTree[T] { - type ThisTree[T >: Untyped] = Try[T] + type ThisTree[-T >: Untyped] = Try[T] } /** throw expr */ - case class Throw[T >: Untyped](expr: Tree[T]) + case class Throw[-T >: Untyped] private[ast] (expr: Tree[T]) extends TermTree[T] { - type ThisTree[T >: Untyped] = Throw[T] + type ThisTree[-T >: Untyped] = Throw[T] } /** Array[elemtpt](elems) */ - case class SeqLiteral[T >: Untyped](elems: List[Tree[T]]) + case class SeqLiteral[-T >: Untyped] private[ast] (elems: List[Tree[T]]) extends Tree[T] { - type ThisTree[T >: Untyped] = SeqLiteral[T] + type ThisTree[-T >: Untyped] = SeqLiteral[T] } /** A type tree that represents an existing or inferred type */ - case class TypeTree[T >: Untyped](original: Tree[T] = emptyTree[T]) + case class TypeTree[-T >: Untyped] private[ast] (original: Tree[T]) extends DenotingTree[T] with TypTree[T] { - type ThisTree[T >: Untyped] = TypeTree[T] + type ThisTree[-T >: Untyped] = TypeTree[T] override def initialPos = NoPosition override def isEmpty = !hasType && original.isEmpty } - object TypeTree { - def apply(tpe: Type): TypeTree[Type] = TypeTree().withType(tpe) - } - /** ref.type */ - case class SingletonTypeTree[T >: Untyped](ref: Tree[T]) + case class SingletonTypeTree[-T >: Untyped] private[ast] (ref: Tree[T]) extends DenotingTree[T] with TypTree[T] { - type ThisTree[T >: Untyped] = SingletonTypeTree[T] + type ThisTree[-T >: Untyped] = SingletonTypeTree[T] } /** qualifier # name */ - case class SelectFromTypeTree[T >: Untyped](qualifier: Tree[T], name: Name) + case class SelectFromTypeTree[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name) extends RefTree[T] { - type ThisTree[T >: Untyped] = SelectFromTypeTree[T] - def withName(name: Name) = this.derivedSelectFromTypeTree(qualifier, name) + type ThisTree[-T >: Untyped] = SelectFromTypeTree[T] + def withName(name: Name)(implicit ctx: Context): untpd.SelectFromTypeTree = untpd.cpy.SelectFromTypeTree(this, qualifier, name) } /** left & right */ - case class AndTypeTree[T >: Untyped](left: Tree[T], right: Tree[T]) + case class AndTypeTree[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T]) extends TypTree[T] { - type ThisTree[T >: Untyped] = AndTypeTree[T] + type ThisTree[-T >: Untyped] = AndTypeTree[T] } /** left | right */ - case class OrTypeTree[T >: Untyped](left: Tree[T], right: Tree[T]) + case class OrTypeTree[-T >: Untyped] private[ast] (left: Tree[T], right: Tree[T]) extends TypTree[T] { - type ThisTree[T >: Untyped] = OrTypeTree[T] + type ThisTree[-T >: Untyped] = OrTypeTree[T] } /** tpt { refinements } */ - case class RefinedTypeTree[T >: Untyped](tpt: Tree[T], refinements: List[Tree[T]]) + case class RefinedTypeTree[-T >: Untyped] private[ast] (tpt: Tree[T], refinements: List[Tree[T]]) extends ProxyTree[T] with TypTree[T] { - type ThisTree[T >: Untyped] = RefinedTypeTree[T] + type ThisTree[-T >: Untyped] = RefinedTypeTree[T] def forwardTo = tpt } /** tpt[args] */ - case class AppliedTypeTree[T >: Untyped](tpt: Tree[T], args: List[Tree[T]]) + case class AppliedTypeTree[-T >: Untyped] private[ast] (tpt: Tree[T], args: List[Tree[T]]) extends ProxyTree[T] with TypTree[T] { - type ThisTree[T >: Untyped] = AppliedTypeTree[T] + type ThisTree[-T >: Untyped] = AppliedTypeTree[T] def forwardTo = tpt } - def AppliedTypeTree[T >: Untyped](tpt: Tree[T], arg: Tree[T]): AppliedTypeTree[T] = - AppliedTypeTree(tpt, arg :: Nil) - /** >: lo <: hi */ - case class TypeBoundsTree[T >: Untyped](lo: Tree[T], hi: Tree[T]) + case class TypeBoundsTree[-T >: Untyped] private[ast] (lo: Tree[T], hi: Tree[T]) extends Tree[T] { - type ThisTree[T >: Untyped] = TypeBoundsTree[T] + type ThisTree[-T >: Untyped] = TypeBoundsTree[T] } /** name @ body */ - case class Bind[T >: Untyped](name: Name, body: Tree[T]) + case class Bind[-T >: Untyped] private[ast] (name: Name, body: Tree[T]) extends NameTree[T] with DefTree[T] with PatternTree[T] { - type ThisTree[T >: Untyped] = Bind[T] + type ThisTree[-T >: Untyped] = Bind[T] override def envelope: Position = pos union initialPos - def withName(name: Name) = this.derivedBind(name, body) + def withName(name: Name)(implicit ctx: Context): untpd.Bind = untpd.cpy.Bind(this, name, body) } /** tree_1 | ... | tree_n */ - case class Alternative[T >: Untyped](trees: List[Tree[T]]) + case class Alternative[-T >: Untyped] private[ast] (trees: List[Tree[T]]) extends PatternTree[T] { - type ThisTree[T >: Untyped] = Alternative[T] + type ThisTree[-T >: Untyped] = Alternative[T] } /** fun(args) in a pattern, if fun is an extractor */ - case class UnApply[T >: Untyped](fun: Tree[T], args: List[Tree[T]]) + case class UnApply[-T >: Untyped] private[ast] (fun: Tree[T], args: List[Tree[T]]) extends PatternTree[T] { - type ThisTree[T >: Untyped] = UnApply[T] + type ThisTree[-T >: Untyped] = UnApply[T] } /** mods val name: tpt = rhs */ - case class ValDef[T >: Untyped](mods: Modifiers[T], name: TermName, tpt: Tree[T], rhs: Tree[T]) + case class ValDef[-T >: Untyped] private[ast] (mods: Modifiers[T], name: TermName, tpt: Tree[T], rhs: Tree[T]) extends ValOrDefDef[T] { - type ThisTree[T >: Untyped] = ValDef[T] - def withName(name: Name) = this.derivedValDef(mods, name.toTermName, tpt, rhs) + type ThisTree[-T >: Untyped] = ValDef[T] + def withName(name: Name)(implicit ctx: Context): untpd.ValDef = untpd.cpy.ValDef(this, mods, name.toTermName, tpt, rhs) } /** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */ - 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]) + case class DefDef[-T >: Untyped] private[ast] (mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T]) extends ValOrDefDef[T] { - type ThisTree[T >: Untyped] = DefDef[T] - def withName(name: Name) = this.derivedDefDef(mods, name.toTermName, tparams, vparamss, tpt, rhs) + type ThisTree[-T >: Untyped] = DefDef[T] + def withName(name: Name)(implicit ctx: Context): untpd.DefDef = untpd.cpy.DefDef(this, mods, name.toTermName, tparams, vparamss, tpt, rhs) } /** mods class name template or @@ -579,10 +573,10 @@ object Trees { * mods type name = rhs or * mods type name >: lo <: hi, if rhs = TypeBoundsTree(lo, hi) & (lo ne hi) */ - case class TypeDef[T >: Untyped](mods: Modifiers[T], name: TypeName, rhs: Tree[T]) + case class TypeDef[-T >: Untyped] private[ast] (mods: Modifiers[T], name: TypeName, rhs: Tree[T]) extends MemberDef[T] { - type ThisTree[T >: Untyped] = TypeDef[T] - def withName(name: Name) = this.derivedTypeDef(mods, name.toTypeName, rhs, tparams) + type ThisTree[-T >: Untyped] = TypeDef[T] + def withName(name: Name)(implicit ctx: Context): untpd.TypeDef = untpd.cpy.TypeDef(this, mods, name.toTypeName, rhs, tparams) /** Is this a definition of a class? */ def isClassDef = rhs.isInstanceOf[Template[_]] @@ -595,97 +589,76 @@ object Trees { } /** extends parents { self => body } */ - case class Template[T >: Untyped](constr: DefDef[T], parents: List[Tree[T]], self: ValDef[T], body: List[Tree[T]]) + case class Template[-T >: Untyped] private[ast] (constr: DefDef[T], parents: List[Tree[T]], self: ValDef[T], body: List[Tree[T]]) extends DefTree[T] { - type ThisTree[T >: Untyped] = Template[T] + type ThisTree[-T >: Untyped] = Template[T] } /** import expr.selectors * where a selector is either an untyped `Ident`, `name` or * an untyped `Pair` `name => rename` */ - case class Import[T >: Untyped](expr: Tree[T], selectors: List[Tree[Untyped]]) + case class Import[-T >: Untyped] private[ast] (expr: Tree[T], selectors: List[Tree[Untyped]]) extends DenotingTree[T] { - type ThisTree[T >: Untyped] = Import[T] + type ThisTree[-T >: Untyped] = Import[T] } /** package pid { stats } */ - case class PackageDef[T >: Untyped](pid: RefTree[T], stats: List[Tree[T]]) + case class PackageDef[-T >: Untyped] private[ast] (pid: RefTree[T], stats: List[Tree[T]]) extends ProxyTree[T] { - type ThisTree[T >: Untyped] = PackageDef[T] + type ThisTree[-T >: Untyped] = PackageDef[T] def forwardTo = pid } /** arg @annot */ - case class Annotated[T >: Untyped](annot: Tree[T], arg: Tree[T]) + case class Annotated[-T >: Untyped] private[ast] (annot: Tree[T], arg: Tree[T]) extends ProxyTree[T] { - type ThisTree[T >: Untyped] = Annotated[T] + type ThisTree[-T >: Untyped] = Annotated[T] def forwardTo = arg } - trait WithoutType[T >: Untyped] extends Tree[T] { - override def tpe = NoType.asInstanceOf[T] + trait WithoutType[-T >: Untyped] extends Tree[T] { + override def tpe: T @uncheckedVariance = NoType.asInstanceOf[T] override def withType(tpe: Type) = this.asInstanceOf[ThisTree[Type]] } - val EmptyTree: Thicket[_] = Thicket(Nil) - - def emptyTree[T >: Untyped](): Thicket[T] = EmptyTree.asInstanceOf[Thicket[T]] - - class EmptyValDef[T >: Untyped] extends ValDef[T]( - Modifiers[T](Private), nme.WILDCARD, emptyTree[T], emptyTree[T]) with WithoutType[T] { - override def isEmpty: Boolean = true - } - - private object theEmptyValDef extends EmptyValDef[Untyped] - - object EmptyValDef { - 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 >: Untyped](shared: Tree[T]) extends ProxyTree[T] { - type ThisTree[T >: Untyped] = SharedTree[T] - def forwardTo: Tree[T] = shared - } - /** Temporary class that results from translation of ModuleDefs * (and possibly other statements). * The contained trees will be integrated when transformed with * a `transform(List[Tree])` call. */ - case class Thicket[T >: Untyped](trees: List[Tree[T]]) + case class Thicket[-T >: Untyped](trees: List[Tree[T]]) extends Tree[T] with WithoutType[T] { - type ThisTree[T >: Untyped] = Thicket[T] + type ThisTree[-T >: Untyped] = Thicket[T] override def isEmpty: Boolean = trees.isEmpty override def toList: List[Tree[T]] = trees override def toString = if (isEmpty) "EmptyTree" else "Thicket(" + trees.mkString(", ") + ")" } - object Thicket { - def apply[T >: Untyped](): Thicket[T] = emptyTree() - def apply[T >: Untyped](x1: Tree[T], x2: Tree[T]): Thicket[T] = Thicket(x1 :: x2 :: Nil) - def apply[T >: Untyped](x1: Tree[T], x2: Tree[T], x3: Tree[T]): Thicket[T] = Thicket(x1 :: x2 :: x3 :: Nil) - def make[T >: Untyped](xs: List[Tree[T]]): Tree[T] = flatten(xs) match { - case x :: Nil => x - case _ => apply(xs) - } + class EmptyValDef[T >: Untyped] extends ValDef[T]( + Modifiers[T](Private), nme.WILDCARD, genericEmptyTree[T], genericEmptyTree[T]) with WithoutType[T] { + override def isEmpty: Boolean = true } - // ----- Auxiliary creation methods ------------------ + val theEmptyTree: Thicket[Type] = Thicket(Nil) + val theEmptyValDef = new EmptyValDef[Type] + + def genericEmptyValDef[T >: Untyped]: ValDef[T] = theEmptyValDef.asInstanceOf[ValDef[T]] + def genericEmptyTree[T >: Untyped]: Thicket[T] = theEmptyTree.asInstanceOf[Thicket[T]] - def Block[T >: Untyped](stat: Tree[T], expr: Tree[T]): Block[T] = - Block(stat :: Nil, expr) + /** A tree that can be shared without its position + * polluting containing trees. Accumulators and tranformers + * memoize results of shared subtrees + */ + case class SharedTree[-T >: Untyped](shared: Tree[T]) extends ProxyTree[T] { + type ThisTree[-T >: Untyped] = SharedTree[T] + def forwardTo: Tree[T] = shared + } - def Apply[T >: Untyped](fn: Tree[T], arg: Tree[T]): Apply[T] = - Apply(fn, arg :: Nil) // ----- Generic Tree Instances, inherited from `tpt` and `untpd`. - abstract class Instance[T >: Untyped] { + abstract class Instance[T >: Untyped] extends DotClass { inst => type Modifiers = Trees.Modifiers[T] type Tree = Trees.Tree[T] @@ -703,6 +676,7 @@ object Trees { type Ident = Trees.Ident[T] type BackquotedIdent = Trees.BackquotedIdent[T] type Select = Trees.Select[T] + type SelectWithSig = Trees.SelectWithSig[T] type This = Trees.This[T] type Super = Trees.Super[T] type Apply = Trees.Apply[T] @@ -743,182 +717,521 @@ object Trees { type SharedTree = Trees.SharedTree[T] type Thicket = Trees.Thicket[T] - protected implicit def pos(implicit ctx: Context): Position = ctx.position + def Ident(name: Name)(implicit ctx: Context): Ident = new Ident(name) + def BackquotedIdent(name: Name)(implicit ctx: Context): BackquotedIdent = new BackquotedIdent(name) + def Select(qualifier: Tree, name: Name)(implicit ctx: Context): Select = new Select(qualifier, name) + def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit ctx: Context): Select = new SelectWithSig(qualifier, name, sig) + def This(qual: TypeName)(implicit ctx: Context): This = new This(qual) + def Super(qual: Tree, mix: TypeName)(implicit ctx: Context): Super = new Super(qual, mix) + def Apply(fun: Tree, args: List[Tree])(implicit ctx: Context): Apply = new Apply(fun, args) + def TypeApply(fun: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = new TypeApply(fun, args) + def Literal(const: Constant)(implicit ctx: Context): Literal = new Literal(const) + def New(tpt: Tree)(implicit ctx: Context): New = new New(tpt) + def Pair(left: Tree, right: Tree)(implicit ctx: Context): Pair = new Pair(left, right) + def Typed(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed = new Typed(expr, tpt) + def NamedArg(name: Name, arg: Tree)(implicit ctx: Context): NamedArg = new NamedArg(name, arg) + def Assign(lhs: Tree, rhs: Tree)(implicit ctx: Context): Assign = new Assign(lhs, rhs) + def Block(stats: List[Tree], expr: Tree)(implicit ctx: Context): Block = new Block(stats, expr) + def If(cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If = new If(cond, thenp, elsep) + def Closure(env: List[Tree], meth: RefTree)(implicit ctx: Context): Closure = new Closure(env, meth) + def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = new Match(selector, cases) + def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef = new CaseDef(pat, guard, body) + def Return(expr: Tree, from: Tree)(implicit ctx: Context): Return = new Return(expr, from) + def Try(expr: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): Try = new Try(expr, handler, finalizer) + def Throw(expr: Tree)(implicit ctx: Context): Throw = new Throw(expr) + def SeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral = new SeqLiteral(elems) + def TypeTree(original: Tree)(implicit ctx: Context): TypeTree = new TypeTree(original) + def TypeTree() = new TypeTree(EmptyTree) + def SingletonTypeTree(ref: Tree)(implicit ctx: Context): SingletonTypeTree = new SingletonTypeTree(ref) + def SelectFromTypeTree(qualifier: Tree, name: Name)(implicit ctx: Context): SelectFromTypeTree = new SelectFromTypeTree(qualifier, name) + def AndTypeTree(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = new AndTypeTree(left, right) + def OrTypeTree(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = new OrTypeTree(left, right) + def RefinedTypeTree(tpt: Tree, refinements: List[Tree])(implicit ctx: Context): RefinedTypeTree = new RefinedTypeTree(tpt, refinements) + def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = new AppliedTypeTree(tpt, args) + def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = new TypeBoundsTree(lo, hi) + def Bind(name: Name, body: Tree)(implicit ctx: Context): Bind = new Bind(name, body) + def Alternative(trees: List[Tree])(implicit ctx: Context): Alternative = new Alternative(trees) + def UnApply(fun: Tree, args: List[Tree])(implicit ctx: Context): UnApply = new UnApply(fun, args) + def ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree)(implicit ctx: Context): ValDef = new ValDef(mods, name, tpt, rhs) + def DefDef(mods: Modifiers, name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree)(implicit ctx: Context): DefDef = new DefDef(mods, name, tparams, vparamss, tpt, rhs) + def TypeDef(mods: Modifiers, name: TypeName, rhs: Tree)(implicit ctx: Context): TypeDef = new TypeDef(mods, name, rhs) + def Template(constr: DefDef, parents: List[Tree], self: ValDef, body: List[Tree])(implicit ctx: Context): Template = new Template(constr, parents, self, body) + def Import(expr: Tree, selectors: List[untpd.Tree])(implicit ctx: Context): Import = new Import(expr, selectors) + def PackageDef(pid: RefTree, stats: List[Tree])(implicit ctx: Context): PackageDef = new PackageDef(pid, stats) + def Annotated(annot: Tree, arg: Tree)(implicit ctx: Context): Annotated = new Annotated(annot, arg) + def SharedTree(shared: Tree)(implicit ctx: Context): SharedTree = new SharedTree(shared) + def Thicket(trees: List[Tree])(implicit ctx: Context): Thicket = new Thicket(trees) + + val EmptyTree: Thicket = genericEmptyTree + val EmptyValDef: ValDef = genericEmptyValDef + + def Modifiers(flags: FlagSet = EmptyFlags, + privateWithin: TypeName = tpnme.EMPTY, + annotations: List[Tree] = Nil) = new Modifiers(flags, privateWithin, annotations) + + // ----- Auxiliary creation methods ------------------ + + // def TypeTree(tpe: Type): TypeTree = TypeTree().withType(tpe) todo: move to untpd/tpd + + /** new tpt(args1)...(args_n) + */ + def New(tpt: Tree, argss: List[List[Tree]])(implicit ctx: Context): Tree = + ((Select(New(tpt), nme.CONSTRUCTOR): Tree) /: argss)(Apply(_, _)) - def defPos(sym: Symbol)(implicit ctx: Context) = ctx.position union sym.coord.toPosition - } + def Block(stat: Tree, expr: Tree)(implicit ctx: Context): Block = + Block(stat :: Nil, expr) - // ----- Helper functions and classes --------------------------------------- + def Apply(fn: Tree, arg: Tree)(implicit ctx: Context): Apply = + Apply(fn, arg :: Nil) - implicit class TreeCopier[T >: Untyped](val tree: Tree[T]) extends AnyVal { - def derivedIdent(name: Name): Ident[T] = tree match { - case tree: BackquotedIdent[_] => - if (name == tree.name) tree - else new BackquotedIdent[T](name).withPos(tree.pos) - case tree: Ident[_] if (name == tree.name) => tree - case _ => Ident[T](name).withPos(tree.pos) - } - def derivedSelect(qualifier: Tree[T], name: Name): Select[T] = tree match { - case tree: Select[_] if (qualifier eq tree.qualifier) && (name == tree.name) => tree - case _ => Select(qualifier, name).withPos(tree.pos) - } - def derivedThis(qual: TypeName): This[T] = tree match { - case tree: This[_] if (qual == tree.qual) => tree - case _ => This[T](qual).withPos(tree.pos) - } - def derivedSuper(qual: Tree[T], mix: TypeName): Super[T] = tree match { - case tree: Super[_] if (qual eq tree.qual) && (mix == tree.mix) => tree - case _ => Super(qual, mix).withPos(tree.pos) - } - def derivedApply(fun: Tree[T], args: List[Tree[T]]): Apply[T] = tree match { - case tree: Apply[_] if (fun eq tree.fun) && (args eq tree.args) => tree - case _ => Apply(fun, args).withPos(tree.pos) - } - def derivedTypeApply(fun: Tree[T], args: List[Tree[T]]): TypeApply[T] = tree match { - case tree: TypeApply[_] if (fun eq tree.fun) && (args eq tree.args) => tree - case _ => TypeApply(fun, args).withPos(tree) - } - def derivedLiteral(const: Constant): Literal[T] = tree match { - case tree: Literal[_] if (const == tree.const) => tree - case _ => Literal[T](const).withPos(tree.pos) - } - def derivedNew(tpt: Tree[T]): New[T] = tree match { - case tree: New[_] if (tpt eq tree.tpt) => tree - case _ => New(tpt).withPos(tree.pos) - } - def derivedPair(left: Tree[T], right: Tree[T]): Pair[T] = tree match { - case tree: Pair[_] if (left eq tree.left) && (right eq tree.right) => tree - case _ => Pair(left, right).withPos(tree.pos) - } - def derivedTyped(expr: Tree[T], tpt: Tree[T]): Typed[T] = tree match { - case tree: Typed[_] if (expr eq tree.expr) && (tpt eq tree.tpt) => tree - case _ => Typed(expr, tpt).withPos(tree.pos) - } - def derivedNamedArg(name: Name, arg: Tree[T]): NamedArg[T] = tree match { - case tree: NamedArg[_] if (name == tree.name) && (arg eq tree.arg) => tree - case _ => NamedArg(name, arg).withPos(tree.pos) - } - def derivedAssign(lhs: Tree[T], rhs: Tree[T]): Assign[T] = tree match { - case tree: Assign[_] if (lhs eq tree.lhs) && (rhs eq tree.rhs) => tree - case _ => Assign(lhs, rhs).withPos(tree.pos) - } - def derivedBlock(stats: List[Tree[T]], expr: Tree[T]): Block[T] = tree match { - case tree: Block[_] if (stats eq tree.stats) && (expr eq tree.expr) => tree - case _ => Block(stats, expr).withPos(tree.pos) - } - def derivedIf(cond: Tree[T], thenp: Tree[T], elsep: Tree[T]): If[T] = tree match { - case tree: If[_] if (cond eq tree.cond) && (thenp eq tree.thenp) && (elsep eq tree.elsep) => tree - case _ => If(cond, thenp, elsep).withPos(tree.pos) - } - def derivedClosure(env: List[Tree[T]], meth: RefTree[T]): Closure[T] = tree match { - case tree: Closure[_] if (env eq tree.env) && (meth eq tree.meth) => tree - case _ => Closure(env, meth).withPos(tree.pos) - } - def derivedMatch(selector: Tree[T], cases: List[CaseDef[T]]): Match[T] = tree match { - case tree: Match[_] if (selector eq tree.selector) && (cases eq tree.cases) => tree - case _ => Match(selector, cases).withPos(tree.pos) - } - def derivedCaseDef(pat: Tree[T], guard: Tree[T], body: Tree[T]): CaseDef[T] = tree match { - case tree: CaseDef[_] if (pat eq tree.pat) && (guard eq tree.guard) && (body eq tree.body) => tree - case _ => CaseDef(pat, guard, body).withPos(tree.pos) - } - def derivedReturn(expr: Tree[T], from: Tree[T]): Return[T] = tree match { - case tree: Return[_] if (expr eq tree.expr) && (from eq tree.from) => tree - case _ => Return(expr, from).withPos(tree.pos) - } - def derivedTry(expr: Tree[T], handler: Tree[T], finalizer: Tree[T]): Try[T] = tree match { - case tree: Try[_] if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree - case _ => Try(expr, handler, finalizer).withPos(tree.pos) - } - def derivedThrow(expr: Tree[T]): Throw[T] = tree match { - case tree: Throw[_] if (expr eq tree.expr) => tree - case _ => Throw(expr).withPos(tree.pos) - } - def derivedSeqLiteral(elems: List[Tree[T]]): SeqLiteral[T] = tree match { - case tree: SeqLiteral[_] if (elems eq tree.elems) => tree - case _ => SeqLiteral(elems).withPos(tree.pos) - } - def derivedSingletonTypeTree(ref: Tree[T]): SingletonTypeTree[T] = tree match { - case tree: SingletonTypeTree[_] if (ref eq tree.ref) => tree - case _ => SingletonTypeTree(ref).withPos(tree.pos) - } - def derivedSelectFromTypeTree(qualifier: Tree[T], name: Name): SelectFromTypeTree[T] = tree match { - case tree: SelectFromTypeTree[_] if (qualifier eq tree.qualifier) && (name == tree.name) => tree - case _ => SelectFromTypeTree(qualifier, name).withPos(tree.pos) - } - def derivedAndTypeTree(left: Tree[T], right: Tree[T]): AndTypeTree[T] = tree match { - case tree: AndTypeTree[_] if (left eq tree.left) && (right eq tree.right) => tree - case _ => AndTypeTree(left, right).withPos(tree.pos) - } - def derivedOrTypeTree(left: Tree[T], right: Tree[T]): OrTypeTree[T] = tree match { - case tree: OrTypeTree[_] if (left eq tree.left) && (right eq tree.right) => tree - case _ => OrTypeTree(left, right).withPos(tree.pos) - } - def derivedRefinedTypeTree(tpt: Tree[T], refinements: List[Tree[T]]): RefinedTypeTree[T] = tree match { - case tree: RefinedTypeTree[_] if (tpt eq tree.tpt) && (refinements eq tree.refinements) => tree - case _ => RefinedTypeTree(tpt, refinements).withPos(tree.pos) - } - def derivedAppliedTypeTree(tpt: Tree[T], args: List[Tree[T]]): AppliedTypeTree[T] = tree match { - case tree: AppliedTypeTree[_] if (tpt eq tree.tpt) && (args eq tree.args) => tree - case _ => AppliedTypeTree(tpt, args).withPos(tree.pos) - } - def derivedTypeBoundsTree(lo: Tree[T], hi: Tree[T]): TypeBoundsTree[T] = tree match { - case tree: TypeBoundsTree[_] if (lo eq tree.lo) && (hi eq tree.hi) => tree - case _ => TypeBoundsTree(lo, hi).withPos(tree.pos) - } - def derivedBind(name: Name, body: Tree[T]): Bind[T] = tree match { - case tree: Bind[_] if (name eq tree.name) && (body eq tree.body) => tree - case _ => Bind(name, body).withPos(tree.pos) - } - def derivedAlternative(trees: List[Tree[T]]): Alternative[T] = tree match { - case tree: Alternative[_] if (trees eq tree.trees) => tree - case _ => Alternative(trees).withPos(tree.pos) - } - def derivedUnApply(fun: Tree[T], args: List[Tree[T]]): UnApply[T] = tree match { - case tree: UnApply[_] if (fun eq tree.fun) && (args eq tree.args) => tree - case _ => UnApply(fun, args).withPos(tree.pos) - } - def derivedValDef(mods: Modifiers[T], name: TermName, tpt: Tree[T], rhs: Tree[T]): ValDef[T] = tree match { - case tree: ValDef[_] if (mods == tree.mods) && (name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree - case _ => ValDef(mods, name, tpt, rhs).withPos(tree.pos) - } - def derivedDefDef(mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T]): DefDef[T] = tree match { - case tree: DefDef[_] if (mods == tree.mods) && (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree - case _ => DefDef(mods, name, tparams, vparamss, tpt, rhs).withPos(tree.pos) - } - def derivedTypeDef(mods: Modifiers[T], name: TypeName, rhs: Tree[T], tparams: List[untpd.TypeDef] = Nil): TypeDef[T] = tree match { - case tree: TypeDef[_] if (mods == tree.mods) && (name == tree.name) && (rhs eq tree.rhs) && (tparams eq tree.tparams) => tree - case _ => - if (tparams.nonEmpty) - (untpd.typeDef _).asInstanceOf[(Modifiers[T], TypeName, List[untpd.TypeDef], Tree[T]) => TypeDef[T]]( - mods, name, tparams, rhs).withPos(tree.pos) - else TypeDef(mods, name, rhs).withPos(tree.pos) + def AppliedTypeTree(tpt: Tree, arg: Tree)(implicit ctx: Context): AppliedTypeTree = + AppliedTypeTree(tpt, arg :: Nil) + + def Thicket()(implicit ctx: Context): Thicket = EmptyTree + def Thicket(x1: Tree, x2: Tree)(implicit ctx: Context): Thicket = Thicket(x1 :: x2 :: Nil) + def Thicket(x1: Tree, x2: Tree, x3: Tree)(implicit ctx: Context): Thicket = Thicket(x1 :: x2 :: x3 :: Nil) + def flatTree(xs: List[Tree])(implicit ctx: Context): Tree = flatten(xs) match { + case x :: Nil => x + case _ => Thicket(xs) } - def derivedTemplate(constr: DefDef[T], parents: List[Tree[T]], self: ValDef[T], body: List[Tree[T]]): Template[T] = tree match { - case tree: Template[_] if (constr eq tree.constr) && (parents eq tree.parents) && (self eq tree.self) && (body eq tree.body) => tree - case _ => Template(constr, parents, self, body).withPos(tree.pos) + + def flatten(trees: List[Tree]): List[Tree] = { + var buf: ListBuffer[Tree] = null + def add(tree: Tree) = { + assert(!tree.isInstanceOf[Thicket]) + buf += tree + } + var xs = trees + while (xs.nonEmpty) { + xs.head match { + case Thicket(elems) => + if (buf == null) { + buf = new ListBuffer + var ys = trees + while (ys ne xs) { + buf += ys.head + ys = ys.tail + } + } + for (elem <- elems) { + assert(!elem.isInstanceOf[Thicket]) + buf += elem + } + case tree => + if (buf != null) buf += tree + } + xs = xs.tail + } + if (buf != null) buf.toList else trees } - def derivedImport(expr: Tree[T], selectors: List[Tree[Untyped]]): Import[T] = tree match { - case tree: Import[_] if (expr eq tree.expr) && (selectors eq tree.selectors) => tree - case _ => Import(expr, selectors).withPos(tree.pos) + + // ----- Position handling ----------------------------------------- + + protected implicit def pos(implicit ctx: Context): Position = ctx.position + + def defPos(sym: Symbol)(implicit ctx: Context) = ctx.position union sym.coord.toPosition + + // ----- Helper classes for copying, transforming, accumulating ----------------- + + val cpy: TreeCopier + + abstract class TreeCopier { + + def postProcess(tree: Tree, copied: untpd.Tree): copied.ThisTree[T] + + def finalize(tree: Tree, copied: untpd.Tree): copied.ThisTree[T] = + postProcess(tree, copied withPos tree.pos) + + private def copyAttrs(t: untpd.Tree, tree: Tree): t.ThisTree[T] = + t.withType(tree.typeOpt).withPos(tree.pos).asInstanceOf[t.ThisTree[T]] + + def Ident(tree: Tree, name: Name)(implicit ctx: Context): Ident = tree match { + case tree: BackquotedIdent => + if (name == tree.name) tree + else finalize(tree, new BackquotedIdent(name)) + case tree: Ident if (name == tree.name) => tree + case _ => finalize(tree, untpd.Ident(name)) + } + def Select(tree: Tree, qualifier: Tree, name: Name)(implicit ctx: Context): Select = tree match { + case tree: SelectWithSig => + if ((qualifier eq tree.qualifier) && (name == tree.name) ) tree + else finalize(tree, new SelectWithSig(qualifier, name, tree.sig)) + case tree: Select if (qualifier eq tree.qualifier) && (name == tree.name) => tree + case _ => finalize(tree, untpd.Select(qualifier, name)) + } + def This(tree: Tree, qual: TypeName)(implicit ctx: Context): This = tree match { + case tree: This if (qual == tree.qual) => tree + case _ => finalize(tree, untpd.This(qual)) + } + def Super(tree: Tree, qual: Tree, mix: TypeName)(implicit ctx: Context): Super = tree match { + case tree: Super if (qual eq tree.qual) && (mix == tree.mix) => tree + case _ => finalize(tree, untpd.Super(qual, mix)) + } + def Apply(tree: Tree, fun: Tree, args: List[Tree])(implicit ctx: Context): Apply = tree match { + case tree: Apply if (fun eq tree.fun) && (args eq tree.args) => tree + case _ => finalize(tree, untpd.Apply(fun, args)) + } + def TypeApply(tree: Tree, fun: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = tree match { + case tree: TypeApply if (fun eq tree.fun) && (args eq tree.args) => tree + case _ => inst.TypeApply(fun, args).withPos(tree) + } + def Literal(tree: Tree, const: Constant)(implicit ctx: Context): Literal = tree match { + case tree: Literal if (const == tree.const) => tree + case _ => finalize(tree, untpd.Literal(const)) + } + def New(tree: Tree, tpt: Tree)(implicit ctx: Context): New = tree match { + case tree: New if (tpt eq tree.tpt) => tree + case _ => finalize(tree, untpd.New(tpt)) + } + def Pair(tree: Tree, left: Tree, right: Tree)(implicit ctx: Context): Pair = tree match { + case tree: Pair if (left eq tree.left) && (right eq tree.right) => tree + case _ => finalize(tree, untpd.Pair(left, right)) + } + def Typed(tree: Tree, expr: Tree, tpt: Tree)(implicit ctx: Context): Typed = tree match { + case tree: Typed if (expr eq tree.expr) && (tpt eq tree.tpt) => tree + case _ => finalize(tree, untpd.Typed(expr, tpt)) + } + def NamedArg(tree: Tree, name: Name, arg: Tree)(implicit ctx: Context): NamedArg = tree match { + case tree: NamedArg if (name == tree.name) && (arg eq tree.arg) => tree + case _ => finalize(tree, untpd.NamedArg(name, arg)) + } + def Assign(tree: Tree, lhs: Tree, rhs: Tree)(implicit ctx: Context): Assign = tree match { + case tree: Assign if (lhs eq tree.lhs) && (rhs eq tree.rhs) => tree + case _ => finalize(tree, untpd.Assign(lhs, rhs)) + } + def Block(tree: Tree, stats: List[Tree], expr: Tree)(implicit ctx: Context): Block = tree match { + case tree: Block if (stats eq tree.stats) && (expr eq tree.expr) => tree + case _ => finalize(tree, untpd.Block(stats, expr)) + } + def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If = tree match { + case tree: If if (cond eq tree.cond) && (thenp eq tree.thenp) && (elsep eq tree.elsep) => tree + case _ => finalize(tree, untpd.If(cond, thenp, elsep)) + } + def Closure(tree: Tree, env: List[Tree], meth: RefTree)(implicit ctx: Context): Closure = tree match { + case tree: Closure if (env eq tree.env) && (meth eq tree.meth) => tree + case _ => finalize(tree, untpd.Closure(env, meth)) + } + def Match(tree: Tree, selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = tree match { + case tree: Match if (selector eq tree.selector) && (cases eq tree.cases) => tree + case _ => finalize(tree, untpd.Match(selector, cases)) + } + def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef = tree match { + case tree: CaseDef if (pat eq tree.pat) && (guard eq tree.guard) && (body eq tree.body) => tree + case _ => finalize(tree, untpd.CaseDef(pat, guard, body)) + } + def Return(tree: Tree, expr: Tree, from: Tree)(implicit ctx: Context): Return = tree match { + case tree: Return if (expr eq tree.expr) && (from eq tree.from) => tree + case _ => finalize(tree, untpd.Return(expr, from)) + } + def Try(tree: Tree, expr: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): Try = tree match { + case tree: Try if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree + case _ => finalize(tree, untpd.Try(expr, handler, finalizer)) + } + def Throw(tree: Tree, expr: Tree)(implicit ctx: Context): Throw = tree match { + case tree: Throw if (expr eq tree.expr) => tree + case _ => finalize(tree, untpd.Throw(expr)) + } + def SeqLiteral(tree: Tree, elems: List[Tree])(implicit ctx: Context): SeqLiteral = tree match { + case tree: SeqLiteral if (elems eq tree.elems) => tree + case _ => finalize(tree, untpd.SeqLiteral(elems)) + } + def SingletonTypeTree(tree: Tree, ref: Tree)(implicit ctx: Context): SingletonTypeTree = tree match { + case tree: SingletonTypeTree if (ref eq tree.ref) => tree + case _ => finalize(tree, untpd.SingletonTypeTree(ref)) + } + def SelectFromTypeTree(tree: Tree, qualifier: Tree, name: Name)(implicit ctx: Context): SelectFromTypeTree = tree match { + case tree: SelectFromTypeTree if (qualifier eq tree.qualifier) && (name == tree.name) => tree + case _ => finalize(tree, untpd.SelectFromTypeTree(qualifier, name)) + } + def AndTypeTree(tree: Tree, left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = tree match { + case tree: AndTypeTree if (left eq tree.left) && (right eq tree.right) => tree + case _ => finalize(tree, untpd.AndTypeTree(left, right)) + } + def OrTypeTree(tree: Tree, left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = tree match { + case tree: OrTypeTree if (left eq tree.left) && (right eq tree.right) => tree + case _ => finalize(tree, untpd.OrTypeTree(left, right)) + } + def RefinedTypeTree(tree: Tree, tpt: Tree, refinements: List[Tree])(implicit ctx: Context): RefinedTypeTree = tree match { + case tree: RefinedTypeTree if (tpt eq tree.tpt) && (refinements eq tree.refinements) => tree + case _ => finalize(tree, untpd.RefinedTypeTree(tpt, refinements)) + } + def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = tree match { + case tree: AppliedTypeTree if (tpt eq tree.tpt) && (args eq tree.args) => tree + case _ => finalize(tree, untpd.AppliedTypeTree(tpt, args)) + } + def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = tree match { + case tree: TypeBoundsTree if (lo eq tree.lo) && (hi eq tree.hi) => tree + case _ => finalize(tree, untpd.TypeBoundsTree(lo, hi)) + } + def Bind(tree: Tree, name: Name, body: Tree)(implicit ctx: Context): Bind = tree match { + case tree: Bind if (name eq tree.name) && (body eq tree.body) => tree + case _ => finalize(tree, untpd.Bind(name, body)) + } + def Alternative(tree: Tree, trees: List[Tree])(implicit ctx: Context): Alternative = tree match { + case tree: Alternative if (trees eq tree.trees) => tree + case _ => finalize(tree, untpd.Alternative(trees)) + } + def UnApply(tree: Tree, fun: Tree, args: List[Tree])(implicit ctx: Context): UnApply = tree match { + case tree: UnApply if (fun eq tree.fun) && (args eq tree.args) => tree + case _ => finalize(tree, untpd.UnApply(fun, args)) + } + def ValDef(tree: Tree, mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree)(implicit ctx: Context): ValDef = tree match { + case tree: ValDef if (mods == tree.mods) && (name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree + case _ => finalize(tree, untpd.ValDef(mods, name, tpt, rhs)) + } + def DefDef(tree: Tree, mods: Modifiers, name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree)(implicit ctx: Context): DefDef = tree match { + case tree: DefDef if (mods == tree.mods) && (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree + case _ => finalize(tree, untpd.DefDef(mods, name, tparams, vparamss, tpt, rhs)) + } + def TypeDef(tree: Tree, mods: Modifiers, name: TypeName, rhs: Tree, tparams: List[untpd.TypeDef] = Nil)(implicit ctx: Context): TypeDef = tree match { + case tree: TypeDef if (mods == tree.mods) && (name == tree.name) && (rhs eq tree.rhs) && (tparams eq tree.tparams) => tree + case _ => finalize(tree, untpd.TypeDef(mods, name, tparams, rhs)) + } + def Template(tree: Tree, constr: DefDef, parents: List[Tree], self: ValDef, body: List[Tree])(implicit ctx: Context): Template = tree match { + case tree: Template if (constr eq tree.constr) && (parents eq tree.parents) && (self eq tree.self) && (body eq tree.body) => tree + case _ => finalize(tree, untpd.Template(constr, parents, self, body)) + } + def Import(tree: Tree, expr: Tree, selectors: List[untpd.Tree])(implicit ctx: Context): Import = tree match { + case tree: Import if (expr eq tree.expr) && (selectors eq tree.selectors) => tree + case _ => finalize(tree, untpd.Import(expr, selectors)) + } + def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree])(implicit ctx: Context): PackageDef = tree match { + case tree: PackageDef if (pid eq tree.pid) && (stats eq tree.stats) => tree + case _ => finalize(tree, untpd.PackageDef(pid, stats)) + } + def Annotated(tree: Tree, annot: Tree, arg: Tree)(implicit ctx: Context): Annotated = tree match { + case tree: Annotated if (annot eq tree.annot) && (arg eq tree.arg) => tree + case _ => finalize(tree, untpd.Annotated(annot, arg)) + } + def SharedTree(tree: Tree, shared: Tree)(implicit ctx: Context): SharedTree = tree match { + case tree: SharedTree if (shared eq tree.shared) => tree + case _ => finalize(tree, untpd.SharedTree(shared)) + } + def Thicket(tree: Tree, trees: List[Tree])(implicit ctx: Context): Thicket = tree match { + case tree: Thicket if (trees eq tree.trees) => tree + case _ => finalize(tree, untpd.Thicket(trees)) + } } - def derivedPackageDef(pid: RefTree[T], stats: List[Tree[T]]): PackageDef[T] = tree match { - case tree: PackageDef[_] if (pid eq tree.pid) && (stats eq tree.stats) => tree - case _ => PackageDef(pid, stats).withPos(tree.pos) + + abstract class TreeTransformer(val cpy: TreeCopier = inst.cpy) { + var sharedMemo: Map[SharedTree, SharedTree] = Map() + + def transform(tree: Tree)(implicit ctx: Context): Tree = tree match { + case Ident(name) => + tree + case Select(qualifier, name) => + cpy.Select(tree, transform(qualifier), name) + case This(qual) => + tree + case Super(qual, mix) => + cpy.Super(tree, transform(qual), mix) + case Apply(fun, args) => + cpy.Apply(tree, transform(fun), transform(args)) + case TypeApply(fun, args) => + cpy.TypeApply(tree, transform(fun), transform(args)) + case Literal(const) => + tree + case New(tpt) => + cpy.New(tree, transform(tpt)) + case Pair(left, right) => + cpy.Pair(tree, transform(left), transform(right)) + case Typed(expr, tpt) => + cpy.Typed(tree, transform(expr), transform(tpt)) + case NamedArg(name, arg) => + cpy.NamedArg(tree, name, transform(arg)) + case Assign(lhs, rhs) => + cpy.Assign(tree, transform(lhs), transform(rhs)) + case Block(stats, expr) => + cpy.Block(tree, transformStats(stats), transform(expr)) + case If(cond, thenp, elsep) => + cpy.If(tree, transform(cond), transform(thenp), transform(elsep)) + case Closure(env, meth) => + cpy.Closure(tree, transform(env), transformSub(meth)) + case Match(selector, cases) => + cpy.Match(tree, transform(selector), transformSub(cases)) + case CaseDef(pat, guard, body) => + cpy.CaseDef(tree, transform(pat), transform(guard), transform(body)) + case Return(expr, from) => + cpy.Return(tree, transform(expr), transformSub(from)) + case Try(block, handler, finalizer) => + cpy.Try(tree, transform(block), transform(handler), transform(finalizer)) + case Throw(expr) => + cpy.Throw(tree, transform(expr)) + case SeqLiteral(elems) => + cpy.SeqLiteral(tree, transform(elems)) + case TypeTree(original) => + tree + case SingletonTypeTree(ref) => + cpy.SingletonTypeTree(tree, transform(ref)) + case SelectFromTypeTree(qualifier, name) => + cpy.SelectFromTypeTree(tree, transform(qualifier), name) + case AndTypeTree(left, right) => + cpy.AndTypeTree(tree, transform(left), transform(right)) + case OrTypeTree(left, right) => + cpy.OrTypeTree(tree, transform(left), transform(right)) + case RefinedTypeTree(tpt, refinements) => + cpy.RefinedTypeTree(tree, transform(tpt), transformSub(refinements)) + case AppliedTypeTree(tpt, args) => + cpy.AppliedTypeTree(tree, transform(tpt), transform(args)) + case TypeBoundsTree(lo, hi) => + cpy.TypeBoundsTree(tree, transform(lo), transform(hi)) + case Bind(name, body) => + cpy.Bind(tree, name, transform(body)) + case Alternative(trees) => + cpy.Alternative(tree, transform(trees)) + case UnApply(fun, args) => + cpy.UnApply(tree, transform(fun), transform(args)) + case ValDef(mods, name, tpt, rhs) => + cpy.ValDef(tree, mods, name, transform(tpt), transform(rhs)) + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + cpy.DefDef(tree, mods, name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(rhs)) + case tree @ TypeDef(mods, name, rhs) => + cpy.TypeDef(tree, mods, name, transform(rhs), tree.tparams) + case Template(constr, parents, self, body) => + cpy.Template(tree, transformSub(constr), transform(parents), transformSub(self), transformStats(body)) + case Import(expr, selectors) => + cpy.Import(tree, transform(expr), selectors) + case PackageDef(pid, stats) => + cpy.PackageDef(tree, transformSub(pid), transformStats(stats)) + case Annotated(annot, arg) => + cpy.Annotated(tree, transform(annot), transform(arg)) + case Thicket(trees) => + val trees1 = transform(trees) + if (trees1 eq trees) tree else Thicket(trees1) + case tree @ SharedTree(shared) => + sharedMemo get tree match { + case Some(tree1) => tree1 + case None => + val tree1 = cpy.SharedTree(tree, transform(shared)) + sharedMemo = sharedMemo.updated(tree, tree1) + tree1 + } + } + def transformStats(trees: List[Tree])(implicit ctx: Context): List[Tree] = + transform(trees) + def transform(trees: List[Tree])(implicit ctx: Context): List[Tree] = + flatten(trees mapConserve (transform(_))) + def transformSub[Tr <: Tree](tree: Tr)(implicit ctx: Context): Tr = + transform(tree).asInstanceOf[Tr] + def transformSub[Tr <: Tree](trees: List[Tr])(implicit ctx: Context): List[Tr] = + transform(trees).asInstanceOf[List[Tr]] } - def derivedAnnotated(annot: Tree[T], arg: Tree[T]): Annotated[T] = tree match { - case tree: Annotated[_] if (annot eq tree.annot) && (arg eq tree.arg) => tree - case _ => Annotated(annot, arg).withPos(tree.pos) + + abstract class TreeAccumulator[X] extends ((X, Tree) => X) { + var sharedMemo: Map[SharedTree, X] = Map() + def apply(x: X, tree: Tree): X + def apply(x: X, trees: Traversable[Tree]): X = (x /: trees)(apply) + def foldOver(x: X, tree: Tree): X = tree match { + case Ident(name) => + x + case Select(qualifier, name) => + this(x, qualifier) + case This(qual) => + x + case Super(qual, mix) => + this(x, qual) + case Apply(fun, args) => + this(this(x, fun), args) + case TypeApply(fun, args) => + this(this(x, fun), args) + case Literal(const) => + x + case New(tpt) => + this(x, tpt) + case Pair(left, right) => + this(this(x, left), right) + case Typed(expr, tpt) => + this(this(x, expr), tpt) + case NamedArg(name, arg) => + this(x, arg) + case Assign(lhs, rhs) => + this(this(x, lhs), rhs) + case Block(stats, expr) => + this(this(x, stats), expr) + case If(cond, thenp, elsep) => + this(this(this(x, cond), thenp), elsep) + case Closure(env, meth) => + this(this(x, env), meth) + case Match(selector, cases) => + this(this(x, selector), cases) + case CaseDef(pat, guard, body) => + this(this(this(x, pat), guard), body) + case Return(expr, from) => + this(this(x, expr), from) + case Try(block, handler, finalizer) => + this(this(this(x, block), handler), finalizer) + case Throw(expr) => + this(x, expr) + case SeqLiteral(elems) => + this(x, elems) + case TypeTree(original) => + x + case SingletonTypeTree(ref) => + this(x, ref) + case SelectFromTypeTree(qualifier, name) => + this(x, qualifier) + case AndTypeTree(left, right) => + this(this(x, left), right) + case OrTypeTree(left, right) => + this(this(x, left), right) + case RefinedTypeTree(tpt, refinements) => + this(this(x, tpt), refinements) + case AppliedTypeTree(tpt, args) => + this(this(x, tpt), args) + case TypeBoundsTree(lo, hi) => + this(this(x, lo), hi) + case Bind(name, body) => + this(x, body) + case Alternative(trees) => + this(x, trees) + case UnApply(fun, args) => + this(this(x, fun), args) + case ValDef(mods, name, tpt, rhs) => + this(this(x, tpt), rhs) + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + this(this((this(x, tparams) /: vparamss)(apply), tpt), rhs) + case TypeDef(mods, name, rhs) => + this(x, rhs) + case Template(constr, parents, self, body) => + this(this(this(this(x, constr), parents), self), body) + case Import(expr, selectors) => + this(x, expr) + case PackageDef(pid, stats) => + this(this(x, pid), stats) + case Annotated(annot, arg) => + this(this(x, annot), arg) + case Thicket(ts) => + this(x, ts) + case tree @ SharedTree(shared) => + sharedMemo get tree match { + case Some(x1) => x1 + case None => + val x1 = this(x, shared) + sharedMemo = sharedMemo.updated(tree, x1) + x1 + } + } } - def derivedSharedTree(shared: Tree[T]): SharedTree[T] = tree match { - case tree: SharedTree[_] if (shared eq tree.shared) => tree - case _ => SharedTree(shared).withPos(tree.pos) + + /** Fold `f` over all tree nodes, in depth-first, prefix order */ + class DeepFolder[X](f: (X, Tree) => X) extends TreeAccumulator[X] { + def apply(x: X, tree: Tree): X = foldOver(f(x, tree), tree) } - def derivedThicket(trees: List[Tree[T]]): Thicket[T] = tree match { - case tree: Thicket[_] if (trees eq tree.trees) => tree - case _ => Thicket(trees).withPos(tree.pos) + + /** 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[X](f: (X, Tree) => X) extends TreeAccumulator[X] { + def apply(x: X, tree: Tree): X = { + val x1 = f(x, tree) + if (x1.asInstanceOf[AnyRef] ne x1.asInstanceOf[AnyRef]) x1 + else foldOver(x1, tree) + } } } +} + // ----- Helper functions and classes --------------------------------------- +/* abstract class FullTreeTransformer[T >: Untyped, C] { var sharedMemo: Map[SharedTree[T], SharedTree[T]] = Map() @@ -1068,250 +1381,5 @@ object Trees { def finishEmptyTree(tree: Tree[T], old: Tree[T], c: C, plugins: Plugins) = tree def finishSharedTree(tree: Tree[T], old: Tree[T], c: C, plugins: Plugins) = tree } +*/ - def flatten[T >: Untyped](trees: List[Tree[T]]): List[Tree[T]] = { - var buf: ListBuffer[Tree[T]] = null - def add(tree: Tree[T]) = { - assert(!tree.isInstanceOf[Thicket[_]]) - buf += tree - } - var xs = trees - while (xs.nonEmpty) { - xs.head match { - case Thicket(elems) => - if (buf == null) { - buf = new ListBuffer - var ys = trees - while (ys ne xs) { - buf += ys.head - ys = ys.tail - } - } - for (elem <- elems) { - assert(!elem.isInstanceOf[Thicket[_]]) - buf += elem - } - case tree => - if (buf != null) buf += tree - } - xs = xs.tail - } - if (buf != null) buf.toList else trees - } - - abstract class TreeTransformer[T >: Untyped] { - var sharedMemo: Map[SharedTree[T], SharedTree[T]] = Map() - - def transform(tree: Tree[T]): Tree[T] = tree match { - case Ident(name) => - tree - case Select(qualifier, name) => - tree.derivedSelect(transform(qualifier), name) - case This(qual) => - tree - case Super(qual, mix) => - tree.derivedSuper(transform(qual), mix) - case Apply(fun, args) => - tree.derivedApply(transform(fun), transform(args)) - case TypeApply(fun, args) => - tree.derivedTypeApply(transform(fun), transform(args)) - case Literal(const) => - tree - case New(tpt) => - tree.derivedNew(transform(tpt)) - case Pair(left, right) => - tree.derivedPair(transform(left), transform(right)) - case Typed(expr, tpt) => - tree.derivedTyped(transform(expr), transform(tpt)) - case NamedArg(name, arg) => - tree.derivedNamedArg(name, transform(arg)) - case Assign(lhs, rhs) => - tree.derivedAssign(transform(lhs), transform(rhs)) - case Block(stats, expr) => - tree.derivedBlock(transformStats(stats), transform(expr)) - case If(cond, thenp, elsep) => - tree.derivedIf(transform(cond), transform(thenp), transform(elsep)) - case Closure(env, meth) => - tree.derivedClosure(transform(env), transformSub(meth)) - case Match(selector, cases) => - tree.derivedMatch(transform(selector), transformSub(cases)) - case CaseDef(pat, guard, body) => - tree.derivedCaseDef(transform(pat), transform(guard), transform(body)) - case Return(expr, from) => - tree.derivedReturn(transform(expr), transformSub(from)) - case Try(block, handler, finalizer) => - tree.derivedTry(transform(block), transform(handler), transform(finalizer)) - case Throw(expr) => - tree.derivedThrow(transform(expr)) - case SeqLiteral(elems) => - tree.derivedSeqLiteral(transform(elems)) - case TypeTree(original) => - tree - case SingletonTypeTree(ref) => - tree.derivedSingletonTypeTree(transform(ref)) - case SelectFromTypeTree(qualifier, name) => - tree.derivedSelectFromTypeTree(transform(qualifier), name) - case AndTypeTree(left, right) => - tree.derivedAndTypeTree(transform(left), transform(right)) - case OrTypeTree(left, right) => - tree.derivedOrTypeTree(transform(left), transform(right)) - case RefinedTypeTree(tpt, refinements) => - tree.derivedRefinedTypeTree(transform(tpt), transformSub(refinements)) - case AppliedTypeTree(tpt, args) => - tree.derivedAppliedTypeTree(transform(tpt), transform(args)) - case TypeBoundsTree(lo, hi) => - tree.derivedTypeBoundsTree(transform(lo), transform(hi)) - case Bind(name, body) => - tree.derivedBind(name, transform(body)) - case Alternative(trees) => - tree.derivedAlternative(transform(trees)) - case UnApply(fun, args) => - tree.derivedUnApply(transform(fun), transform(args)) - case ValDef(mods, name, tpt, rhs) => - tree.derivedValDef(mods, name, transform(tpt), transform(rhs)) - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - tree.derivedDefDef(mods, name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(rhs)) - case tree @ TypeDef(mods, name, rhs) => - tree.derivedTypeDef(mods, name, transform(rhs), tree.tparams) - case Template(constr, parents, self, body) => - tree.derivedTemplate(transformSub(constr), transform(parents), transformSub(self), transformStats(body)) - case Import(expr, selectors) => - tree.derivedImport(transform(expr), selectors) - case PackageDef(pid, stats) => - tree.derivedPackageDef(transformSub(pid), transformStats(stats)) - case Annotated(annot, arg) => - tree.derivedAnnotated(transform(annot), transform(arg)) - case Thicket(trees) => - val trees1 = transform(trees) - if (trees1 eq trees) tree else Thicket(trees1) - case tree @ SharedTree(shared) => - sharedMemo get tree match { - case Some(tree1) => tree1 - case None => - val tree1 = tree.derivedSharedTree(transform(shared)) - sharedMemo = sharedMemo.updated(tree, tree1) - tree1 - } - } - def transformStats(trees: List[Tree[T]]): List[Tree[T]] = - transform(trees) - def transform(trees: List[Tree[T]]): List[Tree[T]] = - flatten(trees mapConserve (transform(_))) - def transformSub(tree: Tree[T]): tree.ThisTree[T] = - transform(tree).asInstanceOf[tree.ThisTree[T]] - def transformSub[TT <: Tree[T]](trees: List[TT]): List[TT] = - transform(trees).asInstanceOf[List[TT]] - } - - 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: Traversable[Tree[T]]): X = (x /: trees)(apply) - def foldOver(x: X, tree: Tree[T]): X = tree match { - case Ident(name) => - x - case Select(qualifier, name) => - this(x, qualifier) - case This(qual) => - x - case Super(qual, mix) => - this(x, qual) - case Apply(fun, args) => - this(this(x, fun), args) - case TypeApply(fun, args) => - this(this(x, fun), args) - case Literal(const) => - x - case New(tpt) => - this(x, tpt) - case Pair(left, right) => - this(this(x, left), right) - case Typed(expr, tpt) => - this(this(x, expr), tpt) - case NamedArg(name, arg) => - this(x, arg) - case Assign(lhs, rhs) => - this(this(x, lhs), rhs) - case Block(stats, expr) => - this(this(x, stats), expr) - case If(cond, thenp, elsep) => - this(this(this(x, cond), thenp), elsep) - case Closure(env, meth) => - this(this(x, env), meth) - case Match(selector, cases) => - this(this(x, selector), cases) - case CaseDef(pat, guard, body) => - this(this(this(x, pat), guard), body) - case Return(expr, from) => - this(this(x, expr), from) - case Try(block, handler, finalizer) => - this(this(this(x, block), handler), finalizer) - case Throw(expr) => - this(x, expr) - case SeqLiteral(elems) => - this(x, elems) - case TypeTree(original) => - x - case SingletonTypeTree(ref) => - this(x, ref) - case SelectFromTypeTree(qualifier, name) => - this(x, qualifier) - case AndTypeTree(left, right) => - this(this(x, left), right) - case OrTypeTree(left, right) => - this(this(x, left), right) - case RefinedTypeTree(tpt, refinements) => - this(this(x, tpt), refinements) - case AppliedTypeTree(tpt, args) => - this(this(x, tpt), args) - case TypeBoundsTree(lo, hi) => - this(this(x, lo), hi) - case Bind(name, body) => - this(x, body) - case Alternative(trees) => - this(x, trees) - case UnApply(fun, args) => - this(this(x, fun), args) - case ValDef(mods, name, tpt, rhs) => - this(this(x, tpt), rhs) - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - this(this((this(x, tparams) /: vparamss)(apply), tpt), rhs) - case TypeDef(mods, name, rhs) => - this(x, rhs) - case Template(constr, parents, self, body) => - this(this(this(this(x, constr), parents), self), body) - case Import(expr, selectors) => - this(x, expr) - case PackageDef(pid, stats) => - this(this(x, pid), stats) - case Annotated(annot, arg) => - this(this(x, annot), arg) - case Thicket(ts) => - this(x, ts) - case tree @ SharedTree(shared) => - sharedMemo get tree match { - case Some(x1) => x1 - case None => - val x1 = this(x, shared) - sharedMemo = sharedMemo.updated(tree, x1) - x1 - } - } - } - - /** Fold `f` over all tree nodes, in depth-first, prefix order */ - 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[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/ast/TypedTrees.scala b/src/dotty/tools/dotc/ast/TypedTrees.scala index c3eadeb8d..e4488ac79 100644 --- a/src/dotty/tools/dotc/ast/TypedTrees.scala +++ b/src/dotty/tools/dotc/ast/TypedTrees.scala @@ -5,28 +5,37 @@ package ast import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ -import CheckTrees._ +import CheckTrees._, Denotations._ -object tpd extends Trees.Instance[Type] { +object tpd extends Trees.Instance[Type] with TypedTreeInfo { - def Modifiers(sym: Symbol)(implicit ctx: Context): Modifiers = Trees.Modifiers[Type]( + def Modifiers(sym: Symbol)(implicit ctx: Context): Modifiers = Modifiers( sym.flags & ModifierFlags, if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY, sym.annotations map (_.tree)) - def Modifiers(flags: FlagSet = EmptyFlags, privateWithin: TypeName = tpnme.EMPTY, annotations: List[Tree] = Nil) = - Trees.Modifiers(flags, privateWithin, annotations) + override def Ident(name: Name)(implicit ctx: Context): Ident = unsupported("Ident") + override def BackquotedIdent(name: Name)(implicit ctx: Context): BackquotedIdent = unsupported("BackquotedIdent") def Ident(tp: NamedType)(implicit ctx: Context): Ident = - Trees.Ident(tp.name).withType(tp.underlyingIfRepeated).checked + super.Ident(tp.name).withType(tp.underlyingIfRepeated).checked + + override def Select(qualifier: Tree, name: Name)(implicit ctx: Context): Select = + Select(qualifier, NamedType(qualifier.tpe, name)) def Select(pre: Tree, tp: NamedType)(implicit ctx: Context): Select = - Trees.Select(pre, tp.name).withType(tp).checked + super.Select(pre, tp.name).withType(tp).checked + + override def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit ctx: Context) = + super.SelectWithSig(qualifier, name, sig) + .withType(TermRef.withSig(qualifier.tpe, name.asTermName, sig)) + + override def This(qual: TypeName)(implicit ctx: Context): This = unsupported("This") def This(cls: ClassSymbol)(implicit ctx: Context): This = - Trees.This(cls.name).withType(cls.thisType).checked + super.This(cls.name).withType(cls.thisType).checked - def Super(qual: Tree, mix: TypeName)(implicit ctx: Context): Super = { + override def Super(qual: Tree, mix: TypeName)(implicit ctx: Context): Super = { val owntype = if (mix.isEmpty) ctx.glb(qual.tpe.parents) else { @@ -34,10 +43,10 @@ object tpd extends Trees.Instance[Type] { check(mixParents.length == 1) mixParents.head } - Trees.Super(qual, mix).withType(SuperType(qual.tpe, owntype)).checked + super.Super(qual, mix).withType(SuperType(qual.tpe, owntype)).checked } - def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply = { + override def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply = { val owntype = fn.tpe.widen match { case fntpe @ MethodType(pnames, ptypes) => check(sameLength(ptypes, args), s"${fn.show}: ${fntpe.show} to ${args.map(_.show).mkString(", ")}") @@ -46,10 +55,10 @@ object tpd extends Trees.Instance[Type] { check(false) ErrorType } - Trees.Apply(fn, args).withType(owntype).checked + super.Apply(fn, args).withType(owntype).checked } - def TypeApply(fn: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = { + override def TypeApply(fn: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = { val owntype = fn.tpe.widen match { case fntpe @ PolyType(pnames) => check(sameLength(pnames, args)) @@ -58,30 +67,32 @@ object tpd extends Trees.Instance[Type] { check(false) ErrorType } - Trees.TypeApply(fn, args).withType(owntype).checked + super.TypeApply(fn, args).withType(owntype).checked } - def Literal(const: Constant)(implicit ctx: Context): Literal = - Trees.Literal(const).withType(const.tpe).checked + override def Literal(const: Constant)(implicit ctx: Context): Literal = + super.Literal(const).withType(const.tpe).checked + + override def New(tpt: Tree)(implicit ctx: Context): New = + super.New(tpt).withType(tpt.tpe).checked - def New(tp: Type)(implicit ctx: Context): New = - Trees.New(TypeTree(tp)).withType(tp).checked + def New(tp: Type)(implicit ctx: Context): New = New(TypeTree(tp)) - def Pair(left: Tree, right: Tree)(implicit ctx: Context): Pair = - Trees.Pair(left, right).withType(defn.PairType.appliedTo(left.tpe, right.tpe)).checked + override def Pair(left: Tree, right: Tree)(implicit ctx: Context): Pair = + super.Pair(left, right).withType(defn.PairType.appliedTo(left.tpe, right.tpe)).checked - def Typed(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed = - Trees.Typed(expr, tpt).withType(tpt.tpe).checked + override def Typed(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed = + super.Typed(expr, tpt).withType(tpt.tpe).checked - def NamedArg(name: TermName, arg: Tree)(implicit ctx: Context) = - Trees.NamedArg(name, arg).withType(arg.tpe).checked + override def NamedArg(name: Name, arg: Tree)(implicit ctx: Context) = + super.NamedArg(name, arg).withType(arg.tpe).checked - def Assign(lhs: Tree, rhs: Tree)(implicit ctx: Context): Assign = - Trees.Assign(lhs, rhs).withType(defn.UnitType).checked + override def Assign(lhs: Tree, rhs: Tree)(implicit ctx: Context): Assign = + super.Assign(lhs, rhs).withType(defn.UnitType).checked - def Block(stats: List[Tree], expr: Tree)(implicit ctx: Context): Block = { + override def Block(stats: List[Tree], expr: Tree)(implicit ctx: Context): Block = { lazy val locals = localSyms(stats).toSet - val blk = Trees.Block(stats, expr) + val blk = super.Block(stats, expr) def widen(tp: Type): Type = tp match { case tp: TermRef if locals contains tp.symbol => widen(tp.info) @@ -93,8 +104,18 @@ object tpd extends Trees.Instance[Type] { def maybeBlock(stats: List[Tree], expr: Tree)(implicit ctx: Context): Tree = if (stats.isEmpty) expr else Block(stats, expr) - def If(cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If = - Trees.If(cond, thenp, elsep).withType(thenp.tpe | elsep.tpe).checked + override def If(cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If = + super.If(cond, thenp, elsep).withType(thenp.tpe | elsep.tpe).checked + + override def Closure(env: List[Tree], meth: RefTree)(implicit ctx: Context): Closure = { + val ownType = meth.tpe.widen match { + case mt @ MethodType(_, formals) => + assert(!mt.isDependent) + val formals1 = formals mapConserve (_.underlyingIfRepeated) + defn.FunctionType(formals1, mt.resultType) + } + super.Closure(env, meth).withType(ownType).checked + } /** A function def * @@ -107,90 +128,97 @@ object tpd extends Trees.Instance[Type] { * where the closure's type is the target type of the expression (FunctionN, unless * otherwise specified). */ - def Closure(meth: TermSymbol, bodyFn: List[Tree] => Tree, target: Type = NoType)(implicit ctx: Context): Block = { - val funtpe = - if (target.exists) target - else meth.info match { - case mt @ MethodType(_, formals) => - assert(!mt.isDependent) - val formals1 = formals mapConserve (_.underlyingIfRepeated) - defn.FunctionType(formals1, mt.resultType) - } + def Closure(meth: TermSymbol, bodyFn: List[Tree] => Tree)(implicit ctx: Context): Block = { val rhsFn: List[List[Tree]] => Tree = { case args :: Nil => bodyFn(args) } Block( DefDef(meth, rhsFn) :: Nil, - Trees.Closure(Nil, Ident(TermRef.withSym(NoPrefix, meth)))).withType(funtpe).checked + Closure(Nil, Ident(TermRef.withSym(NoPrefix, meth)))) } - def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = - Trees.Match(selector, cases).withType(ctx.lub(cases map (_.body.tpe))).checked + override def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = + super.Match(selector, cases).withType(ctx.lub(cases map (_.body.tpe))).checked - def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef = - Trees.CaseDef(pat, guard, body).withType(body.tpe).checked + override def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef = + super.CaseDef(pat, guard, body).withType(body.tpe).checked - def Return(expr: Tree, from: Ident)(implicit ctx: Context): Return = - Trees.Return(expr, from).withType(defn.NothingType).checked + override def Return(expr: Tree, from: Tree)(implicit ctx: Context): Return = + super.Return(expr, from).withType(defn.NothingType).checked - def Try(block: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): Try = - Trees.Try(block, handler, finalizer).withType(block.tpe | handler.tpe).checked + override def Try(block: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): Try = + super.Try(block, handler, finalizer).withType(block.tpe | handler.tpe).checked - def Throw(expr: Tree)(implicit ctx: Context): Throw = - Trees.Throw(expr).withType(defn.NothingType).checked + override def Throw(expr: Tree)(implicit ctx: Context): Throw = + super.Throw(expr).withType(defn.NothingType).checked - def SeqLiteral(tpe: Type, elems: List[Tree])(implicit ctx: Context): SeqLiteral = - Trees.SeqLiteral(elems).withType(tpe).checked - - def SeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral = + override def SeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral = SeqLiteral(defn.SeqClass.typeConstructor.appliedTo( ctx.lub(elems map (_.tpe)) :: Nil), elems) + // TODO: Split into Java/Scala eq literals + def SeqLiteral(tpe: Type, elems: List[Tree])(implicit ctx: Context): SeqLiteral = + super.SeqLiteral(elems).withType(tpe).checked + + override def TypeTree(): TypeTree = unsupported("TypeTree()") + + override def TypeTree(original: Tree)(implicit ctx: Context): TypeTree = + TypeTree(original.tpe, original) + def TypeTree(tp: Type, original: Tree = EmptyTree)(implicit ctx: Context): TypeTree = - Trees.TypeTree(original).withType(tp).checked + super.TypeTree(original).withType(tp).checked + + override def SingletonTypeTree(ref: Tree)(implicit ctx: Context): SingletonTypeTree = + super.SingletonTypeTree(ref).withType(ref.tpe).checked - def SingletonTypeTree(ref: Tree)(implicit ctx: Context): SingletonTypeTree = - Trees.SingletonTypeTree(ref).withType(ref.tpe).checked + override def SelectFromTypeTree(qualifier: Tree, name: Name)(implicit ctx: Context): SelectFromTypeTree = + SelectFromTypeTree(qualifier, NamedType(qualifier.tpe, name)) def SelectFromTypeTree(qualifier: Tree, tp: NamedType)(implicit ctx: Context): SelectFromTypeTree = - Trees.SelectFromTypeTree(qualifier, tp.name).withType(tp).checked + super.SelectFromTypeTree(qualifier, tp.name).withType(tp).checked - def AndTypeTree(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = - Trees.AndTypeTree(left, right).withType(left.tpe & right.tpe).checked + override def AndTypeTree(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = + super.AndTypeTree(left, right).withType(left.tpe & right.tpe).checked - def OrTypeTree(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = - Trees.OrTypeTree(left, right).withType(left.tpe | right.tpe).checked + override def OrTypeTree(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = + super.OrTypeTree(left, right).withType(left.tpe | right.tpe).checked - def RefinedTypeTree(tpt: Tree, refinements: List[DefTree])(implicit ctx: Context): RefinedTypeTree = { + override def RefinedTypeTree(tpt: Tree, refinements: List[Tree])(implicit ctx: Context): RefinedTypeTree = { def refineType(tp: Type, refinement: Symbol): Type = RefinedType(tp, refinement.name, refinement.info) - Trees.RefinedTypeTree(tpt, refinements) + super.RefinedTypeTree(tpt, refinements) .withType((tpt.tpe /: (refinements map (_.symbol)))(refineType)).checked } def refineType(tp: Type, refinement: Symbol)(implicit ctx: Context): Type = RefinedType(tp, refinement.name, refinement.info) - def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = - Trees.AppliedTypeTree(tpt, args).withType(tpt.tpe.appliedTo(args map (_.tpe))).checked + override def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = + super.AppliedTypeTree(tpt, args).withType(tpt.tpe.appliedTo(args map (_.tpe))).checked - def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = - Trees.TypeBoundsTree(lo, hi).withType(TypeBounds(lo.tpe, hi.tpe)).checked + override def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = + super.TypeBoundsTree(lo, hi).withType(TypeBounds(lo.tpe, hi.tpe)).checked + + override def Bind(name: Name, body: Tree)(implicit ctx: Context): Bind = unsupported("Bind") def Bind(sym: TermSymbol, body: Tree)(implicit ctx: Context): Bind = - Trees.Bind(sym.name, body).withType(refType(sym)).checked + super.Bind(sym.name, body).withType(refType(sym)).checked - def Alternative(trees: List[Tree])(implicit ctx: Context): Alternative = - Trees.Alternative(trees).withType(ctx.lub(trees map (_.tpe))).checked + override def Alternative(trees: List[Tree])(implicit ctx: Context): Alternative = + super.Alternative(trees).withType(ctx.lub(trees map (_.tpe))).checked - def UnApply(fun: Tree, args: List[Tree])(implicit ctx: Context): UnApply = { + override def UnApply(fun: Tree, args: List[Tree])(implicit ctx: Context): UnApply = { val owntype = fun.tpe.widen match { case MethodType(_, paramType :: Nil) => paramType case _ => check(false); ErrorType } - Trees.UnApply(fun, args).withType(owntype).checked + super.UnApply(fun, args).withType(owntype).checked } + override def ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree)(implicit ctx: Context): ValDef = unsupported("ValDef") + def ValDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): ValDef = - Trees.ValDef(Modifiers(sym), sym.name, TypeTree(sym.info), rhs).withType(refType(sym)).checked + super.ValDef(Modifiers(sym), sym.name, TypeTree(sym.info), rhs).withType(refType(sym)).checked + + override def DefDef(mods: Modifiers, name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree)(implicit ctx: Context): DefDef = unsupported("DefDef") def DefDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef = DefDef(sym, Function.const(rhs) _) @@ -215,14 +243,16 @@ object tpd extends Trees.Instance[Type] { } val (vparamss, rtp) = valueParamss(mtp) val argss = vparamss map (_ map (vparam => Ident(vparam.symRef))) - Trees.DefDef( + super.DefDef( Modifiers(sym), sym.name, tparams map TypeDef, vparamss map (_ map (ValDef(_))), TypeTree(rtp), rhsFn(argss)) .withType(refType(sym)).checked } + override def TypeDef(mods: Modifiers, name: TypeName, rhs: Tree)(implicit ctx: Context): TypeDef = unsupported("TypeDef") + def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef = - Trees.TypeDef(Modifiers(sym), sym.name, TypeTree(sym.info)) + super.TypeDef(Modifiers(sym), sym.name, TypeTree(sym.info)) .withType(refType(sym)).checked def ClassDef(cls: ClassSymbol, typeParams: List[TypeSymbol], constr: DefDef, body: List[Tree])(implicit ctx: Context): TypeDef = { @@ -241,32 +271,29 @@ object tpd extends Trees.Instance[Type] { val findLocalDummy = new FindLocalDummyAccumulator(cls) val localDummy = ((NoSymbol: Symbol) /: body)(findLocalDummy) .orElse(ctx.newLocalDummy(cls)) - val impl = Trees.Template(constr, parents, selfType, rest) + val impl = super.Template(constr, parents, selfType, rest) .withType(refType(localDummy)).checked - Trees.TypeDef(Modifiers(cls), cls.name, impl) // !!! todo: revise + super.TypeDef(Modifiers(cls), cls.name, impl) // !!! todo: revise .withType(refType(cls)).checked } - def Import(expr: Tree, selectors: List[untpd.Tree])(implicit ctx: Context): Import = - Trees.Import(expr, selectors).withType(refType(ctx.newImportSymbol(SharedTree(expr)))).checked + override def Import(expr: Tree, selectors: List[untpd.Tree])(implicit ctx: Context): Import = + super.Import(expr, selectors).withType(refType(ctx.newImportSymbol(SharedTree(expr)))).checked - def PackageDef(pid: RefTree, stats: List[Tree])(implicit ctx: Context): PackageDef = - Trees.PackageDef(pid, stats).withType(refType(pid.symbol)).checked + override def PackageDef(pid: RefTree, stats: List[Tree])(implicit ctx: Context): PackageDef = + super.PackageDef(pid, stats).withType(refType(pid.symbol)).checked - def Annotated(annot: Tree, arg: Tree)(implicit ctx: Context): Annotated = - Trees.Annotated(annot, arg).withType(AnnotatedType(Annotation(annot), arg.tpe)).checked + override def Annotated(annot: Tree, arg: Tree)(implicit ctx: Context): Annotated = + super.Annotated(annot, arg).withType(AnnotatedType(Annotation(annot), arg.tpe)).checked - val EmptyTree: Tree = emptyTree[Type]() + override def SharedTree(tree: Tree)(implicit ctx: Context): SharedTree = + Trees.SharedTree(tree).withType(tree.tpe) - val EmptyValDef: ValDef = Trees.EmptyValDef().withType(NoType) - def SharedTree(tree: Tree): SharedTree = - Trees.SharedTree(tree).withType(tree.tpe) + // ------ Making references ------------------------------------------------------ def refType(sym: Symbol)(implicit ctx: Context): NamedType = NamedType.withSym(sym.owner.thisType, sym) - // ------ Creating typed equivalents of trees that exist only in untyped form ------- - /** A tree representing the same reference as the given type */ def ref(tp: NamedType)(implicit ctx: Context): NameTree = if (tp.symbol.isStatic) Ident(tp) @@ -278,6 +305,8 @@ object tpd extends Trees.Instance[Type] { def ref(sym: Symbol)(implicit ctx: Context): tpd.NameTree = ref(NamedType(sym.owner.thisType, sym.name).withDenot(sym)) + // ------ Creating typed equivalents of trees that exist only in untyped form ------- + /** new C(args) */ def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = Apply( @@ -331,6 +360,13 @@ object tpd extends Trees.Instance[Type] { } else foldOver(sym, tree) } + override val cpy = new TypedTreeCopier + + class TypedTreeCopier extends TreeCopier { + def postProcess(tree: Tree, copied: untpd.Tree): copied.ThisTree[Type] = + copied.withType(tree.tpe) + } + implicit class TreeOps[ThisTree <: tpd.Tree](val tree: ThisTree) extends AnyVal { def isValue(implicit ctx: Context): Boolean = @@ -366,7 +402,7 @@ object tpd extends Trees.Instance[Type] { } class TreeMapper(val typeMap: TypeMap = IdentityTypeMap, val ownerMap: Symbol => Symbol = identity)(implicit ctx: Context) extends TreeTransformer { - override def transform(tree: tpd.Tree): tpd.Tree = super.transform { + override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = super.transform { tree.withType(typeMap(tree.tpe)) match { case bind: tpd.Bind => val sym = bind.symbol @@ -380,7 +416,7 @@ object tpd extends Trees.Instance[Type] { tree1 } } - override def transformStats(trees: List[tpd.Tree]) = { + override def transformStats(trees: List[tpd.Tree])(implicit ctx: Context) = { val locals = localSyms(trees) val mapped = ctx.mapSymbols(locals, typeMap, ownerMap) if (locals eq mapped) super.transform(trees) @@ -406,10 +442,5 @@ object tpd extends Trees.Instance[Type] { def localSyms(stats: List[tpd.Tree])(implicit ctx: Context): List[Symbol] = for (stat <- stats if (stat.isDef)) yield stat.symbol - - type TreeAccumulator[U] = Trees.TreeAccumulator[U, Type] - type TreeCopier = Trees.TreeCopier[Type] - type TreeTransformer = Trees.TreeTransformer[Type] - } diff --git a/src/dotty/tools/dotc/ast/UntypedTrees.scala b/src/dotty/tools/dotc/ast/UntypedTrees.scala index 9449392dd..f8a03385e 100644 --- a/src/dotty/tools/dotc/ast/UntypedTrees.scala +++ b/src/dotty/tools/dotc/ast/UntypedTrees.scala @@ -5,14 +5,11 @@ package ast import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ -import TreeInfo._ import Decorators._ import language.higherKinds import collection.mutable.ListBuffer -object untpd extends Trees.Instance[Untyped] { - - val EmptyTree = emptyTree[Untyped]() +object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] { // ----- Tree cases that exist in untyped form only ------------------ @@ -22,8 +19,8 @@ object untpd extends Trees.Instance[Untyped] { /** mods object name impl */ case class ModuleDef(mods: Modifiers, name: TermName, impl: Template) extends MemberDef { - type ThisTree[T >: Untyped] <: Trees.NameTree[T] with Trees.MemberDef[T] with ModuleDef - def withName(name: Name) = this.derivedModuleDef(mods, name.toTermName, impl) + type ThisTree[-T >: Untyped] <: Trees.NameTree[T] with Trees.MemberDef[T] with ModuleDef + def withName(name: Name)(implicit ctx: Context) = cpy.ModuleDef(this, mods, name.toTermName, impl) } case class SymbolLit(str: String) extends Tree @@ -44,24 +41,32 @@ object untpd extends Trees.Instance[Untyped] { case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree) extends Tree class PolyTypeDef(mods: Modifiers, name: TypeName, override val tparams: List[TypeDef], rhs: Tree) - extends TypeDef(mods, name, rhs) + extends TypeDef(mods, name, rhs) { + override def withName(name: Name)(implicit ctx: Context) = cpy.PolyTypeDef(this, mods, name.toTypeName, tparams, rhs) + } + +// ------ Additional creation methods for untyped only ----------------- + + def Literal(const: Constant) = new Literal(const) - def typeDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree): TypeDef = + def TypeTree(tpe: Type)(implicit ctx: Context): TypedSplice = TypedSplice(TypeTree().withType(tpe)) + + def TypeDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree)(implicit ctx: Context): TypeDef = if (tparams.isEmpty) TypeDef(mods, name, rhs) else new PolyTypeDef(mods, name, tparams, rhs) // ------ Untyped tree values and creation methods --------------------- - val unitLiteral = Literal(Constant()) + def unitLiteral(implicit ctx: Context) = Literal(Constant()) def ref(tp: NamedType)(implicit ctx: Context): Tree = TypedSplice(tpd.ref(tp)) def scalaUnit(implicit ctx: Context) = ref(defn.UnitClass.typeConstructor) - def makeConstructor(mods: Modifiers, tparams: List[TypeDef], vparamss: List[List[ValDef]], rhs: Tree = EmptyTree): DefDef = + def makeConstructor(mods: Modifiers, tparams: List[TypeDef], vparamss: List[List[ValDef]], rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef = DefDef(mods, nme.CONSTRUCTOR, tparams, vparamss, TypeTree(), rhs) - def emptyConstructor: DefDef = + def emptyConstructor(implicit ctx: Context): DefDef = makeConstructor(Modifiers(), Nil, Nil) def makeSelfDef(name: TermName, tpt: Tree)(implicit ctx: Context) = @@ -77,13 +82,13 @@ object untpd extends Trees.Instance[Untyped] { case _ => Tuple(ts) } - def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = Modifiers()): ValDef = - ValDef(mods | Param, pname, tpe, emptyTree()) + def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = Modifiers())(implicit ctx: Context): ValDef = + ValDef(mods | Param, pname, tpe, EmptyTree) def makeSyntheticParameter(n: Int = 1, tpt: Tree = EmptyTree)(implicit ctx: Context): ValDef = ValDef(Modifiers(SyntheticTermParam), nme.syntheticParamName(n), TypeTree(), EmptyTree) - def refOfDef(tree: NameTree) = Ident(tree.name) + def refOfDef(tree: NameTree)(implicit ctx: Context) = Ident(tree.name) // ------- A decorator for producing a path to a location -------------- @@ -102,125 +107,130 @@ object untpd extends Trees.Instance[Untyped] { // --------- Copier/Transformer/Accumulator classes for untyped trees ----- - implicit class UntypedTreeCopier(val tree: Tree) extends AnyVal { - def derivedModuleDef(mods: Modifiers, name: TermName, impl: Template) = tree match { + override val cpy: UntypedTreeCopier = new UntypedTreeCopier + + class UntypedTreeCopier extends TreeCopier { + def postProcess(tree: Tree, copied: Tree): copied.ThisTree[Untyped] = + copied.asInstanceOf[copied.ThisTree[Untyped]] + + def ModuleDef(tree: Tree, mods: Modifiers, name: TermName, impl: Template) = tree match { case tree: ModuleDef if (mods eq tree.mods) && (name eq tree.name) && (impl eq tree.impl) => tree - case _ => ModuleDef(mods, name, impl).withPos(tree.pos) + case _ => untpd.ModuleDef(mods, name, impl).withPos(tree.pos) } - def derivedPolyTypeDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree) = tree match { + def PolyTypeDef(tree: Tree, mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree) = tree match { case tree: PolyTypeDef if (mods eq tree.mods) && (name eq tree.name) && (tparams eq tree.tparams) && (rhs eq tree.rhs) => tree case _ => new PolyTypeDef(mods, name, tparams, rhs).withPos(tree.pos) } - def derivedSymbolLit(str: String) = tree match { + def SymbolLit(tree: Tree, str: String) = tree match { case tree: SymbolLit if (str == tree.str) => tree - case _ => SymbolLit(str).withPos(tree.pos) + case _ => untpd.SymbolLit(str).withPos(tree.pos) } - def derivedInterpolatedString(id: TermName, strings: List[Literal], elems: List[Tree]) = tree match { + def InterpolatedString(tree: Tree, id: TermName, strings: List[Literal], elems: List[Tree]) = tree match { case tree: InterpolatedString if (id eq tree.id) && (strings eq tree.strings) && (elems eq tree.elems) => tree - case _ => InterpolatedString(id, strings, elems).withPos(tree.pos) + case _ => untpd.InterpolatedString(id, strings, elems).withPos(tree.pos) } - def derivedFunction(args: List[Tree], body: Tree) = tree match { + def Function(tree: Tree, args: List[Tree], body: Tree) = tree match { case tree: Function if (args eq tree.args) && (body eq tree.body) => tree - case _ => Function(args, body).withPos(tree.pos) + case _ => untpd.Function(args, body).withPos(tree.pos) } - def derivedInfixOp(left: Tree, op: Name, right: Tree) = tree match { + def InfixOp(tree: Tree, left: Tree, op: Name, right: Tree) = tree match { case tree: InfixOp if (left eq tree.left) && (op eq tree.op) && (right eq tree.right) => tree - case _ => InfixOp(left, op, right).withPos(tree.pos) + case _ => untpd.InfixOp(left, op, right).withPos(tree.pos) } - def derivedPostfixOp(od: Tree, op: Name) = tree match { + def PostfixOp(tree: Tree, od: Tree, op: Name) = tree match { case tree: PostfixOp if (od eq tree.od) && (op eq tree.op) => tree - case _ => PostfixOp(od, op).withPos(tree.pos) + case _ => untpd.PostfixOp(od, op).withPos(tree.pos) } - def derivedPrefixOp(op: Name, od: Tree) = tree match { + def PrefixOp(tree: Tree, op: Name, od: Tree) = tree match { case tree: PrefixOp if (op eq tree.op) && (od eq tree.od) => tree - case _ => PrefixOp(op, od).withPos(tree.pos) + case _ => untpd.PrefixOp(op, od).withPos(tree.pos) } - def derivedParens(t: Tree) = tree match { + def Parens(tree: Tree, t: Tree) = tree match { case tree: Parens if (t eq tree.t) => tree - case _ => Parens(t).withPos(tree.pos) + case _ => untpd.Parens(t).withPos(tree.pos) } - def derivedTuple(trees: List[Tree]) = tree match { + def Tuple(tree: Tree, trees: List[Tree]) = tree match { case tree: Tuple if (trees eq tree.trees) => tree - case _ => Tuple(trees).withPos(tree.pos) + case _ => untpd.Tuple(trees).withPos(tree.pos) } - def derivedWhileDo(cond: Tree, body: Tree) = tree match { + def WhileDo(tree: Tree, cond: Tree, body: Tree) = tree match { case tree: WhileDo if (cond eq tree.cond) && (body eq tree.body) => tree - case _ => WhileDo(cond, body).withPos(tree.pos) + case _ => untpd.WhileDo(cond, body).withPos(tree.pos) } - def derivedDoWhile(body: Tree, cond: Tree) = tree match { + def DoWhile(tree: Tree, body: Tree, cond: Tree) = tree match { case tree: DoWhile if (body eq tree.body) && (cond eq tree.cond) => tree - case _ => DoWhile(body, cond).withPos(tree.pos) + case _ => untpd.DoWhile(body, cond).withPos(tree.pos) } - def derivedForYield(enums: List[Tree], expr: Tree) = tree match { + def ForYield(tree: Tree, enums: List[Tree], expr: Tree) = tree match { case tree: ForYield if (enums eq tree.enums) && (expr eq tree.expr) => tree - case _ => ForYield(enums, expr).withPos(tree.pos) + case _ => untpd.ForYield(enums, expr).withPos(tree.pos) } - def derivedForDo(enums: List[Tree], body: Tree) = tree match { + def ForDo(tree: Tree, enums: List[Tree], body: Tree) = tree match { case tree: ForDo if (enums eq tree.enums) && (body eq tree.body) => tree - case _ => ForDo(enums, body).withPos(tree.pos) + case _ => untpd.ForDo(enums, body).withPos(tree.pos) } - def derivedGenFrom(pat: Tree, expr: Tree) = tree match { + def GenFrom(tree: Tree, pat: Tree, expr: Tree) = tree match { case tree: GenFrom if (pat eq tree.pat) && (expr eq tree.expr) => tree - case _ => GenFrom(pat, expr).withPos(tree.pos) + case _ => untpd.GenFrom(pat, expr).withPos(tree.pos) } - def derivedGenAlias(pat: Tree, expr: Tree) = tree match { + def GenAlias(tree: Tree, pat: Tree, expr: Tree) = tree match { case tree: GenAlias if (pat eq tree.pat) && (expr eq tree.expr) => tree - case _ => GenAlias(pat, expr).withPos(tree.pos) + case _ => untpd.GenAlias(pat, expr).withPos(tree.pos) } - def derivedContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree]) = tree match { + def ContextBounds(tree: Tree, bounds: TypeBoundsTree, cxBounds: List[Tree]) = tree match { case tree: ContextBounds if (bounds eq tree.bounds) && (cxBounds eq tree.cxBounds) => tree - case _ => ContextBounds(bounds, cxBounds).withPos(tree.pos) + case _ => untpd.ContextBounds(bounds, cxBounds).withPos(tree.pos) } - def derivedPatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree) = tree match { + def PatDef(tree: Tree, mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree) = tree match { case tree: PatDef if (mods eq tree.mods) && (pats eq tree.pats) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree - case _ => PatDef(mods, pats, tpt, rhs).withPos(tree.pos) + case _ => untpd.PatDef(mods, pats, tpt, rhs).withPos(tree.pos) } } - abstract class TreeTransformer extends Trees.TreeTransformer[Untyped] { - override def transform(tree: Tree): Tree = tree match { + abstract class UntypedTreeTransformer(cpy: UntypedTreeCopier = untpd.cpy) extends TreeTransformer(cpy) { + override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match { case ModuleDef(mods, name, impl) => - tree.derivedModuleDef(mods, name, transformSub(impl)) + cpy.ModuleDef(tree, mods, name, transformSub(impl)) case SymbolLit(str) => - tree.derivedSymbolLit(str) + cpy.SymbolLit(tree, str) case InterpolatedString(id, strings, elems) => - tree.derivedInterpolatedString(id, transformSub(strings), transform(elems)) + cpy.InterpolatedString(tree, id, transformSub(strings), transform(elems)) case Function(args, body) => - tree.derivedFunction(transform(args), transform(body)) + cpy.Function(tree, transform(args), transform(body)) case InfixOp(left, op, right) => - tree.derivedInfixOp(transform(left), op, transform(right)) + cpy.InfixOp(tree, transform(left), op, transform(right)) case PostfixOp(od, op) => - tree.derivedPostfixOp(transform(od), op) + cpy.PostfixOp(tree, transform(od), op) case PrefixOp(op, od) => - tree.derivedPrefixOp(op, transform(od)) + cpy.PrefixOp(tree, op, transform(od)) case Parens(t) => - tree.derivedParens(transform(t)) + cpy.Parens(tree, transform(t)) case Tuple(trees) => - tree.derivedTuple(transform(trees)) + cpy.Tuple(tree, transform(trees)) case WhileDo(cond, body) => - tree.derivedWhileDo(transform(cond), transform(body)) + cpy.WhileDo(tree, transform(cond), transform(body)) case DoWhile(body, cond) => - tree.derivedDoWhile(transform(body), transform(cond)) + cpy.DoWhile(tree, transform(body), transform(cond)) case ForYield(enums, expr) => - tree.derivedForYield(transform(enums), transform(expr)) + cpy.ForYield(tree, transform(enums), transform(expr)) case ForDo(enums, body) => - tree.derivedForDo(transform(enums), transform(body)) + cpy.ForDo(tree, transform(enums), transform(body)) case GenFrom(pat, expr) => - tree.derivedGenFrom(transform(pat), transform(expr)) + cpy.GenFrom(tree, transform(pat), transform(expr)) case GenAlias(pat, expr) => - tree.derivedGenAlias(transform(pat), transform(expr)) + cpy.GenAlias(tree, transform(pat), transform(expr)) case ContextBounds(bounds, cxBounds) => - tree.derivedContextBounds(transformSub(bounds), transform(cxBounds)) + cpy.ContextBounds(tree, transformSub(bounds), transform(cxBounds)) case PatDef(mods, pats, tpt, rhs) => - tree.derivedPatDef(mods, transform(pats), transform(tpt), transform(rhs)) + cpy.PatDef(tree, mods, transform(pats), transform(tpt), transform(rhs)) case tree: PolyTypeDef => - tree.derivedPolyTypeDef(tree.mods, tree.name, transformSub(tree.tparams), transform(tree.rhs)) + cpy.PolyTypeDef(tree, tree.mods, tree.name, transformSub(tree.tparams), transform(tree.rhs)) case _ => super.transform(tree) } } - abstract class TreeAccumulator[X] extends Trees.TreeAccumulator[X, Untyped] { + abstract class UntypedTreeAccumulator[X] extends TreeAccumulator[X] { override def foldOver(x: X, tree: Tree): X = tree match { case ModuleDef(mods, name, impl) => this(x, impl) diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index 133db4268..a488e0e18 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -10,7 +10,7 @@ import java.lang.Double.longBitsToDouble import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._ import util.Positions._ -import ast.Trees, ast.tpd._ +import ast.Trees, ast.tpd._, ast.untpd import printing.Texts._ import printing.Printer import io.AbstractFile @@ -938,9 +938,9 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: val selectors = until(end, () => { val fromName = readNameRef() val toName = readNameRef() - val from = Trees.Ident(fromName) - val to = Trees.Ident(toName) - if (toName.isEmpty) from else Trees.Pair(from, Trees.Ident(toName)) + val from = untpd.Ident(fromName) + val to = untpd.Ident(toName) + if (toName.isEmpty) from else untpd.Pair(from, untpd.Ident(toName)) }) Import(expr, selectors) @@ -950,7 +950,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: val parents = times(readNat(), readTreeRef) val self = readValDefRef() val body = until(end, readTreeRef) - Trees.Template[Type](???, parents, self, body) // !!! TODO: pull out primary constructor + untpd.Template(???, parents, self, body) // !!! TODO: pull out primary constructor .withType(refType(symbol)) case BLOCKtree => @@ -992,7 +992,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: val vparams = until(end, readValDefRef) val applyType = MethodType(vparams map (_.name), vparams map (_.tpt.tpe), body.tpe) val applyMeth = cctx.newSymbol(symbol.owner, nme.apply, Method, applyType) - Closure(applyMeth, Function.const(body.changeOwner(symbol, applyMeth)), tpe) + Closure(applyMeth, Function.const(body.changeOwner(symbol, applyMeth)) _) case ASSIGNtree => val lhs = readTreeRef() diff --git a/src/dotty/tools/dotc/parsing/MarkupParsers.scala b/src/dotty/tools/dotc/parsing/MarkupParsers.scala index f74ebb509..ef9c81cdb 100644 --- a/src/dotty/tools/dotc/parsing/MarkupParsers.scala +++ b/src/dotty/tools/dotc/parsing/MarkupParsers.scala @@ -7,7 +7,6 @@ import mutable.{ Buffer, ArrayBuffer, ListBuffer } import scala.util.control.ControlThrowable import util.SourceFile import scala.xml.{ Text, TextBuffer } -import scala.xml.parsing.MarkupParserCommon import scala.xml.Utility.{ isNameStart, isNameChar, isSpace } import scala.reflect.internal.Chars.{ SU, LF } import Parsers._ diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 04932c7f0..abba1be37 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -276,9 +276,9 @@ object Parsers { */ def convertToTypeId(tree: Tree): Tree = tree match { case id @ Ident(name) => - id.derivedIdent(name.toTypeName) + cpy.Ident(id, name.toTypeName) case id @ Select(qual, name) => - id.derivedSelect(qual, name.toTypeName) + cpy.Select(id, qual, name.toTypeName) case _ => syntaxError("identifier expected", tree.pos) tree @@ -336,7 +336,7 @@ object Parsers { var opStack: List[OpInfo] = Nil def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean) = - if (TreeInfo.isLeftAssoc(op) != leftAssoc) + if (isLeftAssoc(op) != leftAssoc) syntaxError( "left- and right-associative operators with same precedence may not be mixed", offset) @@ -376,7 +376,7 @@ object Parsers { var top = first while (isIdent && in.name != notAnOperator) { val op = in.name - top = reduceStack(base, top, precedence(op), TreeInfo.isLeftAssoc(op)) + top = reduceStack(base, top, precedence(op), isLeftAssoc(op)) opStack = OpInfo(top, op, in.offset) :: opStack ident() newLineOptWhenFollowing(canStartOperand) @@ -417,7 +417,7 @@ object Parsers { } private def makeIdent(tok: Token, name: Name) = - if (tok == BACKQUOTED_IDENT) new BackquotedIdent(name) + if (tok == BACKQUOTED_IDENT) BackquotedIdent(name) else Ident(name) /** IdentOrWildcard ::= id | `_' */ @@ -618,7 +618,7 @@ object Parsers { atPos(start, in.skipToken()) { Function(ts, typ()) } else { for (t <- ts) - if (TreeInfo.isByNameParamType(t)) + if (isByNameParamType(t)) syntaxError("no by-name parameter type allowed here", t.pos) val tuple = atPos(start) { makeTupleOrParens(ts) } infixTypeRest(refinedTypeRest(withTypeRest(simpleTypeRest(tuple)))) @@ -1047,7 +1047,7 @@ object Parsers { if (in.token == LBRACE) blockExpr() :: Nil else parArgumentExprs() val argumentExpr = () => exprInParens() match { - case a @ Assign(Ident(id), rhs) => a.derivedNamedArg(id, rhs) + case a @ Assign(Ident(id), rhs) => cpy.NamedArg(a, id, rhs) case e => e } @@ -1192,14 +1192,14 @@ object Parsers { */ def pattern1(): Tree = { val p = pattern2() - if (TreeInfo.isVarPattern(p) && in.token == COLON) ascription(p, Location.InPattern) + if (isVarPattern(p) && in.token == COLON) ascription(p, Location.InPattern) else p } /** Pattern2 ::= [varid `@'] InfixPattern */ val pattern2 = () => infixPattern() match { - case p @ Ident(name) if TreeInfo.isVarPattern(p) && in.token == AT => + case p @ Ident(name) if isVarPattern(p) && in.token == AT => atPos(p.pos.start, in.skipToken()) { Bind(name, infixPattern()) } case p => p @@ -1355,8 +1355,8 @@ object Parsers { /** Adjust start of annotation or constructor to position of preceding @ or new */ def adjustStart(start: Offset)(tree: Tree): Tree = { val tree1 = tree match { - case Apply(fn, args) => tree.derivedApply(adjustStart(start)(fn), args) - case Select(qual, name) => tree.derivedSelect(adjustStart(start)(qual), name) + case Apply(fn, args) => cpy.Apply(tree, adjustStart(start)(fn), args) + case Select(qual, name) => cpy.Select(tree, adjustStart(start)(qual), name) case _ => tree } if (start < tree1.pos.start) tree1.withPos(tree1.pos.withStart(start)) @@ -1427,7 +1427,7 @@ object Parsers { val bounds = if (isConcreteOwner) typeParamBounds(name) else typeBounds() - typeDef(mods, name, hkparams, bounds) + TypeDef(mods, name, hkparams, bounds) } } commaSeparated(typeParam) @@ -1546,7 +1546,7 @@ object Parsers { imp case sel @ Select(qual, name) => val selector = atPos(sel.pos.point) { Ident(name) } - sel.derivedImport(qual, selector :: Nil) + cpy.Import(sel, qual, selector :: Nil) case t => accept(DOT) Import(t, Ident(nme.WILDCARD) :: Nil) @@ -1565,7 +1565,7 @@ object Parsers { else { val sel = importSelector() sel :: { - if (!TreeInfo.isWildcardArg(sel) && in.token == COMMA) { + if (!isWildcardArg(sel) && in.token == COMMA) { in.nextToken() importSelectors() } @@ -1628,7 +1628,7 @@ object Parsers { } } else EmptyTree lhs match { - case (id @ Ident(name: TermName)) :: Nil => id.derivedValDef(mods, name, tpt, rhs) + case (id @ Ident(name: TermName)) :: Nil => cpy.ValDef(id, mods, name, tpt, rhs) case _ => PatDef(mods, lhs, tpt, rhs) } } @@ -1708,9 +1708,9 @@ object Parsers { in.token match { case EQUALS => in.nextToken() - typeDef(mods, name, tparams, typ()) + TypeDef(mods, name, tparams, typ()) case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | EOF => - typeDef(mods, name, tparams, typeBounds()) + TypeDef(mods, name, tparams, typeBounds()) case _ => syntaxErrorOrIncomplete("`=', `>:', or `<:' expected") EmptyTree @@ -1783,7 +1783,7 @@ object Parsers { */ def template(constr: DefDef): Template = templateOrNew(constr) match { case impl: Template => impl - case parent => Template(constr, parent :: Nil, EmptyValDef(), Nil) + case parent => Template(constr, parent :: Nil, EmptyValDef, Nil) } /** Same as template, but if {...} is missing and there's only one @@ -1807,14 +1807,14 @@ object Parsers { else { newLineOptWhenFollowedBy(LBRACE) if (in.token == LBRACE) template(constr) - else Template(constr, Nil, EmptyValDef(), Nil).withPos(constr.pos.toSynthetic) + else Template(constr, Nil, EmptyValDef, Nil).withPos(constr.pos.toSynthetic) } /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' */ def templateBodyOpt(constr: DefDef, parents: List[Tree]) = atPos(constr.pos.start) { val (self, stats) = - if (in.token == LBRACE) templateBody() else (EmptyValDef(), Nil) + if (in.token == LBRACE) templateBody() else (EmptyValDef, Nil) Template(constr, parents, self, stats) } @@ -1884,7 +1884,7 @@ object Parsers { * | */ def templateStatSeq(): (ValDef, List[Tree]) = { - var self: ValDef = EmptyValDef() + var self: ValDef = EmptyValDef val stats = new ListBuffer[Tree] if (isExprIntro) { val first = expr1() @@ -2048,6 +2048,6 @@ object Parsers { override def blockExpr(): Tree = skipBraces(EmptyTree) - override def templateBody() = skipBraces((EmptyValDef(), List(EmptyTree))) + override def templateBody() = skipBraces((EmptyValDef, List(EmptyTree))) } } diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index d0b9dc6bd..a8c6d5bcf 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -16,7 +16,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { protected val PrintableFlags = (ModifierFlags | Label | Module).toCommonFlags /** The closest enclosing DefDef, TypeDef, or ClassDef node */ - private var currentOwner: Tree[_ >: Untyped] = emptyTree() + private var currentOwner: untpd.Tree = untpd.EmptyTree def atOwner(owner: Tree[_ >: Untyped])(op: => Text): Text = { val saved = currentOwner diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 3ce735c12..6424b96e4 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -27,7 +27,7 @@ import language.implicitConversions object Applications { - import tpd._ + import tpd.{ cpy => _, _ } private val isNamedArg = (arg: Any) => arg.isInstanceOf[Trees.NamedArg[_]] def hasNamedArg(args: List[Any]) = args exists isNamedArg @@ -44,10 +44,9 @@ object Applications { * 3. there is an implicit conversion from `tp` to `pt`. */ def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean = ( - tp <:< pt - || pt.typeSymbol == defn.ByNameParamClass && tp <:< pt.typeArgs.head - || viewExists(tp, pt) - ) + tp <:< pt + || pt.typeSymbol == defn.ByNameParamClass && tp <:< pt.typeArgs.head + || viewExists(tp, pt)) } /** The normalized form of a type @@ -82,15 +81,15 @@ object Applications { import Applications._ -trait Applications extends Compatibility{ self: Typer => +trait Applications extends Compatibility { self: Typer => import Applications._ - import tpd._ + import tpd.{ cpy => _, _ } + import untpd.cpy private def state(implicit ctx: Context) = ctx.typerState - /** - * @param Arg the type of arguments, could be tpd.Tree, untpd.Tree, or Type + /** @param Arg the type of arguments, could be tpd.Tree, untpd.Tree, or Type * @param methRef the reference to the method of the application * @param funType the type of the function part of the application * @param args the arguments of the application @@ -206,7 +205,7 @@ trait Applications extends Compatibility{ self: Typer => args match { case (arg @ NamedArg(aname, _)) :: args1 => if (namedToArg contains aname) - emptyTree[T]() :: recur(pnames1, args) + genericEmptyTree :: recur(pnames1, args) else { badNamedArg(arg) recur(pnames1, args1) @@ -222,8 +221,7 @@ trait Applications extends Compatibility{ self: Typer => val (namedArgs, otherArgs) = args partition isNamedArg namedArgs foreach badNamedArg otherArgs - } - else args + } else args } recur(methodType.paramNames, args) @@ -289,14 +287,14 @@ trait Applications extends Compatibility{ self: Typer => } def tryDefault(n: Int, args1: List[Arg]): Unit = { - findDefaultGetter(n + TreeInfo.numArgs(normalizedFun)) match { + findDefaultGetter(n + numArgs(normalizedFun)) match { case dref: NamedType => liftFun() addTyped(treeToArg(spliceMeth(Ident(dref), normalizedFun)), formal) matchArgs(args1, formals1, n + 1) case _ => missingArg(n) - } + } } if (formal.isRepeatedParam) @@ -377,7 +375,7 @@ trait Applications extends Compatibility{ self: Typer => */ trait TreeApplication[T >: Untyped] extends Application[Trees.Tree[T]] { type TypeArg = Tree - def isVarArg(arg: Trees.Tree[T]): Boolean = TreeInfo.isWildcardStarArg(arg) + def isVarArg(arg: Trees.Tree[T]): Boolean = isWildcardStarArg(arg) } /** Subclass of Application for applicability tests with trees as arguments. */ @@ -471,7 +469,7 @@ trait Applications extends Compatibility{ self: Typer => typedArgs = args.asInstanceOf[List[Tree]] methodType.instantiate(typedArgs map (_.tpe)) } - val app1 = app.withType(ownType).derivedApply(normalizedFun, typedArgs) + val app1 = cpy.Apply(app, normalizedFun, typedArgs).withType(ownType) if (liftedDefs != null && liftedDefs.nonEmpty) Block(liftedDefs.toList, app1) else app1 } @@ -495,7 +493,7 @@ trait Applications extends Compatibility{ self: Typer => new ApplyToTyped(app, fun, methRef, args, resultType).result def typedApply(fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree = - typedApply(Trees.Apply(untpd.TypedSplice(fun), Nil), fun, methRef, args, resultType) + typedApply(untpd.Apply(untpd.TypedSplice(fun), Nil), fun, methRef, args, resultType) def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { if (ctx.mode is Mode.Pattern) @@ -505,7 +503,7 @@ trait Applications extends Compatibility{ self: Typer => def realApply(implicit ctx: Context) = { val proto = new FunProtoType(tree.args, pt, this) val fun1 = typedExpr(tree.fun, proto) - TreeInfo.methPart(fun1).tpe match { + methPart(fun1).tpe match { case funRef: TermRef => val app = if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt) @@ -525,12 +523,12 @@ trait Applications extends Compatibility{ self: Typer => val lhs1 = typedExpr(lhs) val lifted = new mutable.ListBuffer[Tree] val lhs2 = untpd.TypedSplice(liftApp(lifted, lhs1)) - val assign = Trees.Assign(lhs2, Trees.Apply(Trees.Select(lhs2, name.init), rhss)) + val assign = untpd.Assign(lhs2, untpd.Apply(untpd.Select(lhs2, name.init), rhss)) typed(assign) } realApply - if (TreeInfo.isOpAssign(tree)) + if (untpd.isOpAssign(tree)) tryEither { implicit ctx => realApply } { failed => @@ -555,7 +553,7 @@ trait Applications extends Compatibility{ self: Typer => ctx.error(s"${err.exprStr(typedFn)} does not take type parameters", tree.pos) ErrorType } - tree.withType(ownType).derivedTypeApply(typedFn, typedArgs) + cpy.TypeApply(tree, typedFn, typedArgs).withType(ownType) } def typedUnApply(qual: untpd.Tree, args: List[untpd.Tree], tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { @@ -586,7 +584,7 @@ trait Applications extends Compatibility{ self: Typer => ctx.error(s"${unapplyResult.show} is not a valid result type of an unapply method of an extractor", tree.pos) Nil } - } + } recur(unapplyResult) } @@ -595,13 +593,14 @@ trait Applications extends Compatibility{ self: Typer => val dummyArg = untpd.TypedSplice(dummyTreeOfType(WildcardType)) val unappProto = FunProtoType(dummyArg :: Nil, pt, this) tryEither { - implicit ctx => typedExpr(Trees.Select(qual, nme.unapply), unappProto) + implicit ctx => typedExpr(untpd.Select(qual, nme.unapply), unappProto) } { - s => tryEither { - implicit ctx => typedExpr(Trees.Select(qual, nme.unapplySeq), unappProto) // for backwards compatibility; will be dropped - } { - _ => errorTree(s.value, s"${qual.show} cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method") - } + s => + tryEither { + implicit ctx => typedExpr(untpd.Select(qual, nme.unapplySeq), unappProto) // for backwards compatibility; will be dropped + } { + _ => errorTree(s.value, s"${qual.show} cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method") + } } } fn.tpe.widen match { @@ -610,7 +609,7 @@ trait Applications extends Compatibility{ self: Typer => ownType <:< pt // done for registering the constraints; error message would come later var argTypes = unapplyArgs(ownType) val bunchedArgs = argTypes match { - case argType :: Nil if argType.isRepeatedParam => Trees.SeqLiteral(args) :: Nil + case argType :: Nil if argType.isRepeatedParam => untpd.SeqLiteral(args) :: Nil case _ => args } if (argTypes.length != bunchedArgs.length) { @@ -619,7 +618,7 @@ trait Applications extends Compatibility{ self: Typer => List.fill(argTypes.length - args.length)(WildcardType) } val typedArgs = (bunchedArgs, argTypes).zipped map (typed(_, _)) - Trees.UnApply(fn, typedArgs).withPos(tree.pos).withType(ownType) + untpd.UnApply(fn, typedArgs).withPos(tree.pos).withType(ownType) case et: ErrorType => tree.withType(ErrorType) } @@ -713,7 +712,7 @@ trait Applications extends Compatibility{ self: Typer => best :: asGood(alts1) } - private val dummyTree = Trees.Literal(Constant(null)) + private val dummyTree = untpd.Literal(Constant(null)) def dummyTreeOfType(tp: Type): Tree = dummyTree withType tp /** Resolve overloaded alternative `alts`, given expected type `pt`. */ @@ -735,7 +734,7 @@ trait Applications extends Compatibility{ self: Typer => def treeShape(tree: untpd.Tree): Tree = tree match { case NamedArg(name, arg) => val argShape = treeShape(arg) - tree.withType(argShape.tpe).derivedNamedArg(name, argShape) + cpy.NamedArg(tree, name, argShape).withType(argShape.tpe) case _ => dummyTreeOfType(typeShape(tree)) } @@ -783,7 +782,7 @@ trait Applications extends Compatibility{ self: Typer => } case pt @ PolyProtoType(nargs, _) => - alts filter ( alt => alt.widen match { + alts filter (alt => alt.widen match { case PolyType(pnames) if pnames.length == nargs => true case _ => false }) diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala index 48b7a063e..6a2b2060e 100644 --- a/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -21,7 +21,7 @@ object EtaExpansion { import tpd._ def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: String = "")(implicit ctx: Context): Tree = - if (TreeInfo.isIdempotentExpr(expr)) expr + if (isIdempotentExpr(expr)) expr else { val name = ctx.freshName(prefix).toTermName val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, expr.tpe, coord = positionCoord(expr.pos)) @@ -46,11 +46,11 @@ object EtaExpansion { def liftApp(defs: mutable.ListBuffer[Tree], tree: Tree)(implicit ctx: Context): Tree = tree match { case Apply(fn, args) => - tree.derivedApply(liftApp(defs, fn), liftArgs(defs, fn.tpe, args)) + cpy.Apply(tree, liftApp(defs, fn), liftArgs(defs, fn.tpe, args)) case TypeApply(fn, targs) => - tree.derivedTypeApply(liftApp(defs, fn), targs) + cpy.TypeApply(tree, liftApp(defs, fn), targs) case Select(pre, name) => - tree.derivedSelect(lift(defs, pre), name) + cpy.Select(tree, lift(defs, pre), name) case Ident(name) => lift(defs, tree) case Block(stats, expr) => diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 1279fcf03..716de5f3c 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -178,8 +178,8 @@ class Namer { typer: Typer => case Some(cdef) => val Thicket((mcls @ TypeDef(_, _, impl: Template)) :: mrest) = expandedTree(mdef) val Thicket(cls :: TypeDef(_, _, compimpl: Template) :: crest) = expandedTree(cdef) - val mcls1 = mcls.derivedTypeDef(mcls.mods, mcls.name, - impl.derivedTemplate(impl.constr, impl.parents, impl.self, + val mcls1 = cpy.TypeDef(mcls, mcls.mods, mcls.name, + cpy.Template(impl, impl.constr, impl.parents, impl.self, compimpl.body ++ impl.body)) expandedTree(mdef) = Thicket(mcls1 :: mrest) expandedTree(cdef) = Thicket(cls :: crest) @@ -311,7 +311,7 @@ class Namer { typer: Typer => def classDefSig(cdef: TypeDef, cls: ClassSymbol)(implicit ctx: Context): Type = { def parentType(constr: untpd.Tree): Type = { - val Trees.Select(Trees.New(tpt), _) = TreeInfo.methPart(constr) + val Trees.Select(Trees.New(tpt), _) = methPart(constr) val ptype = typedAheadType(tpt).tpe if (ptype.uninstantiatedTypeParams.isEmpty) ptype else typedAheadExpr(constr).tpe diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 6d6211daf..733eac739 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -31,7 +31,7 @@ trait TyperContextOps { ctx: Context => } object Typer { - import tpd._ + import tpd.{cpy => _, _} object BindingPrec { val definition = 4 @@ -59,8 +59,9 @@ object Typer { class Typer extends Namer with Applications with Implicits { - import tpd._ import Typer._ + import tpd.{cpy => _, _} + import untpd.cpy /** A temporary data item valid for a single typed ident: * The set of all root import symbols that have been @@ -300,7 +301,7 @@ class Typer extends Namer with Applications with Implicits { val qual1 = typedExpr(tree.qualifier, RefinedType(WildcardType, tree.name, pt)) val ownType = typedSelection(qual1.exprType, tree.name, tree.pos) if (!ownType.isError) checkAccessible(ownType, qual1.isInstanceOf[Super], tree.pos) - tree.withType(ownType).derivedSelect(qual1, tree.name) + cpy.Select(tree, qual1, tree.name).withType(ownType) } def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = { @@ -326,7 +327,7 @@ class Typer extends Namer with Applications with Implicits { else if (ctx.mode is Mode.InSuperInit) cls.info.firstParent else cls.info.parents.reduceLeft((x: Type, y: Type) => AndType(x, y)) - tree.withType(SuperType(cls.thisType, owntype)).derivedSuper(qual1, mix) + cpy.Super(tree, qual1, mix).withType(SuperType(cls.thisType, owntype)) } def typedLiteral(tree: untpd.Literal)(implicit ctx: Context) = @@ -336,24 +337,24 @@ class Typer extends Namer with Applications with Implicits { val tpt1 = typedType(tree.tpt) val cls = checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos) checkInstantiatable(cls, tpt1.pos) - tree.withType(tpt1.tpe).derivedNew(tpt1) + cpy.New(tree, tpt1).withType(tpt1.tpe) } def typedPair(tree: untpd.Pair)(implicit ctx: Context) = { val left1 = typed(tree.left) val right1 = typed(tree.right) - tree.withType(defn.PairType.appliedTo(left1.tpe :: right1.tpe :: Nil)).derivedPair(left1, right1) + cpy.Pair(tree, left1, right1).withType(defn.PairType.appliedTo(left1.tpe :: right1.tpe :: Nil)) } def TypedTyped(tree: untpd.Typed)(implicit ctx: Context) = { val tpt1 = typedType(tree.tpt) val expr1 = typedExpr(tree.expr, tpt1.tpe) - tree.withType(tpt1.tpe).derivedTyped(tpt1, expr1) + cpy.Typed(tree, tpt1, expr1).withType(tpt1.tpe) } def NamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = { val arg1 = typed(tree.arg, pt) - tree.withType(arg1.tpe).derivedNamedArg(tree.name, arg1) + cpy.NamedArg(tree, tree.name, arg1).withType(arg1.tpe) } def Assign(tree: untpd.Assign)(implicit ctx: Context) = { @@ -375,7 +376,7 @@ class Typer extends Namer with Applications with Implicits { val tpt1 = typedType(tpt) val rhs1 = typedExpr(rhs, tpt1.tpe) val pt = if (sym.exists) sym.symRef else NoType - vdef.withType(pt).derivedValDef(mods1, name, tpt1, rhs1) + cpy.ValDef(vdef, mods1, name, tpt1, rhs1).withType(pt) } def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = { @@ -385,7 +386,7 @@ class Typer extends Namer with Applications with Implicits { val vparamss1 = vparamss.mapconserve(_ mapconserve (typed(_).asInstanceOf[ValDef])) val tpt1 = typedType(tpt) val rhs1 = typedExpr(rhs, tpt1.tpe) - ddef.withType(sym.symRef).derivedDefDef(mods1, name, tparams1, vparamss1, tpt1, rhs1) + cpy.DefDef(ddef, mods1, name, tparams1, vparamss1, tpt1, rhs1).withType(sym.symRef) //todo: make sure dependent method types do not depend on implicits or by-name params } @@ -393,7 +394,7 @@ class Typer extends Namer with Applications with Implicits { val TypeDef(mods, name, rhs) = tdef val mods1 = typedModifiers(mods) val rhs1 = typedType(rhs) - tdef.withType(sym.symRef).derivedTypeDef(mods1, name, rhs1) + cpy.TypeDef(tdef, mods1, name, rhs1).withType(sym.symRef) } def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = { @@ -401,15 +402,15 @@ class Typer extends Namer with Applications with Implicits { val mods1 = typedModifiers(mods) val constr1 = typed(constr).asInstanceOf[DefDef] val parents1 = parents mapconserve (typed(_)) - val self1 = self.withType(NoType).derivedValDef( - typedModifiers(self.mods), self.name, typedType(self.tpt), EmptyTree) + val self1 = cpy.ValDef(self, typedModifiers(self.mods), self.name, typedType(self.tpt), EmptyTree) + .withType(NoType) val localDummy = ctx.newLocalDummy(cls, impl.pos) val body1 = typedStats(body, localDummy)(inClassContext(cls, self.name)) - val impl1 = impl.withType(localDummy.symRef).derivedTemplate( - constr1, parents1, self1, body1) + val impl1 = cpy.Template(impl, constr1, parents1, self1, body1) + .withType(localDummy.symRef) - cdef.withType(cls.symRef).derivedTypeDef(mods1, name, impl1) + cpy.TypeDef(cdef, mods1, name, impl1).withType(cls.symRef) // todo later: check that // 1. If class is non-abstract, it is instantiatable: @@ -422,7 +423,7 @@ class Typer extends Namer with Applications with Implicits { def typedImport(imp: untpd.Import, sym: Symbol)(implicit ctx: Context): Import = { val expr1 = typedExpr(imp.expr) - imp.withType(sym.symRef).derivedImport(expr1, imp.selectors) + cpy.Import(imp, expr1, imp.selectors).withType(sym.symRef) } def typedExpanded(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = { @@ -509,7 +510,7 @@ class Typer extends Namer with Applications with Implicits { def tryInsertApply(tree: Tree, pt: Type)(fallBack: StateFul[Tree] => Tree)(implicit ctx: Context): Tree = tryEither { - implicit ctx => typedSelect(Trees.Select(untpd.TypedSplice(tree), nme.apply), pt) + implicit ctx => typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt) } { fallBack } @@ -582,7 +583,7 @@ class Typer extends Namer with Applications with Implicits { def adaptToArgs(tp: Type, pt: FunProtoType) = tp match { case _: MethodType => tree case _ => tryInsertApply(tree, pt) { - def fn = err.refStr(TreeInfo.methPart(tree).tpe) + def fn = err.refStr(methPart(tree).tpe) val more = tree match { case Apply(_, _) => " more" case _ => "" diff --git a/test/test/ContravariantTrees.scala b/test/test/ContravariantTrees.scala new file mode 100644 index 000000000..5fd45bce2 --- /dev/null +++ b/test/test/ContravariantTrees.scala @@ -0,0 +1,65 @@ +package test + +import language.higherKinds +import dotty.tools.dotc.core._ +import Flags._, Names._, StdNames._ +import annotation.unchecked.uncheckedVariance + +object ContravariantTrees { + + type Untyped = Null + + case class Modifiers[-T >: Untyped] ( + flags: FlagSet = EmptyFlags, + privateWithin: TypeName = tpnme.EMPTY, + annotations: List[Tree[T]] = Nil) { + + def is(fs: FlagSet): Boolean = flags is fs + def is(fc: FlagConjunction): Boolean = flags is fc + + def | (fs: FlagSet): Modifiers[T] = withFlags(flags | fs) + def & (fs: FlagSet): Modifiers[T] = withFlags(flags & fs) + def &~(fs: FlagSet): Modifiers[T] = withFlags(flags &~ fs) + + def toTypeFlags: Modifiers[T] = withFlags(flags.toTypeFlags) + def toTermFlags: Modifiers[T] = withFlags(flags.toTermFlags) + + private def withFlags(flags: FlagSet) = + if (this.flags == flags) this + else copy(flags = flags) + + def withPrivateWithin(pw: TypeName) = + if (pw.isEmpty) this + else copy(privateWithin = pw) + + def hasFlags = flags != EmptyFlags + def hasAnnotations = annotations.nonEmpty + def hasPrivateWithin = privateWithin != tpnme.EMPTY + } + + abstract class Tree[-T >: Untyped] { + private[this] var myTpe: T = _ + private def setMyTpe(tpe: T) = myTpe = tpe + + def tpe: T @uncheckedVariance = { + if (myTpe == null) throw new Error() + myTpe + } + } + + trait TermTree[-T >: Untyped] extends Tree[T] { + type ThisTree[T >: Untyped] <: TermTree[T] + } + + case class Select[-T >: Untyped](qualifier: Tree[T], name: Name) + extends TermTree[T] { + type ThisTree[T >: Untyped] = Select[T] + } + + /** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */ + case class DefDef[-T >: Untyped](mods: Modifiers[T], name: TermName, tparams: List[Tree[T]], vparamss: List[List[Tree[T]]], tpt: Tree[T], rhs: Tree[T]) + extends Tree[T] { + type ThisTree[T >: Untyped] = DefDef[T] + } + +} \ No newline at end of file diff --git a/test/test/DeSugarTest.scala b/test/test/DeSugarTest.scala index b408d4b34..ba6be7cef 100644 --- a/test/test/DeSugarTest.scala +++ b/test/test/DeSugarTest.scala @@ -5,12 +5,12 @@ import dotty.tools.dotc.util._ import dotty.tools.dotc.core._ import dotty.tools.dotc.parsing._ import Tokens._, Parsers._ -import org.junit.Test import dotty.tools.dotc._ import ast.Trees._ import ast.desugar import ast.desugar._ import typer.Mode +import Contexts.Context import scala.collection.mutable.ListBuffer @@ -22,7 +22,7 @@ class DeSugarTest extends ParserTest { val Expr = Mode(0) - object DeSugar extends TreeTransformer { + object DeSugar extends UntypedTreeTransformer { var curMode: Mode = Expr def withMode[T](mode: Mode)(op: => T) = { val saved = curMode @@ -31,10 +31,10 @@ class DeSugarTest extends ParserTest { finally curMode = saved } - def transform(tree: Tree, mode: Mode): Tree = withMode(mode) { transform(tree) } - def transform(trees: List[Tree], mode: Mode): List[Tree] = withMode(mode) { transform(trees) } + def transform(tree: Tree, mode: Mode)(implicit ctx: Context): Tree = withMode(mode) { transform(tree) } + def transform(trees: List[Tree], mode: Mode)(implicit ctx: Context): List[Tree] = withMode(mode) { transform(trees) } - override def transform(tree: Tree): Tree = { + override def transform(tree: Tree)(implicit ctx: Context): Tree = { val tree1 = desugar(tree)(ctx.withMode(curMode)) tree1 match { case TypedSplice(t) => @@ -42,29 +42,29 @@ class DeSugarTest extends ParserTest { case PostfixOp(od, op) => PostfixOp(transform(od), op) case Select(qual, name) => - tree1.derivedSelect(transform(qual, Expr), name) + cpy.Select(tree1, transform(qual, Expr), name) case Apply(fn, args) => - tree1.derivedApply(transform(fn, Expr), transform(args)) + cpy.Apply(tree1, transform(fn, Expr), transform(args)) case TypeApply(fn, args) => - tree1.derivedTypeApply(transform(fn, Expr), transform(args, Type)) + cpy.TypeApply(tree1, transform(fn, Expr), transform(args, Type)) case New(tpt) => - tree1.derivedNew(transform(tpt, Type)) + cpy.New(tree1, transform(tpt, Type)) case Typed(expr, tpt) => - tree1.derivedTyped(transform(expr), transform(tpt, Type)) + cpy.Typed(tree1, transform(expr), transform(tpt, Type)) case CaseDef(pat, guard, body) => - tree1.derivedCaseDef(transform(pat, Pattern), transform(guard), transform(body)) + cpy.CaseDef(tree1, transform(pat, Pattern), transform(guard), transform(body)) case SeqLiteral(elems) => - tree1.derivedSeqLiteral(transform(elems)) + cpy.SeqLiteral(tree1, transform(elems)) case UnApply(fun, args) => - tree1.derivedUnApply(transform(fun, Expr), transform(args)) + cpy.UnApply(tree1, transform(fun, Expr), transform(args)) case ValDef(mods, name, tpt, rhs) => - tree1.derivedValDef(mods, name, transform(tpt, Type), transform(rhs)) + cpy.ValDef(tree1, mods, name, transform(tpt, Type), transform(rhs)) case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - tree1.derivedDefDef(mods, name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt, Type), transform(rhs)) + cpy.DefDef(tree1, mods, name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt, Type), transform(rhs)) case tree1 @ TypeDef(mods, name, rhs) => - tree1.derivedTypeDef(mods, name, transform(rhs, Type), transformSub(tree1.tparams)) + cpy.TypeDef(tree1, mods, name, transform(rhs, Type), transformSub(tree1.tparams)) case Template(constr, parents, self, body) => - tree1.derivedTemplate(transformSub(constr), transform(parents), transformSub(self), transform(body, Expr)) + cpy.Template(tree1, transformSub(constr), transform(parents), transformSub(self), transform(body, Expr)) case Thicket(trees) => Thicket(flatten(trees mapConserve super.transform)) case tree1 => @@ -93,4 +93,4 @@ class DeSugarTest extends ParserTest { } def desugarAll() = parsedTrees foreach (desugarTree(_).show) -} \ No newline at end of file +} diff --git a/test/test/DottyTest.scala b/test/test/DottyTest.scala index 2d9397fa6..3121909e4 100644 --- a/test/test/DottyTest.scala +++ b/test/test/DottyTest.scala @@ -7,7 +7,6 @@ import dotty.tools.dotc.core.Flags._ import Types._, Symbols._, Decorators._ import dotty.tools.dotc.printing.Texts._ import dotty.tools.dotc.core.Decorators._ -import org.junit.Test class DottyTest { diff --git a/test/test/parsePackage.scala b/test/test/parsePackage.scala index c9f0a0651..5c74c87ff 100644 --- a/test/test/parsePackage.scala +++ b/test/test/parsePackage.scala @@ -3,6 +3,7 @@ package test import dotty.tools.dotc._ import core._, ast._ import Trees._ +import Contexts.Context object parsePackage extends ParserTest { @@ -10,8 +11,8 @@ object parsePackage extends ParserTest { var nodes = 0 - val transformer = new TreeTransformer { - override def transform(tree: Tree): Tree = { + val transformer = new UntypedTreeTransformer { + override def transform(tree: Tree)(implicit ctx: Context): Tree = { nodes += 1 tree match { case Ident(name) => -- cgit v1.2.3