package dotty.tools package dotc package ast import dotty.tools.dotc.transform.{ExplicitOuter, Erasure} import dotty.tools.dotc.typer.ProtoTypes.FunProtoTyped import transform.SymUtils._ import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._ import Denotations._, Decorators._, DenotTransformers._ import collection.mutable import util.{Property, SourceFile, NoSource} import typer.ErrorReporting._ import NameKinds.TempResultName import scala.annotation.tailrec import scala.io.Codec /** Some creators for typed trees */ object tpd extends Trees.Instance[Type] with TypedTreeInfo { private def ta(implicit ctx: Context) = ctx.typeAssigner def Ident(tp: NamedType)(implicit ctx: Context): Ident = ta.assignType(untpd.Ident(tp.name), tp) def Select(qualifier: Tree, name: Name)(implicit ctx: Context): Select = ta.assignType(untpd.Select(qualifier, name), qualifier) def Select(qualifier: Tree, tp: NamedType)(implicit ctx: Context): Select = untpd.Select(qualifier, tp.name).withType(tp) def This(cls: ClassSymbol)(implicit ctx: Context): This = untpd.This(untpd.Ident(cls.name)).withType(cls.thisType) def Super(qual: Tree, mix: untpd.Ident, inConstrCall: Boolean, mixinClass: Symbol)(implicit ctx: Context): Super = ta.assignType(untpd.Super(qual, mix), qual, inConstrCall, mixinClass) def Super(qual: Tree, mixName: TypeName, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context): Super = Super(qual, if (mixName.isEmpty) untpd.EmptyTypeIdent else untpd.Ident(mixName), inConstrCall, mixinClass) def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply = ta.assignType(untpd.Apply(fn, args), fn, args) def TypeApply(fn: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = ta.assignType(untpd.TypeApply(fn, args), fn, args) def Literal(const: Constant)(implicit ctx: Context): Literal = ta.assignType(untpd.Literal(const)) def unitLiteral(implicit ctx: Context): Literal = Literal(Constant(())) def New(tpt: Tree)(implicit ctx: Context): New = ta.assignType(untpd.New(tpt), tpt) def New(tp: Type)(implicit ctx: Context): New = New(TypeTree(tp)) def Typed(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed = ta.assignType(untpd.Typed(expr, tpt), tpt) def NamedArg(name: Name, arg: Tree)(implicit ctx: Context): NamedArg = ta.assignType(untpd.NamedArg(name, arg), arg) def Assign(lhs: Tree, rhs: Tree)(implicit ctx: Context): Assign = ta.assignType(untpd.Assign(lhs, rhs)) def Block(stats: List[Tree], expr: Tree)(implicit ctx: Context): Block = ta.assignType(untpd.Block(stats, expr), stats, expr) /** Join `stats` in front of `expr` creating a new block if necessary */ def seq(stats: List[Tree], expr: Tree)(implicit ctx: Context): Tree = if (stats.isEmpty) expr else expr match { case Block(estats, eexpr) => cpy.Block(expr)(stats ::: estats, eexpr) case _ => Block(stats, expr) } def If(cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If = ta.assignType(untpd.If(cond, thenp, elsep), thenp, elsep) def Closure(env: List[Tree], meth: Tree, tpt: Tree)(implicit ctx: Context): Closure = ta.assignType(untpd.Closure(env, meth, tpt), meth, tpt) /** A function def * * vparams => expr * * gets expanded to * * { def $anonfun(vparams) = expr; Closure($anonfun) } * * where the closure's type is the target type of the expression (FunctionN, unless * otherwise specified). */ def Closure(meth: TermSymbol, rhsFn: List[List[Tree]] => Tree, targs: List[Tree] = Nil, targetType: Type = NoType)(implicit ctx: Context): Block = { val targetTpt = if (targetType.exists) TypeTree(targetType) else EmptyTree val call = if (targs.isEmpty) Ident(TermRef(NoPrefix, meth)) else TypeApply(Ident(TermRef(NoPrefix, meth)), targs) Block( DefDef(meth, rhsFn) :: Nil, Closure(Nil, call, targetTpt)) } def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef = ta.assignType(untpd.CaseDef(pat, guard, body), body) def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = ta.assignType(untpd.Match(selector, cases), cases) def Return(expr: Tree, from: Tree)(implicit ctx: Context): Return = ta.assignType(untpd.Return(expr, from)) def Try(block: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = ta.assignType(untpd.Try(block, cases, finalizer), block, cases) def SeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): SeqLiteral = ta.assignType(untpd.SeqLiteral(elems, elemtpt), elems, elemtpt) def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): JavaSeqLiteral = ta.assignType(new untpd.JavaSeqLiteral(elems, elemtpt), elems, elemtpt).asInstanceOf[JavaSeqLiteral] def Inlined(call: Tree, bindings: List[MemberDef], expansion: Tree)(implicit ctx: Context): Inlined = ta.assignType(untpd.Inlined(call, bindings, expansion), bindings, expansion) def TypeTree(tp: Type)(implicit ctx: Context): TypeTree = untpd.TypeTree().withType(tp) def SingletonTypeTree(ref: Tree)(implicit ctx: Context): SingletonTypeTree = ta.assignType(untpd.SingletonTypeTree(ref), ref) def AndTypeTree(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = ta.assignType(untpd.AndTypeTree(left, right), left, right) def OrTypeTree(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = ta.assignType(untpd.OrTypeTree(left, right), left, right) def RefinedTypeTree(parent: Tree, refinements: List[Tree], refineCls: ClassSymbol)(implicit ctx: Context): Tree = ta.assignType(untpd.RefinedTypeTree(parent, refinements), parent, refinements, refineCls) def AppliedTypeTree(tycon: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = ta.assignType(untpd.AppliedTypeTree(tycon, args), tycon, args) def ByNameTypeTree(result: Tree)(implicit ctx: Context): ByNameTypeTree = ta.assignType(untpd.ByNameTypeTree(result), result) def LambdaTypeTree(tparams: List[TypeDef], body: Tree)(implicit ctx: Context): LambdaTypeTree = ta.assignType(untpd.LambdaTypeTree(tparams, body), tparams, body) def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = ta.assignType(untpd.TypeBoundsTree(lo, hi), lo, hi) def Bind(sym: TermSymbol, body: Tree)(implicit ctx: Context): Bind = ta.assignType(untpd.Bind(sym.name, body), sym) /** A pattern corresponding to `sym: tpe` */ def BindTyped(sym: TermSymbol, tpe: Type)(implicit ctx: Context): Bind = Bind(sym, Typed(Underscore(tpe), TypeTree(tpe))) def Alternative(trees: List[Tree])(implicit ctx: Context): Alternative = ta.assignType(untpd.Alternative(trees), trees) def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree], proto: Type)(implicit ctx: Context): UnApply = ta.assignType(untpd.UnApply(fun, implicits, patterns), proto) def ValDef(sym: TermSymbol, rhs: LazyTree = EmptyTree)(implicit ctx: Context): ValDef = ta.assignType(untpd.ValDef(sym.name, TypeTree(sym.info), rhs), sym) def SyntheticValDef(name: TermName, rhs: Tree)(implicit ctx: Context): ValDef = ValDef(ctx.newSymbol(ctx.owner, name, Synthetic, rhs.tpe.widen, coord = rhs.pos), rhs) def DefDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef = ta.assignType(DefDef(sym, Function.const(rhs) _), sym) def DefDef(sym: TermSymbol, rhsFn: List[List[Tree]] => Tree)(implicit ctx: Context): DefDef = polyDefDef(sym, Function.const(rhsFn)) def polyDefDef(sym: TermSymbol, rhsFn: List[Type] => List[List[Tree]] => Tree)(implicit ctx: Context): DefDef = { val (tparams, mtp) = sym.info match { case tp: PolyType => val tparams = ctx.newTypeParams(sym, tp.paramNames, EmptyFlags, tp.instantiateBounds) (tparams, tp.instantiate(tparams map (_.typeRef))) case tp => (Nil, tp) } def valueParamss(tp: Type): (List[List[TermSymbol]], Type) = tp match { case tp: MethodType => def valueParam(name: TermName, info: Type): TermSymbol = { val maybeImplicit = if (tp.isInstanceOf[ImplicitMethodType]) Implicit else EmptyFlags ctx.newSymbol(sym, name, TermParam | maybeImplicit, info) } val params = (tp.paramNames, tp.paramInfos).zipped.map(valueParam) val (paramss, rtp) = valueParamss(tp.instantiate(params map (_.termRef))) (params :: paramss, rtp) case tp => (Nil, tp.widenExpr) } val (vparamss, rtp) = valueParamss(mtp) val targs = tparams map (_.typeRef) val argss = vparamss.nestedMap(vparam => Ident(vparam.termRef)) ta.assignType( untpd.DefDef( sym.name, tparams map TypeDef, vparamss.nestedMap(ValDef(_)), TypeTree(rtp), rhsFn(targs)(argss)), sym) } def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef = ta.assignType(untpd.TypeDef(sym.name, TypeTree(sym.info)), sym) def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(implicit ctx: Context): TypeDef = { val firstParentRef :: otherParentRefs = cls.info.parents val firstParent = cls.typeRef.baseTypeWithArgs(firstParentRef.symbol) val superRef = if (cls is Trait) TypeTree(firstParent) else { def isApplicable(ctpe: Type): Boolean = ctpe match { case ctpe: PolyType => isApplicable(ctpe.instantiate(firstParent.argTypes)) case ctpe: MethodType => (superArgs corresponds ctpe.paramInfos)(_.tpe <:< _) case _ => false } val constr = firstParent.decl(nme.CONSTRUCTOR).suchThat(constr => isApplicable(constr.info)) New(firstParent, constr.symbol.asTerm, superArgs) } val parents = superRef :: otherParentRefs.map(TypeTree(_)) val selfType = if (cls.classInfo.selfInfo ne NoType) ValDef(ctx.newSelfSym(cls)) else EmptyValDef def isOwnTypeParam(stat: Tree) = (stat.symbol is TypeParam) && stat.symbol.owner == cls val bodyTypeParams = body filter isOwnTypeParam map (_.symbol) val newTypeParams = for (tparam <- cls.typeParams if !(bodyTypeParams contains tparam)) yield TypeDef(tparam) val findLocalDummy = new FindLocalDummyAccumulator(cls) val localDummy = ((NoSymbol: Symbol) /: body)(findLocalDummy.apply) .orElse(ctx.newLocalDummy(cls)) val impl = untpd.Template(constr, parents, selfType, newTypeParams ++ body) .withType(localDummy.nonMemberTermRef) ta.assignType(untpd.TypeDef(cls.name, impl), cls) } /** An anonymous class * * new parents { forwarders } * * where `forwarders` contains forwarders for all functions in `fns`. * @param parents a non-empty list of class types * @param fns a non-empty of functions for which forwarders should be defined in the class. * The class has the same owner as the first function in `fns`. * Its position is the union of all functions in `fns`. */ def AnonClass(parents: List[Type], fns: List[TermSymbol], methNames: List[TermName])(implicit ctx: Context): Block = { val owner = fns.head.owner val parents1 = if (parents.head.classSymbol.is(Trait)) parents.head.parents.head :: parents else parents val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_FUN, Synthetic, parents1, coord = fns.map(_.pos).reduceLeft(_ union _)) val constr = ctx.newConstructor(cls, Synthetic, Nil, Nil).entered def forwarder(fn: TermSymbol, name: TermName) = { val fwdMeth = fn.copy(cls, name, Synthetic | Method).entered.asTerm DefDef(fwdMeth, prefss => ref(fn).appliedToArgss(prefss)) } val forwarders = (fns, methNames).zipped.map(forwarder) val cdef = ClassDef(cls, DefDef(constr), forwarders) Block(cdef :: Nil, New(cls.typeRef, Nil)) } // {