diff options
author | Martin Odersky <odersky@gmail.com> | 2013-05-22 18:56:31 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-05-22 18:56:57 +0200 |
commit | 965a62d4a165da7e5a53c9afdba3175e10fe714b (patch) | |
tree | 9698567b21c4a6006aa5c1e3bdd7ba788706539b /src/dotty | |
parent | fd079d2f3335db7b54b0f78a4d884d9948a7beea (diff) | |
download | dotty-965a62d4a165da7e5a53c9afdba3175e10fe714b.tar.gz dotty-965a62d4a165da7e5a53c9afdba3175e10fe714b.tar.bz2 dotty-965a62d4a165da7e5a53c9afdba3175e10fe714b.zip |
Made tpd/untpd toplevel objects.
Moved all other elements of TypedTrees and UntypedTrees into tpd and untpd.
Diffstat (limited to 'src/dotty')
18 files changed, 706 insertions, 711 deletions
diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala index f62eb1921..c10a2dacb 100644 --- a/src/dotty/tools/dotc/ast/CheckTrees.scala +++ b/src/dotty/tools/dotc/ast/CheckTrees.scala @@ -5,10 +5,11 @@ package ast import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ -import TypedTrees.{tpd, TreeOps, localSyms} object CheckTrees { + import tpd.{TreeMapper, localSyms, TreeOps} + def check(p: Boolean, msg: => String = "")(implicit ctx: Context): Unit = assert(p, msg) def checkTypeArg(arg: tpd.Tree, bounds: TypeBounds)(implicit ctx: Context): Unit = { diff --git a/src/dotty/tools/dotc/ast/PluggableTransformers.scala b/src/dotty/tools/dotc/ast/PluggableTransformers.scala index 8c64feb21..84bbf833c 100644 --- a/src/dotty/tools/dotc/ast/PluggableTransformers.scala +++ b/src/dotty/tools/dotc/ast/PluggableTransformers.scala @@ -84,7 +84,7 @@ object PluggableTransformers { } } -import PluggableTransformers._, Types._, Trees._, Contexts._, TypedTrees.tpd +import PluggableTransformers._, Types._, Trees._, Contexts._ class ExampleTransformer extends PluggableTransformer[Type] { diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index eeab6ceb0..75e82ecca 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -3,7 +3,7 @@ package dotc package ast import core._ -import Flags._, Trees._, UntypedTrees._, TypedTrees._, Types._, Contexts._ +import Flags._, Trees._, Types._, Contexts._ import Names._, StdNames._, NameOps._, Decorators._, Symbols._ import util.HashSet diff --git a/src/dotty/tools/dotc/ast/TypedTrees.scala b/src/dotty/tools/dotc/ast/TypedTrees.scala index b6583baf0..958927148 100644 --- a/src/dotty/tools/dotc/ast/TypedTrees.scala +++ b/src/dotty/tools/dotc/ast/TypedTrees.scala @@ -7,320 +7,317 @@ import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ import CheckTrees._ -object TypedTrees { +object tpd extends Trees.Instance[Type] { - object tpd extends Trees.Instance[Type] { + def Modifiers(sym: Symbol)(implicit ctx: Context): Modifiers = Trees.Modifiers[Type]( + sym.flags & ModifierFlags, + if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY, + sym.annotations map (_.tree)) - def Modifiers(sym: Symbol)(implicit ctx: Context): Modifiers = Trees.Modifiers[Type]( - sym.flags & ModifierFlags, - if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY, - sym.annotations map (_.tree)) + def Ident(tp: NamedType)(implicit ctx: Context): Ident = + Trees.Ident(tp.name).withType(tp).checked - def Ident(tp: NamedType)(implicit ctx: Context): Ident = - Trees.Ident(tp.name).withType(tp).checked + def Select(pre: Tree, tp: NamedType)(implicit ctx: Context): Select = + Trees.Select(pre, tp.name).withType(tp).checked - def Select(pre: Tree, tp: NamedType)(implicit ctx: Context): Select = - Trees.Select(pre, tp.name).withType(tp).checked + def This(cls: ClassSymbol)(implicit ctx: Context): This = + Trees.This(cls.name).withType(cls.thisType).checked - def This(cls: ClassSymbol)(implicit ctx: Context): This = - Trees.This(cls.name).withType(cls.thisType).checked - - def Super(qual: Tree, mix: TypeName)(implicit ctx: Context): Super = { - val owntype = - if (mix.isEmpty) ctx.glb(qual.tpe.parents) - else { - val mixParents = qual.tpe.parents filter (_.name == mix) - check(mixParents.length == 1) - mixParents.head - } - Trees.Super(qual, mix).withType(SuperType(qual.tpe, owntype)).checked - } - - 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(", ")}") - fntpe.instantiate(args map (_.tpe)) - case _ => - check(false) - ErrorType + def Super(qual: Tree, mix: TypeName)(implicit ctx: Context): Super = { + val owntype = + if (mix.isEmpty) ctx.glb(qual.tpe.parents) + else { + val mixParents = qual.tpe.parents filter (_.name == mix) + check(mixParents.length == 1) + mixParents.head } - Trees.Apply(fn, args).withType(owntype).checked + Trees.Super(qual, mix).withType(SuperType(qual.tpe, owntype)).checked + } + + 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(", ")}") + fntpe.instantiate(args map (_.tpe)) + case _ => + check(false) + ErrorType } + Trees.Apply(fn, args).withType(owntype).checked + } - 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)) - fntpe.instantiate(args map (_.tpe)) - case _ => - check(false) - ErrorType - } - Trees.TypeApply(fn, args).withType(owntype).checked + 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)) + fntpe.instantiate(args map (_.tpe)) + case _ => + check(false) + ErrorType } + Trees.TypeApply(fn, args).withType(owntype).checked + } - def Literal(const: Constant)(implicit ctx: Context): Literal = - Trees.Literal(const).withType(const.tpe).checked + def Literal(const: Constant)(implicit ctx: Context): Literal = + Trees.Literal(const).withType(const.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 = + Trees.New(TypeTree(tp)).withType(tp).checked - def Pair(left: Tree, right: Tree)(implicit ctx: Context): Pair = - Trees.Pair(left, right).withType(defn.PairType.appliedTo(left.tpe, right.tpe)).checked + def Pair(left: Tree, right: Tree)(implicit ctx: Context): Pair = + Trees.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 + def Typed(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed = + Trees.Typed(expr, tpt).withType(tpt.tpe).checked - def NamedArg(name: TermName, arg: Tree)(implicit ctx: Context) = - Trees.NamedArg(name, arg).withType(arg.tpe).checked + def NamedArg(name: TermName, arg: Tree)(implicit ctx: Context) = + Trees.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 + def Assign(lhs: Tree, rhs: Tree)(implicit ctx: Context): Assign = + Trees.Assign(lhs, rhs).withType(defn.UnitType).checked - def Block(stats: List[Tree], expr: Tree)(implicit ctx: Context): Block = { - lazy val locals = localSyms(stats).toSet - val blk = Trees.Block(stats, expr) - def widen(tp: Type): Type = tp match { - case tp: TermRef if locals contains tp.symbol => - widen(tp.info) - case _ => tp - } - blk.withType(widen(expr.tpe)) + def Block(stats: List[Tree], expr: Tree)(implicit ctx: Context): Block = { + lazy val locals = localSyms(stats).toSet + val blk = Trees.Block(stats, expr) + def widen(tp: Type): Type = tp match { + case tp: TermRef if locals contains tp.symbol => + widen(tp.info) + case _ => tp } + blk.withType(widen(expr.tpe)) + } - def If(cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If = - Trees.If(cond, thenp, elsep).withType(thenp.tpe | elsep.tpe).checked - - def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = - Trees.Match(selector, cases).withType(ctx.lub(cases map (_.body.tpe))).checked + def If(cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If = + Trees.If(cond, thenp, elsep).withType(thenp.tpe | elsep.tpe).checked - def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef = - Trees.CaseDef(pat, guard, body).withType(body.tpe).checked + def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = + Trees.Match(selector, cases).withType(ctx.lub(cases map (_.body.tpe))).checked - def Return(expr: Tree, from: Ident)(implicit ctx: Context): Return = - Trees.Return(expr, from).withType(defn.NothingType).checked + def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef = + Trees.CaseDef(pat, guard, body).withType(body.tpe).checked - def Try(block: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): Try = - Trees.Try(block, handler, finalizer).withType(block.tpe | handler.tpe).checked + def Return(expr: Tree, from: Ident)(implicit ctx: Context): Return = + Trees.Return(expr, from).withType(defn.NothingType).checked - def Throw(expr: Tree)(implicit ctx: Context): Throw = - Trees.Throw(expr).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 - def SeqLiteral(elemtpt: Tree, elems: List[Tree])(implicit ctx: Context): SeqLiteral = - Trees.SeqLiteral(elemtpt, elems).withType(defn.RepeatedParamType.appliedTo(elemtpt.tpe)).checked + def Throw(expr: Tree)(implicit ctx: Context): Throw = + Trees.Throw(expr).withType(defn.NothingType).checked - def SeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral = - SeqLiteral(TypeTree(ctx.lub(elems map (_.tpe))), elems) + def SeqLiteral(elemtpt: Tree, elems: List[Tree])(implicit ctx: Context): SeqLiteral = + Trees.SeqLiteral(elemtpt, elems).withType(defn.RepeatedParamType.appliedTo(elemtpt.tpe)).checked - def TypeTree(tp: Type, original: Tree = EmptyTree)(implicit ctx: Context): TypeTree = - Trees.TypeTree(original).withType(tp).checked + def SeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral = + SeqLiteral(TypeTree(ctx.lub(elems map (_.tpe))), elems) - def SingletonTypeTree(ref: Tree)(implicit ctx: Context): SingletonTypeTree = - Trees.SingletonTypeTree(ref).withType(ref.tpe).checked + def TypeTree(tp: Type, original: Tree = EmptyTree)(implicit ctx: Context): TypeTree = + Trees.TypeTree(original).withType(tp).checked - def SelectFromTypeTree(qualifier: Tree, tp: NamedType)(implicit ctx: Context): SelectFromTypeTree = - Trees.SelectFromTypeTree(qualifier, tp.name).withType(tp).checked + def SingletonTypeTree(ref: Tree)(implicit ctx: Context): SingletonTypeTree = + Trees.SingletonTypeTree(ref).withType(ref.tpe).checked - def AndTypeTree(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = - Trees.AndTypeTree(left, right).withType(left.tpe & right.tpe).checked + def SelectFromTypeTree(qualifier: Tree, tp: NamedType)(implicit ctx: Context): SelectFromTypeTree = + Trees.SelectFromTypeTree(qualifier, tp.name).withType(tp).checked - def OrTypeTree(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = - Trees.OrTypeTree(left, right).withType(left.tpe | right.tpe).checked + def AndTypeTree(left: Tree, right: Tree)(implicit ctx: Context): AndTypeTree = + Trees.AndTypeTree(left, right).withType(left.tpe & right.tpe).checked - def RefinedTypeTree(tpt: Tree, refinements: List[DefTree])(implicit ctx: Context): RefinedTypeTree = { - def refineType(tp: Type, refinement: Symbol): Type = - RefinedType(tp, refinement.name, refinement.info) - Trees.RefinedTypeTree(tpt, refinements) - .withType((tpt.tpe /: (refinements map (_.symbol)))(refineType)).checked - } + def OrTypeTree(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree = + Trees.OrTypeTree(left, right).withType(left.tpe | right.tpe).checked - def refineType(tp: Type, refinement: Symbol)(implicit ctx: Context): Type = + def RefinedTypeTree(tpt: Tree, refinements: List[DefTree])(implicit ctx: Context): RefinedTypeTree = { + def refineType(tp: Type, refinement: Symbol): Type = RefinedType(tp, refinement.name, refinement.info) + Trees.RefinedTypeTree(tpt, refinements) + .withType((tpt.tpe /: (refinements map (_.symbol)))(refineType)).checked + } - def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = - Trees.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 + def refineType(tp: Type, refinement: Symbol)(implicit ctx: Context): Type = + RefinedType(tp, refinement.name, refinement.info) - def Bind(sym: TermSymbol, body: Tree)(implicit ctx: Context): Bind = - Trees.Bind(sym.name, body).withType(refType(sym)).checked + def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree = + Trees.AppliedTypeTree(tpt, args).withType(tpt.tpe.appliedTo(args map (_.tpe))).checked - def Alternative(trees: List[Tree])(implicit ctx: Context): Alternative = - Trees.Alternative(trees).withType(ctx.lub(trees map (_.tpe))).checked + def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = + Trees.TypeBoundsTree(lo, hi).withType(TypeBounds(lo.tpe, hi.tpe)).checked - 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 - } + def Bind(sym: TermSymbol, body: Tree)(implicit ctx: Context): Bind = + Trees.Bind(sym.name, body).withType(refType(sym)).checked - 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 + def Alternative(trees: List[Tree])(implicit ctx: Context): Alternative = + Trees.Alternative(trees).withType(ctx.lub(trees map (_.tpe))).checked - def DefDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef = { + 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 + } - val (tparams, mtp) = sym.info match { - case tp: PolyType => - val tparams = ctx.newTypeParams(sym, tp.paramNames, EmptyFlags, tp.instantiateBounds) - (tparams, tp.instantiate(tparams map (_.typeConstructor))) - case tp => (Nil, tp) - } + 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 - def valueParamss(tp: Type): (List[List[TermSymbol]], Type) = tp match { - case tp @ MethodType(paramNames, paramTypes) => - def valueParam(name: TermName, info: Type): TermSymbol = - ctx.newSymbol(sym, name, TermParam, info) - val params = (paramNames, paramTypes).zipped.map(valueParam) - val (paramss, rtp) = valueParamss(tp.instantiate(params map (_.typeConstructor))) - (params :: paramss, rtp) - case tp => (Nil, tp) - } - val (vparamss, rtp) = valueParamss(mtp) + def DefDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef = { - Trees.DefDef( - Modifiers(sym), sym.name, tparams map TypeDef, - vparamss map (_ map (ValDef(_))), TypeTree(rtp), rhs) - .withType(refType(sym)).checked + val (tparams, mtp) = sym.info match { + case tp: PolyType => + val tparams = ctx.newTypeParams(sym, tp.paramNames, EmptyFlags, tp.instantiateBounds) + (tparams, tp.instantiate(tparams map (_.typeConstructor))) + case tp => (Nil, tp) } - def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef = - Trees.TypeDef(Modifiers(sym), sym.name, Nil, TypeTree(sym.info)) // !!! fill in typeParams - .withType(refType(sym)).checked - - def ClassDef(cls: ClassSymbol, typeParams: List[TypeSymbol], constr: DefDef, body: List[Tree])(implicit ctx: Context): ClassDef = { - val parents = cls.info.parents map (TypeTree(_)) - val selfType = - if (cls.classInfo.optSelfType.exists) ValDef(ctx.newSelfSym(cls)) - else EmptyValDef - def isOwnTypeParamAccessor(stat: Tree) = - (stat.symbol is TypeParam) && stat.symbol.owner == cls - val (tparamAccessors, rest) = body partition isOwnTypeParamAccessor - val tparams = - (typeParams map TypeDef) ++ - (tparamAccessors collect { - case td: TypeDef if !(typeParams contains td.symbol) => td - }) - val findLocalDummy = new FindLocalDummyAccumulator(cls) - val localDummy = ((NoSymbol: Symbol) /: body)(findLocalDummy) - .orElse(ctx.newLocalDummy(cls)) - val impl = Trees.Template(constr, parents, selfType, rest) - .withType(refType(localDummy)).checked - Trees.ClassDef(Modifiers(cls), cls.name, tparams, impl) - .withType(refType(cls)).checked + def valueParamss(tp: Type): (List[List[TermSymbol]], Type) = tp match { + case tp @ MethodType(paramNames, paramTypes) => + def valueParam(name: TermName, info: Type): TermSymbol = + ctx.newSymbol(sym, name, TermParam, info) + val params = (paramNames, paramTypes).zipped.map(valueParam) + val (paramss, rtp) = valueParamss(tp.instantiate(params map (_.typeConstructor))) + (params :: paramss, rtp) + case tp => (Nil, tp) } + val (vparamss, rtp) = valueParamss(mtp) - def Import(expr: Tree, selectors: List[Trees.UntypedTree])(implicit ctx: Context): Import = - Trees.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 - - def Annotated(annot: Tree, arg: Tree)(implicit ctx: Context): Annotated = - Trees.Annotated(annot, arg).withType(AnnotatedType(Annotation(annot), arg.tpe)).checked - - val EmptyTree: Tree = Trees.EmptyTree[Type] - - val EmptyValDef: ValDef = Trees.EmptyValDef[Type] - - def SharedTree(tree: Tree): SharedTree = - Trees.SharedTree(tree).withType(tree.tpe) - - 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) - else tp.prefix match { - case pre: TermRef => Select(ref(pre), tp) - case pre => SelectFromTypeTree(TypeTree(pre), tp) - } // no checks necessary - - def ref(sym: Symbol)(implicit ctx: Context): tpd.NameTree = - ref(NamedType(sym.owner.thisType, sym.name).withDenot(sym)) - - /** new C(args) */ - def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = - Apply( - Select( - New(tp), - TermRef.withSym(tp.normalizedPrefix, tp.typeSymbol.primaryConstructor.asTerm)), - args) - - /** An object def - * - * object obs extends parents { decls } - * - * gets expanded to - * - * <module> lazy val obj = { - * class obj$ extends parents { this: obj.type => decls } - * new obj$ - * } - * - * What's interesting here is that the block is well typed - * (because class obj$ is hoistable), but the type of the `obj` val is - * not expressible. What needs to happen in general when - * inferring the type of a val from its RHS, is: if the type contains - * a class that has the val itself as owner, then that class - * is remapped to have the val's owner as owner. Remapping could be - * done by cloning the class with the new owner and substituting - * everywhere in the tree. We know that remapping is safe - * because the only way a local class can appear in the RHS of a val is - * by being hoisted outside of a block, and the necessary checks are - * done at this point already. - * - * On the other hand, for method result type inference, if the type of - * the RHS of a method contains a class owned by the method, this would be - * an error. - */ - def ModuleDef(sym: TermSymbol, body: List[Tree])(implicit ctx: Context): tpd.TempTrees = { - val modcls = sym.moduleClass.asClass - val constr = DefDef(modcls.primaryConstructor.asTerm, EmptyTree) - val clsdef = ClassDef(modcls, Nil, constr, body) - val valdef = ValDef(sym, New(modcls.typeConstructor)) - TempTrees(valdef :: clsdef :: Nil) - } + Trees.DefDef( + Modifiers(sym), sym.name, tparams map TypeDef, + vparamss map (_ map (ValDef(_))), TypeTree(rtp), rhs) + .withType(refType(sym)).checked + } - /** A function def - * - * vparams => expr - * - * gets expanded to - * - * { def $anonfun(vparams) = expr; $anonfun: pt } - * - * where pt is the target type of the expression (FunctionN) unless - * otherwise specified. - */ - def Function(meth: TermSymbol, body: 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) - defn.FunctionType(formals, mt.resultType) - } - Block( - DefDef(meth, body) :: Nil, - Typed(Ident(TermRef.withSym(NoPrefix, meth)), TypeTree(funtpe))) - } + def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef = + Trees.TypeDef(Modifiers(sym), sym.name, Nil, TypeTree(sym.info)) // !!! fill in typeParams + .withType(refType(sym)).checked + + def ClassDef(cls: ClassSymbol, typeParams: List[TypeSymbol], constr: DefDef, body: List[Tree])(implicit ctx: Context): ClassDef = { + val parents = cls.info.parents map (TypeTree(_)) + val selfType = + if (cls.classInfo.optSelfType.exists) ValDef(ctx.newSelfSym(cls)) + else EmptyValDef + def isOwnTypeParamAccessor(stat: Tree) = + (stat.symbol is TypeParam) && stat.symbol.owner == cls + val (tparamAccessors, rest) = body partition isOwnTypeParamAccessor + val tparams = + (typeParams map TypeDef) ++ + (tparamAccessors collect { + case td: TypeDef if !(typeParams contains td.symbol) => td + }) + val findLocalDummy = new FindLocalDummyAccumulator(cls) + val localDummy = ((NoSymbol: Symbol) /: body)(findLocalDummy) + .orElse(ctx.newLocalDummy(cls)) + val impl = Trees.Template(constr, parents, selfType, rest) + .withType(refType(localDummy)).checked + Trees.ClassDef(Modifiers(cls), cls.name, tparams, impl) + .withType(refType(cls)).checked + } - private class FindLocalDummyAccumulator(cls: ClassSymbol)(implicit ctx: Context) extends TreeAccumulator[Symbol] { - def apply(sym: Symbol, tree: Tree) = - if (sym.exists) sym - else if (tree.isDef) { - val owner = tree.symbol.owner - if (owner.isLocalDummy && owner.owner == cls) owner - else if (owner == cls) foldOver(sym, tree) - else sym - } else foldOver(sym, tree) - } + def Import(expr: Tree, selectors: List[Trees.UntypedTree])(implicit ctx: Context): Import = + Trees.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 + + def Annotated(annot: Tree, arg: Tree)(implicit ctx: Context): Annotated = + Trees.Annotated(annot, arg).withType(AnnotatedType(Annotation(annot), arg.tpe)).checked + + val EmptyTree: Tree = Trees.EmptyTree[Type] + + val EmptyValDef: ValDef = Trees.EmptyValDef[Type] + + def SharedTree(tree: Tree): SharedTree = + Trees.SharedTree(tree).withType(tree.tpe) + + 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) + else tp.prefix match { + case pre: TermRef => Select(ref(pre), tp) + case pre => SelectFromTypeTree(TypeTree(pre), tp) + } // no checks necessary + + def ref(sym: Symbol)(implicit ctx: Context): tpd.NameTree = + ref(NamedType(sym.owner.thisType, sym.name).withDenot(sym)) + + /** new C(args) */ + def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = + Apply( + Select( + New(tp), + TermRef.withSym(tp.normalizedPrefix, tp.typeSymbol.primaryConstructor.asTerm)), + args) + + /** An object def + * + * object obs extends parents { decls } + * + * gets expanded to + * + * <module> lazy val obj = { + * class obj$ extends parents { this: obj.type => decls } + * new obj$ + * } + * + * What's interesting here is that the block is well typed + * (because class obj$ is hoistable), but the type of the `obj` val is + * not expressible. What needs to happen in general when + * inferring the type of a val from its RHS, is: if the type contains + * a class that has the val itself as owner, then that class + * is remapped to have the val's owner as owner. Remapping could be + * done by cloning the class with the new owner and substituting + * everywhere in the tree. We know that remapping is safe + * because the only way a local class can appear in the RHS of a val is + * by being hoisted outside of a block, and the necessary checks are + * done at this point already. + * + * On the other hand, for method result type inference, if the type of + * the RHS of a method contains a class owned by the method, this would be + * an error. + */ + def ModuleDef(sym: TermSymbol, body: List[Tree])(implicit ctx: Context): tpd.TempTrees = { + val modcls = sym.moduleClass.asClass + val constr = DefDef(modcls.primaryConstructor.asTerm, EmptyTree) + val clsdef = ClassDef(modcls, Nil, constr, body) + val valdef = ValDef(sym, New(modcls.typeConstructor)) + TempTrees(valdef :: clsdef :: Nil) + } + + /** A function def + * + * vparams => expr + * + * gets expanded to + * + * { def $anonfun(vparams) = expr; $anonfun: pt } + * + * where pt is the target type of the expression (FunctionN) unless + * otherwise specified. + */ + def Function(meth: TermSymbol, body: 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) + defn.FunctionType(formals, mt.resultType) + } + Block( + DefDef(meth, body) :: Nil, + Typed(Ident(TermRef.withSym(NoPrefix, meth)), TypeTree(funtpe))) + } + + private class FindLocalDummyAccumulator(cls: ClassSymbol)(implicit ctx: Context) extends TreeAccumulator[Symbol] { + def apply(sym: Symbol, tree: Tree) = + if (sym.exists) sym + else if (tree.isDef) { + val owner = tree.symbol.owner + if (owner.isLocalDummy && owner.owner == cls) owner + else if (owner == cls) foldOver(sym, tree) + else sym + } else foldOver(sym, tree) } implicit class TreeOps[ThisTree <: tpd.Tree](val tree: ThisTree) extends AnyVal { @@ -357,7 +354,7 @@ object TypedTrees { new TreeMapper(ownerMap = (sym => if (sym == from) to else sym)).apply(tree) } - class TreeMapper(val typeMap: TypeMap = IdentityTypeMap, val ownerMap: Symbol => Symbol = identity)(implicit ctx: Context) extends TreeTransformer[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 = { val tree1 = if (tree.isEmpty) tree @@ -381,7 +378,7 @@ object TypedTrees { val mapped = ctx.mapSymbols(locals, typeMap, ownerMap) if (locals eq mapped) super.transform(trees) else withSubstitution(locals, mapped).transform(trees) - } + } def apply[ThisTree <: tpd.Tree](tree: ThisTree): ThisTree = transform(tree).asInstanceOf[ThisTree] @@ -403,3 +400,4 @@ object TypedTrees { def localSyms(stats: List[tpd.Tree])(implicit ctx: Context): List[Symbol] = for (stat <- stats if (stat.isDef)) yield stat.symbol } + diff --git a/src/dotty/tools/dotc/ast/UntypedTrees.scala b/src/dotty/tools/dotc/ast/UntypedTrees.scala index c7f468134..16a1efa03 100644 --- a/src/dotty/tools/dotc/ast/UntypedTrees.scala +++ b/src/dotty/tools/dotc/ast/UntypedTrees.scala @@ -4,484 +4,481 @@ package ast import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ -import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, TypedTrees._ +import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ import TreeInfo._ import Decorators._ import language.higherKinds import collection.mutable.ListBuffer -object UntypedTrees { +object untpd extends Trees.Instance[Untyped] { - object untpd extends Trees.Instance[Untyped] { + // ----- Tree cases that exist in untyped form only ------------------ - // ----- Tree cases that exist in untyped form only ------------------ + /** A typed subtree of an untyped tree needs to be wrapped in a TypedSlice */ + case class TypedSplice(tree: TypedTree) extends UntypedTree - /** A typed subtree of an untyped tree needs to be wrapped in a TypedSlice */ - case class TypedSplice(tree: TypedTree) extends UntypedTree + /** mods object name impl */ + case class ModuleDef(mods: Modifiers, name: TermName, impl: Template) + extends NameTree with ModDefTree { + type ThisTree[T >: Untyped] <: Trees.NameTree[T] with Trees.ModDefTree[T] with ModuleDef + } - /** mods object name impl */ - case class ModuleDef(mods: Modifiers, name: TermName, impl: Template) - extends NameTree with ModDefTree { - type ThisTree[T >: Untyped] <: Trees.NameTree[T] with Trees.ModDefTree[T] with ModuleDef - } + /** (vparams) => body */ + case class SymbolLit(str: String) extends Tree + case class InterpolatedString(id: TermName, strings: List[Literal], elems: List[Tree]) extends Tree + case class Function(args: List[Tree], body: Tree) extends Tree + case class InfixOp(left: Tree, op: Name, right: Tree) extends Tree + case class PostfixOp(tree: Tree, op: Name) extends Tree + case class PrefixOp(op: Name, tree: Tree) extends Tree + case class Parens(tree: Tree) extends Tree { + def derivedParens(tree: Tree) = if (this.tree eq tree) this else Parens(tree).copyAttr(this) + } + case class Tuple(trees: List[Tree]) extends Tree { + def derivedTuple(trees: List[Tree]) = if (this.trees eq trees) this else Tuple(trees).copyAttr(this) + } + case class WhileDo(cond: Tree, body: Tree) extends TermTree + case class DoWhile(body: Tree, cond: Tree) extends TermTree + case class ForYield(enums: List[Tree], expr: Tree) extends TermTree + case class ForDo(enums: List[Tree], body: Tree) extends TermTree + case class GenFrom(pat: Tree, expr: Tree) extends Tree + case class GenAlias(pat: Tree, expr: Tree) extends Tree + case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree]) extends TypTree + case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree) extends Tree - /** (vparams) => body */ - case class SymbolLit(str: String) extends Tree - case class InterpolatedString(id: TermName, strings: List[Literal], elems: List[Tree]) extends Tree - case class Function(args: List[Tree], body: Tree) extends Tree - case class InfixOp(left: Tree, op: Name, right: Tree) extends Tree - case class PostfixOp(tree: Tree, op: Name) extends Tree - case class PrefixOp(op: Name, tree: Tree) extends Tree - case class Parens(tree: Tree) extends Tree { - def derivedParens(tree: Tree) = if (this.tree eq tree) this else Parens(tree).copyAttr(this) - } - case class Tuple(trees: List[Tree]) extends Tree { - def derivedTuple(trees: List[Tree]) = if (this.trees eq trees) this else Tuple(trees).copyAttr(this) - } - case class WhileDo(cond: Tree, body: Tree) extends TermTree - case class DoWhile(body: Tree, cond: Tree) extends TermTree - case class ForYield(enums: List[Tree], expr: Tree) extends TermTree - case class ForDo(enums: List[Tree], body: Tree) extends TermTree - case class GenFrom(pat: Tree, expr: Tree) extends Tree - case class GenAlias(pat: Tree, expr: Tree) extends Tree - case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree]) extends TypTree - case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree) extends Tree + val unitLiteral = Literal(Constant()) - val unitLiteral = Literal(Constant()) + private type VarInfo = (NameTree, Tree) - private type VarInfo = (NameTree, Tree) + def ref(tp: NamedType)(implicit ctx: Context): Tree = + TypedSplice(tpd.ref(tp)) - def ref(tp: NamedType)(implicit ctx: Context): Tree = - TypedSplice(tpd.ref(tp)) + def scalaUnit(implicit ctx: Context) = ref(defn.UnitClass.typeConstructor) - def scalaUnit(implicit ctx: Context) = ref(defn.UnitClass.typeConstructor) + def makeConstructor(mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree = EmptyTree())(implicit ctx: Context): DefDef = + DefDef(mods, nme.CONSTRUCTOR, Nil, vparamss, TypeTree(), rhs) - def makeConstructor(mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree = EmptyTree())(implicit ctx: Context): DefDef = - DefDef(mods, nme.CONSTRUCTOR, Nil, vparamss, TypeTree(), rhs) + def makeSelfDef(name: TermName, tpt: Tree)(implicit ctx: Context) = + ValDef(Modifiers(Private), name, tpt, EmptyTree()) - def makeSelfDef(name: TermName, tpt: Tree)(implicit ctx: Context) = - ValDef(Modifiers(Private), name, tpt, EmptyTree()) + def makeTupleOrParens(ts: List[Tree])(implicit ctx: Context) = ts match { + case t :: Nil => Parens(t) + case _ => Tuple(ts) + } - def makeTupleOrParens(ts: List[Tree])(implicit ctx: Context) = ts match { - case t :: Nil => Parens(t) - case _ => Tuple(ts) - } + def makeTuple(ts: List[Tree])(implicit ctx: Context) = ts match { + case t :: Nil => t + case _ => Tuple(ts) + } - def makeTuple(ts: List[Tree])(implicit ctx: Context) = ts match { - case t :: Nil => t - case _ => Tuple(ts) - } + /** new C(args) */ + def makeNew(tpt: Tree, args: List[Tree])(implicit ctx: Context): Apply = + Apply(Select(Trees.New(tpt), nme.CONSTRUCTOR), args) + + def makeSyntheticParameter(pname: TermName)(implicit ctx: Context): ValDef = + ValDef(Modifiers(SyntheticTermParam), pname, TypeTree(), EmptyTree()) - /** new C(args) */ - def makeNew(tpt: Tree, args: List[Tree])(implicit ctx: Context): Apply = - Apply(Select(Trees.New(tpt), nme.CONSTRUCTOR), args) + def desugar(tree: Tree, mode: Mode.Value)(implicit ctx: Context): Tree = { - def makeSyntheticParameter(pname: TermName)(implicit ctx: Context): ValDef = - ValDef(Modifiers(SyntheticTermParam), pname, TypeTree(), EmptyTree()) + def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree) = { + val ldef = DefDef(Modifiers(Label), lname, Nil, ListOfNil, TypeTree(), rhs) + Block(ldef, call) + } - def desugar(tree: Tree, mode: Mode.Value)(implicit ctx: Context): Tree = { + def derivedValDef(mods: Modifiers, named: NameTree, tpt: Tree, rhs: Tree) = + ValDef(mods, named.name.asTermName, tpt, rhs).withPos(named.pos) - def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree) = { - val ldef = DefDef(Modifiers(Label), lname, Nil, ListOfNil, TypeTree(), rhs) - Block(ldef, call) + /** Translate infix operation expression left op right + */ + 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 _ => arg + } + if (isLeftAssoc(op)) { + val args: List[Tree] = right match { + case Parens(arg) => assignToNamedArg(arg) :: Nil + case Tuple(args) => args mapConserve assignToNamedArg + case _ => right :: Nil + } + Apply(Select(left, op.encode), args) + } else { + val x = ctx.freshName().toTermName + Block( + ValDef(Modifiers(Synthetic), x, TypeTree(), left), + Apply(Select(right, op.encode), Ident(x))) } + } - def derivedValDef(mods: Modifiers, named: NameTree, tpt: Tree, rhs: Tree) = - ValDef(mods, named.name.asTermName, tpt, rhs).withPos(named.pos) + /** Create tree for for-comprehension <for (enums) do body> or + * <for (enums) yield body> where mapName and flatMapName are chosen + * corresponding to whether this is a for-do or a for-yield. + * The creation performs the following rewrite rules: + * + * 1. + * + * for (P <- G) E ==> G.foreach (P => E) + * + * Here and in the following (P => E) is interpreted as the function (P => E) + * if P is a variable pattern and as the partial function { case P => E } otherwise. + * + * 2. + * + * for (P <- G) yield E ==> G.map (P => E) + * + * 3. + * + * for (P_1 <- G_1; P_2 <- G_2; ...) ... + * ==> + * G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...) + * + * 4. + * + * for (P <- G; E; ...) ... + * => + * for (P <- G.filter (P => E); ...) ... + * + * 5. For any N: + * + * for (P_1 <- G; P_2 = E_2; val P_N = E_N; ...) + * ==> + * for (TupleN(P_1, P_2, ... P_N) <- + * for (x_1 @ P_1 <- G) yield { + * val x_2 @ P_2 = E_2 + * ... + * val x_N & P_N = E_N + * TupleN(x_1, ..., x_N) + * } ...) + * + * If any of the P_i are variable patterns, the corresponding `x_i @ P_i' is not generated + * and the variable constituting P_i is used instead of x_i + * + * @param mapName The name to be used for maps (either map or foreach) + * @param flatMapName The name to be used for flatMaps (either flatMap or foreach) + * @param enums The enumerators in the for expression + * @param body The body of the for expression + */ + def makeFor(mapName: TermName, flatMapName: TermName, enums: List[Tree], body: Tree): Tree = { - /** Translate infix operation expression left op right + /** Make a function value pat => body. + * If pat is a var pattern id: T then this gives (id: T) => body + * Otherwise this gives { case pat => body } */ - 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 _ => arg - } - if (isLeftAssoc(op)) { - val args: List[Tree] = right match { - case Parens(arg) => assignToNamedArg(arg) :: Nil - case Tuple(args) => args mapConserve assignToNamedArg - case _ => right :: Nil - } - Apply(Select(left, op.encode), args) - } else { - val x = ctx.freshName().toTermName - Block( - ValDef(Modifiers(Synthetic), x, TypeTree(), left), - Apply(Select(right, op.encode), Ident(x))) - } + def makeLambda(pat: Tree, body: Tree): Tree = pat match { + case VarPattern(named, tpt) => + Function(derivedValDef(Modifiers(Param), named, tpt, EmptyTree()) :: Nil, body) + case _ => + Match(EmptyTree(), CaseDef(pat, EmptyTree(), body) :: Nil) } - /** Create tree for for-comprehension <for (enums) do body> or - * <for (enums) yield body> where mapName and flatMapName are chosen - * corresponding to whether this is a for-do or a for-yield. - * The creation performs the following rewrite rules: - * - * 1. - * - * for (P <- G) E ==> G.foreach (P => E) - * - * Here and in the following (P => E) is interpreted as the function (P => E) - * if P is a variable pattern and as the partial function { case P => E } otherwise. - * - * 2. - * - * for (P <- G) yield E ==> G.map (P => E) - * - * 3. - * - * for (P_1 <- G_1; P_2 <- G_2; ...) ... - * ==> - * G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...) - * - * 4. - * - * for (P <- G; E; ...) ... - * => - * for (P <- G.filter (P => E); ...) ... - * - * 5. For any N: - * - * for (P_1 <- G; P_2 = E_2; val P_N = E_N; ...) - * ==> - * for (TupleN(P_1, P_2, ... P_N) <- - * for (x_1 @ P_1 <- G) yield { - * val x_2 @ P_2 = E_2 - * ... - * val x_N & P_N = E_N - * TupleN(x_1, ..., x_N) - * } ...) - * - * If any of the P_i are variable patterns, the corresponding `x_i @ P_i' is not generated - * and the variable constituting P_i is used instead of x_i - * - * @param mapName The name to be used for maps (either map or foreach) - * @param flatMapName The name to be used for flatMaps (either flatMap or foreach) - * @param enums The enumerators in the for expression - * @param body The body of the for expression + /** If `pat` is not yet a `Bind` wrap it in one with a fresh name */ - def makeFor(mapName: TermName, flatMapName: TermName, enums: List[Tree], body: Tree): Tree = { - - /** Make a function value pat => body. - * If pat is a var pattern id: T then this gives (id: T) => body - * Otherwise this gives { case pat => body } - */ - def makeLambda(pat: Tree, body: Tree): Tree = pat match { - case VarPattern(named, tpt) => - Function(derivedValDef(Modifiers(Param), named, tpt, EmptyTree()) :: Nil, body) - case _ => - Match(EmptyTree(), CaseDef(pat, EmptyTree(), body) :: Nil) - } - - /** If `pat` is not yet a `Bind` wrap it in one with a fresh name - */ - def makeBind(pat: Tree): Tree = pat match { - case Bind(_, _) => pat - case _ => Bind(ctx.freshName().toTermName, pat) - } - - /** Is pattern `pat` irrefutable when matched against `rhs`? - * We only can do a simple syntactic check here; a more refined check - * is done later prompted by the presence of a "withFilterIfRefutable" call. - */ - def isIrrefutable(pat: Tree, rhs: Tree): Boolean = { - def matchesTuple(pats: List[Tree], rhs: Tree): Boolean = rhs match { - case Tuple(trees) => (pats corresponds trees)(isIrrefutable) - case Parens(rhs1) => matchesTuple(pats, rhs1) - case Block(_, rhs1) => matchesTuple(pats, rhs1) - case If(_, thenp, elsep) => matchesTuple(pats, thenp) && matchesTuple(pats, elsep) - case Match(_, cases) => cases forall (matchesTuple(pats, _)) - case CaseDef(_, _, rhs1) => matchesTuple(pats, rhs) - case Throw(_) => true - case _ => false - } - pat match { - case Bind(_, pat1) => isIrrefutable(pat1, rhs) - case Parens(pat1) => isIrrefutable(pat1, rhs) - case Tuple(pats) => matchesTuple(pats, rhs) - case _ => isVarPattern(pat) - } - } - - /** Make a pattern filter: - * rhs.withFilterIfRefutable { case pat => true case _ => false } - */ - def makePatFilter(rhs: Tree, pat: Tree): Tree = { - val cases = List( - CaseDef(pat, EmptyTree(), Literal(Constant(true))), - CaseDef(Ident(nme.WILDCARD), EmptyTree(), Literal(Constant(false)))) - Apply(Select(rhs, nme.withFilterIfRefutable), Match(EmptyTree(), cases)) - } + def makeBind(pat: Tree): Tree = pat match { + case Bind(_, _) => pat + case _ => Bind(ctx.freshName().toTermName, pat) + } - /** rhs.name with a pattern filter on rhs unless `pat` is irrefutable when - * matched against `rhs`. - */ - def rhsSelect(rhs: Tree, name: TermName, pat: Tree) = { - val rhs1 = if (isIrrefutable(pat, rhs)) rhs else makePatFilter(rhs, pat) - Select(rhs1, name) + /** Is pattern `pat` irrefutable when matched against `rhs`? + * We only can do a simple syntactic check here; a more refined check + * is done later prompted by the presence of a "withFilterIfRefutable" call. + */ + def isIrrefutable(pat: Tree, rhs: Tree): Boolean = { + def matchesTuple(pats: List[Tree], rhs: Tree): Boolean = rhs match { + case Tuple(trees) => (pats corresponds trees)(isIrrefutable) + case Parens(rhs1) => matchesTuple(pats, rhs1) + case Block(_, rhs1) => matchesTuple(pats, rhs1) + case If(_, thenp, elsep) => matchesTuple(pats, thenp) && matchesTuple(pats, elsep) + case Match(_, cases) => cases forall (matchesTuple(pats, _)) + case CaseDef(_, _, rhs1) => matchesTuple(pats, rhs) + case Throw(_) => true + case _ => false } - - enums match { - case (enum @ GenFrom(pat, rhs)) :: Nil => - Apply(rhsSelect(rhs, mapName, pat), makeLambda(pat, body)) - case GenFrom(pat, rhs) :: (rest @ (GenFrom(_, _) :: _)) => - val cont = makeFor(mapName, flatMapName, rest, body) - Apply(rhsSelect(rhs, flatMapName, pat), makeLambda(pat, cont)) - case (enum @ GenFrom(pat, rhs)) :: (rest @ GenAlias(_, _) :: _) => - val (valeqs, rest1) = rest.span(_.isInstanceOf[GenAlias]) - val pats = valeqs map { case GenAlias(pat, _) => pat } - val rhss = valeqs map { case GenAlias(_, rhs) => rhs } - val defpat1 = makeBind(pat) - val defpats = pats map makeBind - val pdefs = (defpats, rhss).zipped map (makePatDef(Modifiers(), _, _)) - val ids = (defpat1 :: defpats) map { case Bind(name, _) => Ident(name) } - val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat1, rhs) :: Nil, Block(pdefs, makeTuple(ids))) - val allpats = pat :: pats - val vfrom1 = GenFrom(makeTuple(allpats), rhs1) - makeFor(mapName, flatMapName, vfrom1 :: rest1, body) - case (enum @ GenFrom(pat, rhs)) :: test :: rest => - val filtered = Apply(rhsSelect(rhs, nme.withFilter, pat), makeLambda(pat, test)) - makeFor(mapName, flatMapName, GenFrom(pat, filtered) :: rest, body) - case _ => - EmptyTree() //may happen for erroneous input + pat match { + case Bind(_, pat1) => isIrrefutable(pat1, rhs) + case Parens(pat1) => isIrrefutable(pat1, rhs) + case Tuple(pats) => matchesTuple(pats, rhs) + case _ => isVarPattern(pat) } } - def makeAnnotated(cls: Symbol, tree: Tree) = - Annotated(TypedSplice(tpd.New(cls.typeConstructor)), tree) - - /** Returns list of all pattern variables, possibly with their types, - * without duplicates - */ - def getVariables(tree: Tree): List[VarInfo] = - getVars(new ListBuffer[VarInfo], tree).toList - - /** In case there is exactly one variable x_1 in pattern - * val/var p = e ==> val/var x_1 = (e: @unchecked) match (case p => (x_1)) - * - * in case there are zero or more than one variables in pattern - * val/var p = e ==> private synthetic val t$ = (e: @unchecked) match (case p => (x_1, ..., x_N)) - * val/var x_1 = t$._1 - * ... - * val/var x_N = t$._N - * If the original pattern variable carries a type annotation, so does the corresponding - * ValDef. + /** Make a pattern filter: + * rhs.withFilterIfRefutable { case pat => true case _ => false } */ - def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree): Tree = pat match { - case VarPattern(named, tpt) => - derivedValDef(mods, named, tpt, rhs) - case _ => - val rhsUnchecked = makeAnnotated(defn.UncheckedAnnot, rhs) - val vars = getVariables(pat) - val ids = for ((named, _) <- vars) yield Ident(named.name) - val caseDef = CaseDef(pat, EmptyTree(), makeTuple(ids)) - val matchExpr = Match(rhsUnchecked, caseDef :: Nil) - vars match { - case (named, tpt) :: Nil => - derivedValDef(mods, named, tpt, matchExpr) - case _ => - val tmpName = ctx.freshName().toTermName - val patMods = Modifiers(PrivateLocal | Synthetic | (mods.flags & Lazy)) - val firstDef = ValDef(patMods, tmpName, TypeTree(), matchExpr) - def selector(n: Int) = Select(Ident(tmpName), ("_" + n).toTermName) - val restDefs = - for (((named, tpt), n) <- vars.zipWithIndex) - yield derivedValDef(mods, named, tpt, selector(n)) - TempTrees(firstDef :: restDefs) - } + def makePatFilter(rhs: Tree, pat: Tree): Tree = { + val cases = List( + CaseDef(pat, EmptyTree(), Literal(Constant(true))), + CaseDef(Ident(nme.WILDCARD), EmptyTree(), Literal(Constant(false)))) + Apply(Select(rhs, nme.withFilterIfRefutable), Match(EmptyTree(), cases)) } - def isPatternVar(id: Ident) = - mode == Mode.Pattern && isVarPattern(id) && id.name != nme.WILDCARD - - // begin desugar - tree match { // todo: move general tree desugaring to typer, and keep only untyped trees here? - case id @ Ident(_) if isPatternVar(id) => - Bind(id.name, Ident(nme.WILDCARD)) - case Typed(id @ Ident(_), tpt) if isPatternVar(id) => - Bind(id.name, Typed(Ident(nme.WILDCARD), tpt)).withPos(id.pos) - case New(templ: Template) => - desugarAnonClass(templ) - case Assign(Apply(fn, args), rhs) => - Apply(Select(fn, nme.update), args :+ rhs) - case If(cond, thenp, EmptyTree()) => - If(cond, thenp, unitLiteral) - case _: DefDef | _: ClassDef => - desugarContextBounds(tree) - case ModuleDef(mods, name, tmpl @ Template(constr, parents, self, body)) => - // <module> val name: name$ = New(name$) - // <module> final class name$ extends parents { self: name.type => body } - val clsName = name.moduleClassName - val clsRef = Ident(clsName) - val modul = ValDef(mods | ModuleCreationFlags, name, clsRef, clsRef) - val clsSelf = self.derivedValDef(self.mods, self.name, SingletonTypeTree(Ident(name)), self.rhs) - val clsTmpl = tmpl.derivedTemplate(constr, parents, clsSelf, body) - val cls = ClassDef(mods & AccessFlags | ModuleClassCreationFlags, clsName, Nil, clsTmpl) - TempTrees(List(modul, cls)) - case SymbolLit(str) => - makeNew(ref(defn.SymbolClass.typeConstructor), Literal(Constant(str)) :: Nil) - case InterpolatedString(id, strs, elems) => - Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems) - case Function(args, body) => - if (mode == Mode.Type) // FunctionN[args: _*, body] - AppliedTypeTree( - ref(defn.FunctionClass(args.length).typeConstructor), - args :+ body) - else { // { def $anonfun(args) = body; $anonfun } - val params = args.asInstanceOf[List[ValDef]] - Block( - DefDef(Modifiers(Synthetic), nme.ANON_FUN, Nil, params :: Nil, EmptyTree(), body), - Ident(nme.ANON_FUN)) - } - case InfixOp(l, op, r) => - mode match { - case Mode.Expr => // l.op'(r), or val x = r; l.op;(x), plus handle named args specially - makeBinop(l, op, r) - case Mode.Pattern => // op'(l, r) - Apply(Ident(op.encode), l :: r :: Nil) - case Mode.Type => // op'[l, r] - AppliedTypeTree(Ident(op.encode), l :: r :: Nil) - } - case PostfixOp(t, op) => - if (mode == Mode.Type && op == nme.raw.STAR) - AppliedTypeTree(ref(defn.RepeatedParamType), t) - else { - assert(mode == Mode.Expr) - if (op == nme.WILDCARD) tree // desugar later by eta expansion - else Select(t, op.encode) - } - case PrefixOp(op, t) => - if (mode == Mode.Type && op == nme.ARROWkw) - AppliedTypeTree(ref(defn.ByNameParamClass.typeConstructor), t) - else - Select(t, nme.UNARY_PREFIX ++ op.encode) - case Parens(t) => - t - case Tuple(ts) => - def PairTypeTree(l: Tree, r: Tree) = - AppliedTypeTree(ref(defn.PairClass.typeConstructor), l :: r :: Nil) - if (mode == Mode.Type) ts.reduceRight(PairTypeTree) - else if (ts.isEmpty) unitLiteral - else ts.reduceRight(Pair(_, _)) - case WhileDo(cond, body) => - // { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() } - val call = Apply(Ident(nme.WHILE_PREFIX), Nil) - val rhs = If(cond, Block(body, call), unitLiteral) - labelDefAndCall(nme.WHILE_PREFIX, rhs, call) - case DoWhile(body, cond) => - // { label def doWhile$(): Unit = { body; if (cond) doWhile$() } ; doWhile$() } - val call = Apply(Ident(nme.DO_WHILE_PREFIX), Nil) - val rhs = Block(body, If(cond, call, unitLiteral)) - labelDefAndCall(nme.DO_WHILE_PREFIX, rhs, call) - case ForDo(enums, body) => - makeFor(nme.foreach, nme.foreach, enums, body) orElse tree - case ForYield(enums, body) => - 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)) - combine(pats1 map (makePatDef(mods, _, rhs))) - case _ => - tree - } - }.withPos(tree.pos) - - def desugarContextBounds(tparams: List[TypeDef], vparamss: List[List[ValDef]], ofClass: Boolean): (List[TypeDef], List[List[ValDef]]) = { - val epbuf = new ListBuffer[ValDef] - def makeEvidenceParam(cxBound: Tree): ValDef = ??? - val tparams1 = tparams map { - case tparam @ TypeDef(mods, name, ttparams, ContextBounds(tbounds, cxbounds)) => - for (cxbound <- cxbounds) { - val accessMods = if (ofClass) PrivateOrLocal else EmptyFlags - val epname = (nme.EVIDENCE_PARAM_PREFIX.toString + epbuf.length).toTermName - epbuf += - ValDef(Modifiers(Implicit | Param | accessMods), epname, cxbound, EmptyTree()) - } - tparam.derivedTypeDef(mods, name, ttparams, tbounds) - case tparam => - tparam + /** rhs.name with a pattern filter on rhs unless `pat` is irrefutable when + * matched against `rhs`. + */ + def rhsSelect(rhs: Tree, name: TermName, pat: Tree) = { + val rhs1 = if (isIrrefutable(pat, rhs)) rhs else makePatFilter(rhs, pat) + Select(rhs1, name) } - val evidenceParams = epbuf.toList - val vparamss1 = vparamss.reverse match { - case (vparams @ (vparam :: _)) :: rvparamss if vparam.mods is Implicit => - ((vparams ++ evidenceParams) :: rvparamss).reverse + + enums match { + case (enum @ GenFrom(pat, rhs)) :: Nil => + Apply(rhsSelect(rhs, mapName, pat), makeLambda(pat, body)) + case GenFrom(pat, rhs) :: (rest @ (GenFrom(_, _) :: _)) => + val cont = makeFor(mapName, flatMapName, rest, body) + Apply(rhsSelect(rhs, flatMapName, pat), makeLambda(pat, cont)) + case (enum @ GenFrom(pat, rhs)) :: (rest @ GenAlias(_, _) :: _) => + val (valeqs, rest1) = rest.span(_.isInstanceOf[GenAlias]) + val pats = valeqs map { case GenAlias(pat, _) => pat } + val rhss = valeqs map { case GenAlias(_, rhs) => rhs } + val defpat1 = makeBind(pat) + val defpats = pats map makeBind + val pdefs = (defpats, rhss).zipped map (makePatDef(Modifiers(), _, _)) + val ids = (defpat1 :: defpats) map { case Bind(name, _) => Ident(name) } + val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat1, rhs) :: Nil, Block(pdefs, makeTuple(ids))) + val allpats = pat :: pats + val vfrom1 = GenFrom(makeTuple(allpats), rhs1) + makeFor(mapName, flatMapName, vfrom1 :: rest1, body) + case (enum @ GenFrom(pat, rhs)) :: test :: rest => + val filtered = Apply(rhsSelect(rhs, nme.withFilter, pat), makeLambda(pat, test)) + makeFor(mapName, flatMapName, GenFrom(pat, filtered) :: rest, body) case _ => - vparamss :+ evidenceParams + EmptyTree() //may happen for erroneous input } - (tparams1, vparamss1) - } - - def desugarContextBounds(tree: Tree): Tree = tree match { - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - val (tparams1, vparamss1) = - desugarContextBounds(tparams, vparamss, ofClass = false) - tree.derivedDefDef(mods, name, tparams1, vparamss, tpt, rhs) - case ClassDef( - mods, name, tparams, templ @ Template(constr, parents, self, body)) => - val (tparams1, vparamss1) = - desugarContextBounds(tparams, constr.vparamss, ofClass = true) - val constr1 = constr.derivedDefDef( - constr.mods, constr.name, constr.tparams, vparamss1, constr.tpt, constr.rhs) - val templ1 = templ.derivedTemplate(constr1, parents, self, body) - tree.derivedClassDef(mods, name, tparams1, templ1) - case _ => tree } - def desugarAnonClass(templ: Template): Tree = { - val x = tpnme.ANON_CLASS - val clsDef = ClassDef(Modifiers(Final), x, Nil, templ) - Block(clsDef, New(Ident(x), Nil)) - } - - object Mode extends Enumeration { - val Type, Expr, Pattern = Value - } + def makeAnnotated(cls: Symbol, tree: Tree) = + Annotated(TypedSplice(tpd.New(cls.typeConstructor)), tree) - /** If tree is a variable pattern, return its name and type, otherwise return None. + /** Returns list of all pattern variables, possibly with their types, + * without duplicates */ - private object VarPattern { - def unapply(tree: Tree): Option[VarInfo] = tree match { - case id: Ident => Some(id, TypeTree()) - case Typed(id: Ident, tpt) => Some((id, tpt)) - case _ => None - } - } + def getVariables(tree: Tree): List[VarInfo] = + getVars(new ListBuffer[VarInfo], tree).toList - /** Traverse pattern and collect all variable names with their types in buffer. - * Works for expanded as well as unexpanded patterns + /** In case there is exactly one variable x_1 in pattern + * val/var p = e ==> val/var x_1 = (e: @unchecked) match (case p => (x_1)) * + * in case there are zero or more than one variables in pattern + * val/var p = e ==> private synthetic val t$ = (e: @unchecked) match (case p => (x_1, ..., x_N)) + * val/var x_1 = t$._1 + * ... + * val/var x_N = t$._N + * If the original pattern variable carries a type annotation, so does the corresponding + * ValDef. */ - private object getVars extends TreeAccumulator[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] = - if (seenName(named.name)) buf else buf += ((named, t)) - tree match { - case Bind(nme.WILDCARD, _) => - foldOver(buf, tree) - case tree @ Bind(_, Typed(tree1, tpt)) if !mayBeTypePat(tpt) => - apply(add(tree, tpt), tree1) - case tree @ Bind(_, tree1) => - apply(add(tree, TypeTree()), tree1) - case Typed(id: Ident, t) if isVarPattern(id) => - add(id, t) - case id: Ident if isVarPattern(id) => - add(id, TypeTree()) + def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree): Tree = pat match { + case VarPattern(named, tpt) => + derivedValDef(mods, named, tpt, rhs) + case _ => + val rhsUnchecked = makeAnnotated(defn.UncheckedAnnot, rhs) + val vars = getVariables(pat) + val ids = for ((named, _) <- vars) yield Ident(named.name) + val caseDef = CaseDef(pat, EmptyTree(), makeTuple(ids)) + val matchExpr = Match(rhsUnchecked, caseDef :: Nil) + vars match { + case (named, tpt) :: Nil => + derivedValDef(mods, named, tpt, matchExpr) case _ => - foldOver(buf, tree) + val tmpName = ctx.freshName().toTermName + val patMods = Modifiers(PrivateLocal | Synthetic | (mods.flags & Lazy)) + val firstDef = ValDef(patMods, tmpName, TypeTree(), matchExpr) + def selector(n: Int) = Select(Ident(tmpName), ("_" + n).toTermName) + val restDefs = + for (((named, tpt), n) <- vars.zipWithIndex) + yield derivedValDef(mods, named, tpt, selector(n)) + TempTrees(firstDef :: restDefs) } - } } - implicit class UntypedTreeDecorator(val self: Tree) extends AnyVal { - def locateEnclosing(base: List[Tree], pos: Position): List[Tree] = { - def encloses(elem: Any) = elem match { - case t: Tree => t.envelope contains pos - case _ => false + def isPatternVar(id: Ident) = + mode == Mode.Pattern && isVarPattern(id) && id.name != nme.WILDCARD + + // begin desugar + tree match { // todo: move general tree desugaring to typer, and keep only untyped trees here? + case id @ Ident(_) if isPatternVar(id) => + Bind(id.name, Ident(nme.WILDCARD)) + case Typed(id @ Ident(_), tpt) if isPatternVar(id) => + Bind(id.name, Typed(Ident(nme.WILDCARD), tpt)).withPos(id.pos) + case New(templ: Template) => + desugarAnonClass(templ) + case Assign(Apply(fn, args), rhs) => + Apply(Select(fn, nme.update), args :+ rhs) + case If(cond, thenp, EmptyTree()) => + If(cond, thenp, unitLiteral) + case _: DefDef | _: ClassDef => + desugarContextBounds(tree) + case ModuleDef(mods, name, tmpl @ Template(constr, parents, self, body)) => + // <module> val name: name$ = New(name$) + // <module> final class name$ extends parents { self: name.type => body } + val clsName = name.moduleClassName + val clsRef = Ident(clsName) + val modul = ValDef(mods | ModuleCreationFlags, name, clsRef, clsRef) + val clsSelf = self.derivedValDef(self.mods, self.name, SingletonTypeTree(Ident(name)), self.rhs) + val clsTmpl = tmpl.derivedTemplate(constr, parents, clsSelf, body) + val cls = ClassDef(mods & AccessFlags | ModuleClassCreationFlags, clsName, Nil, clsTmpl) + TempTrees(List(modul, cls)) + case SymbolLit(str) => + makeNew(ref(defn.SymbolClass.typeConstructor), Literal(Constant(str)) :: Nil) + case InterpolatedString(id, strs, elems) => + Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems) + case Function(args, body) => + if (mode == Mode.Type) // FunctionN[args: _*, body] + AppliedTypeTree( + ref(defn.FunctionClass(args.length).typeConstructor), + args :+ body) + else { // { def $anonfun(args) = body; $anonfun } + val params = args.asInstanceOf[List[ValDef]] + Block( + DefDef(Modifiers(Synthetic), nme.ANON_FUN, Nil, params :: Nil, EmptyTree(), body), + Ident(nme.ANON_FUN)) } - base.productIterator find encloses match { - case Some(tree: Tree) => locateEnclosing(tree :: base, pos) - case none => base + case InfixOp(l, op, r) => + mode match { + case Mode.Expr => // l.op'(r), or val x = r; l.op;(x), plus handle named args specially + makeBinop(l, op, r) + case Mode.Pattern => // op'(l, r) + Apply(Ident(op.encode), l :: r :: Nil) + case Mode.Type => // op'[l, r] + AppliedTypeTree(Ident(op.encode), l :: r :: Nil) } + case PostfixOp(t, op) => + if (mode == Mode.Type && op == nme.raw.STAR) + AppliedTypeTree(ref(defn.RepeatedParamType), t) + else { + assert(mode == Mode.Expr) + if (op == nme.WILDCARD) tree // desugar later by eta expansion + else Select(t, op.encode) + } + case PrefixOp(op, t) => + if (mode == Mode.Type && op == nme.ARROWkw) + AppliedTypeTree(ref(defn.ByNameParamClass.typeConstructor), t) + else + Select(t, nme.UNARY_PREFIX ++ op.encode) + case Parens(t) => + t + case Tuple(ts) => + def PairTypeTree(l: Tree, r: Tree) = + AppliedTypeTree(ref(defn.PairClass.typeConstructor), l :: r :: Nil) + if (mode == Mode.Type) ts.reduceRight(PairTypeTree) + else if (ts.isEmpty) unitLiteral + else ts.reduceRight(Pair(_, _)) + case WhileDo(cond, body) => + // { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() } + val call = Apply(Ident(nme.WHILE_PREFIX), Nil) + val rhs = If(cond, Block(body, call), unitLiteral) + labelDefAndCall(nme.WHILE_PREFIX, rhs, call) + case DoWhile(body, cond) => + // { label def doWhile$(): Unit = { body; if (cond) doWhile$() } ; doWhile$() } + val call = Apply(Ident(nme.DO_WHILE_PREFIX), Nil) + val rhs = Block(body, If(cond, call, unitLiteral)) + labelDefAndCall(nme.DO_WHILE_PREFIX, rhs, call) + case ForDo(enums, body) => + makeFor(nme.foreach, nme.foreach, enums, body) orElse tree + case ForYield(enums, body) => + 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)) + combine(pats1 map (makePatDef(mods, _, rhs))) + case _ => + tree + } + }.withPos(tree.pos) + + def desugarContextBounds(tparams: List[TypeDef], vparamss: List[List[ValDef]], ofClass: Boolean): (List[TypeDef], List[List[ValDef]]) = { + val epbuf = new ListBuffer[ValDef] + def makeEvidenceParam(cxBound: Tree): ValDef = ??? + val tparams1 = tparams map { + case tparam @ TypeDef(mods, name, ttparams, ContextBounds(tbounds, cxbounds)) => + for (cxbound <- cxbounds) { + val accessMods = if (ofClass) PrivateOrLocal else EmptyFlags + val epname = (nme.EVIDENCE_PARAM_PREFIX.toString + epbuf.length).toTermName + epbuf += + ValDef(Modifiers(Implicit | Param | accessMods), epname, cxbound, EmptyTree()) + } + tparam.derivedTypeDef(mods, name, ttparams, tbounds) + case tparam => + tparam + } + val evidenceParams = epbuf.toList + val vparamss1 = vparamss.reverse match { + case (vparams @ (vparam :: _)) :: rvparamss if vparam.mods is Implicit => + ((vparams ++ evidenceParams) :: rvparamss).reverse + case _ => + vparamss :+ evidenceParams + } + (tparams1, vparamss1) + } + + def desugarContextBounds(tree: Tree): Tree = tree match { + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + val (tparams1, vparamss1) = + desugarContextBounds(tparams, vparamss, ofClass = false) + tree.derivedDefDef(mods, name, tparams1, vparamss, tpt, rhs) + case ClassDef( + mods, name, tparams, templ @ Template(constr, parents, self, body)) => + val (tparams1, vparamss1) = + desugarContextBounds(tparams, constr.vparamss, ofClass = true) + val constr1 = constr.derivedDefDef( + constr.mods, constr.name, constr.tparams, vparamss1, constr.tpt, constr.rhs) + val templ1 = templ.derivedTemplate(constr1, parents, self, body) + tree.derivedClassDef(mods, name, tparams1, templ1) + case _ => tree + } + + def desugarAnonClass(templ: Template): Tree = { + val x = tpnme.ANON_CLASS + val clsDef = ClassDef(Modifiers(Final), x, Nil, templ) + Block(clsDef, New(Ident(x), Nil)) + } + + object Mode extends Enumeration { + val Type, Expr, Pattern = Value + } + + /** 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 { + case id: Ident => Some(id, TypeTree()) + case Typed(id: Ident, tpt) => Some((id, tpt)) + case _ => None + } + } + + /** Traverse pattern and collect all variable names with their types in buffer. + * Works for expanded as well as unexpanded patterns + * + */ + private object getVars extends TreeAccumulator[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] = + if (seenName(named.name)) buf else buf += ((named, t)) + tree match { + case Bind(nme.WILDCARD, _) => + foldOver(buf, tree) + case tree @ Bind(_, Typed(tree1, tpt)) if !mayBeTypePat(tpt) => + apply(add(tree, tpt), tree1) + case tree @ Bind(_, tree1) => + apply(add(tree, TypeTree()), tree1) + case Typed(id: Ident, t) if isVarPattern(id) => + add(id, t) + case id: Ident if isVarPattern(id) => + add(id, TypeTree()) + case _ => + foldOver(buf, tree) + } + } + } + + implicit class UntypedTreeDecorator(val self: Tree) extends AnyVal { + def locateEnclosing(base: List[Tree], pos: Position): List[Tree] = { + def encloses(elem: Any) = elem match { + case t: Tree => t.envelope contains pos + case _ => false + } + base.productIterator find encloses match { + case Some(tree: Tree) => locateEnclosing(tree :: base, pos) + case none => base } } } -}
\ No newline at end of file +} diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala index 07ed37f06..bef8499b0 100644 --- a/src/dotty/tools/dotc/core/Annotations.scala +++ b/src/dotty/tools/dotc/core/Annotations.scala @@ -1,7 +1,7 @@ package dotty.tools.dotc package core -import Symbols._, Types._, util.Positions._, Contexts._, Constants._, ast.TypedTrees.tpd._ +import Symbols._, Types._, util.Positions._, Contexts._, Constants._, ast.tpd._ object Annotations { diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 8fcdc2cbd..af8bd6e91 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -9,7 +9,7 @@ import Phases._ import Types._ import Symbols._ import TypeComparers._, NameOps._, SymDenotations._, util.Positions._ -import ast.TypedTrees.tpd._, util.FreshNameCreator +import ast.tpd._, util.FreshNameCreator import config.Settings._ import config.ScalaSettings import reporting._ diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index 8c5474740..0d6f87cda 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -13,8 +13,7 @@ import Contexts._ import SymDenotations._, printing.Texts._ import printing.Printer import Types._, Annotations._, util.Positions._, StdNames._, NameOps._ -import ast.TypedTrees.TreeMapper -import ast.TypedTrees.tpd.SharedTree +import ast.tpd.{TreeMapper, SharedTree} import Denotations.{ Denotation, SingleDenotation, MultiDenotation } import collection.mutable import io.AbstractFile diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 135437671..1b21567a0 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -15,7 +15,7 @@ import SymDenotations._ import Decorators._ import Denotations._ import Periods._ -import ast.TypedTrees.tpd._, ast.TypedTrees.TreeMapper, printing.Texts._ +import ast.tpd._, printing.Texts._ import transform.Erasure import printing.Printer import scala.util.hashing.{ MurmurHash3 => hashing } diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index 9586b9436..8a790d760 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -5,7 +5,7 @@ package pickling import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._ import SymDenotations._, UnPickler._, Constants._, Annotations._, util.Positions._ -import ast.TypedTrees.tpd._ +import ast.tpd._ import java.io.{ File, IOException } import java.lang.Integer.toHexString import scala.collection.{ mutable, immutable } diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index 42899ef44..51816b971 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.TypedTrees.tpd._, ast.TypedTrees.TreeOps +import ast.Trees, ast.tpd._ import printing.Texts._ import printing.Printer import io.AbstractFile diff --git a/src/dotty/tools/dotc/parsing/MarkupParsers.scala b/src/dotty/tools/dotc/parsing/MarkupParsers.scala index 04694a61c..f74ebb509 100644 --- a/src/dotty/tools/dotc/parsing/MarkupParsers.scala +++ b/src/dotty/tools/dotc/parsing/MarkupParsers.scala @@ -35,7 +35,7 @@ import Constants._ */ object MarkupParsers { - import ast.UntypedTrees.untpd._ + import ast.untpd._ case object MissingEndTagControl extends ControlThrowable { override def getMessage = "start tag was here: " diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index f31a93c24..0599c4490 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -25,7 +25,7 @@ import annotation.switch object Parsers { - import ast.UntypedTrees.untpd._ + import ast.untpd._ case class OpInfo(operand: Tree, operator: Name, offset: Offset) diff --git a/src/dotty/tools/dotc/parsing/ScriptParsers.scala b/src/dotty/tools/dotc/parsing/ScriptParsers.scala index 2aab98eaa..bd66c252d 100644 --- a/src/dotty/tools/dotc/parsing/ScriptParsers.scala +++ b/src/dotty/tools/dotc/parsing/ScriptParsers.scala @@ -57,7 +57,7 @@ import Parsers._ */ object ScriptParsers { - import ast.UntypedTrees.untpd._ + import ast.untpd._ class ScriptParser(source: SourceFile)(implicit ctx: Context) extends Parser(source) { diff --git a/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala b/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala index a712a437c..669efcbef 100644 --- a/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala +++ b/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala @@ -7,7 +7,7 @@ import scala.xml.{ EntityRef, Text } import scala.xml.XML.{ xmlns } import core._ import Flags.Mutable -import Names._, NameOps._, StdNames._, Decorators._, ast.Trees._, ast.TypedTrees._, ast.UntypedTrees._, Constants._ +import Names._, NameOps._, StdNames._, Decorators._, ast.Trees._, ast.{tpd, untpd}, Constants._ import Symbols._, Contexts._ import util.Positions._ import Parsers.Parser diff --git a/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused b/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused index c903cc55b..12377ca94 100644 --- a/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused +++ b/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused @@ -10,7 +10,7 @@ import TreeInfo._ /** Methods for building trees, used in the parser. All the trees * returned by this class must be untyped. - * Note: currently unused, should be refactored into UntypedTrees. + * Note: currently unused */ class TreeBuilder(implicit ctx: Context) { diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala index a133d25da..0ada9eac5 100644 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -5,7 +5,7 @@ import core._ import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation import StdNames.nme -import ast.Trees._, ast.UntypedTrees.untpd +import ast.Trees._, ast.untpd import java.lang.Integer.toOctalString import scala.annotation.switch diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index c24d3a800..bcf58e4e5 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -6,7 +6,7 @@ import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation import StdNames.nme import ast.Trees._ -import ast.UntypedTrees.untpd +import ast.untpd import scala.annotation.switch class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { |