aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/ast/UntypedTrees.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools/dotc/ast/UntypedTrees.scala')
-rw-r--r--src/dotty/tools/dotc/ast/UntypedTrees.scala465
1 files changed, 5 insertions, 460 deletions
diff --git a/src/dotty/tools/dotc/ast/UntypedTrees.scala b/src/dotty/tools/dotc/ast/UntypedTrees.scala
index f0488bedf..4af05acfb 100644
--- a/src/dotty/tools/dotc/ast/UntypedTrees.scala
+++ b/src/dotty/tools/dotc/ast/UntypedTrees.scala
@@ -21,7 +21,7 @@ object untpd extends Trees.Instance[Untyped] {
/** mods object name impl */
case class ModuleDef(mods: Modifiers, name: TermName, impl: Template)
- extends NameTree with MemberDef {
+ 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)
}
@@ -45,8 +45,6 @@ object untpd extends Trees.Instance[Untyped] {
// ------ Untyped tree values and creation methods ---------------------
- private type VarInfo = (NameTree, Tree)
-
val unitLiteral = Literal(Constant())
def ref(tp: NamedType)(implicit ctx: Context): Tree =
@@ -54,11 +52,11 @@ object untpd extends Trees.Instance[Untyped] {
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, tparams: List[TypeDef], vparamss: List[List[ValDef]], rhs: Tree = EmptyTree): DefDef =
+ DefDef(mods, nme.CONSTRUCTOR, tparams, vparamss, TypeTree(), rhs)
- def emptyConstructor(implicit ctx: Context): DefDef =
- makeConstructor(Modifiers(), Nil)
+ def emptyConstructor: DefDef =
+ makeConstructor(Modifiers(), Nil, Nil)
def makeSelfDef(name: TermName, tpt: Tree)(implicit ctx: Context) =
ValDef(Modifiers(Private), name, tpt, EmptyTree)
@@ -81,459 +79,6 @@ object untpd extends Trees.Instance[Untyped] {
def refOfDef(tree: NameTree) = Ident(tree.name)
-// ------ Untyped tree desugaring ------------------------------------------
-
- def desugar(tree: Tree, mode: Mode.Value)(implicit ctx: Context): Tree = {
-
- def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree) = {
- val ldef = DefDef(Modifiers(Label), lname, Nil, ListOfNil, TypeTree(), rhs)
- Block(ldef, call)
- }
-
- def derivedValDef(mods: Modifiers, named: NameTree, tpt: Tree, rhs: Tree) =
- ValDef(mods, named.name.asTermName, tpt, rhs).withPos(named.pos)
-
- /** 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), args)
- } else {
- val x = ctx.freshName().toTermName
- Block(
- ValDef(Modifiers(Synthetic), x, TypeTree(), left),
- Apply(Select(right, op), Ident(x)))
- }
- }
-
- /** Make closure corresponding to function params => body */
- def makeClosure(params: List[ValDef], body: Tree) =
- Block(
- DefDef(Modifiers(Synthetic), nme.ANON_FUN, Nil, params :: Nil, EmptyTree, body),
- Closure(Nil, Ident(nme.ANON_FUN)))
-
- /** Make closure corresponding to partial function { cases } */
- def makeCaseClosure(cases: List[CaseDef]) = {
- val param = makeSyntheticParameter()
- makeClosure(param :: Nil, Match(Ident(param.name), cases))
- }
-
- /** 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 = {
-
- /** 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) =>
- makeClosure(derivedValDef(Modifiers(Param), named, tpt, EmptyTree) :: Nil, body)
- case _ =>
- makeCaseClosure(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))
- }
-
- /** 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)
- }
-
- 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
- }
- }
-
- 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.
- */
- 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))
- Thicket(firstDef :: restDefs)
- }
- }
-
- def isPatternVar(id: Ident) =
- mode == Mode.Pattern && isVarPattern(id) && id.name != nme.WILDCARD
-
- // begin desugar
- val tree1 = 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 Match(EmptyTree, cases) =>
- makeCaseClosure(cases)
- case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- val (tparams1, vparamss1) =
- desugarContextBounds(tparams, vparamss, ofClass = false)
- tree.derivedDefDef(mods, name, tparams1, vparamss1, tpt, rhs)
- case ClassDef(
- mods, name, tparams, impl @ 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 = impl.derivedTemplate(constr1, parents, self, body)
- tree.derivedClassDef(mods, name, tparams1, templ1)
- 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, 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 cls = ClassDef(mods.toTypeFlags & AccessFlags | ModuleClassCreationFlags, clsName, Nil, clsTmpl)
- Thicket(modul, cls)
- case SymbolLit(str) =>
- New(ref(defn.SymbolClass.typeConstructor), (Literal(Constant(str)) :: Nil) :: 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
- makeClosure(args.asInstanceOf[List[ValDef]], body)
- 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), l :: r :: Nil)
- case Mode.Type => // op[l, r]
- AppliedTypeTree(Ident(op), 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)
- }
- case PrefixOp(op, t) =>
- if (mode == Mode.Type && op == nme.ARROWkw)
- AppliedTypeTree(ref(defn.ByNameParamClass.typeConstructor), t)
- else
- Select(t, nme.UNARY_PREFIX ++ op)
- 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))
- Thicket(pats1 map (makePatDef(mods, _, rhs)))
- case _ =>
- tree
- }
- tree1 match {
- case tree1: NameTree => tree1.withName(tree1.name.encode)
- case _ => tree1
- }
- }.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 mapConserve {
- 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
- }
- epbuf.toList match {
- case Nil =>
- (tparams, vparamss)
- case evidenceParams =>
- val vparamss1 = vparamss.reverse match {
- case (vparams @ (vparam :: _)) :: rvparamss if vparam.mods is Implicit =>
- ((vparams ++ evidenceParams) :: rvparamss).reverse
- case _ =>
- vparamss :+ evidenceParams
- }
- (tparams1, vparamss1)
- }
- }
-
- val NotInTypeAccessorFlags = Param | Private | Local
-
- def desugarClassDef(cdef: ClassDef)(implicit ctx: Context): ClassDef = {
- val ClassDef(
- mods, name, tparams, impl @ Template(constr, parents, self, body)) = cdef
-
- // desugar context bounds
- val (tparamAccs, vparamAccss) =
- desugarContextBounds(tparams, constr.vparamss, ofClass = true)
-
- val tparams1 = tparams.map(tparam => tparam.derivedTypeDef(
- Modifiers(Param), tparam.name, tparam.tparams, tparam.rhs))
-
- // ensure parameter list is non-empty
- val vparamss1 =
- if (vparamAccss.isEmpty) {
- if (mods is Case)
- ctx.error("case class needs to have at least one parameter list", cdef.pos)
- ListOfNil
- }
- else
- vparamAccss.nestedMap(vparam => vparam.derivedValDef(
- Modifiers(Param), vparam.name, vparam.tpt, vparam.rhs))
-
- val constr1 = constr.derivedDefDef(
- constr.mods, constr.name, constr.tparams, vparamss1, constr.tpt, constr.rhs)
-
- cdef.derivedClassDef(mods, name, tparams1,
- impl.derivedTemplate(constr1, parents, self, tparamAccs ::: vparamAccss.flatten ::: body))
- }
-
- /** Expand to:
- * <module> val name: name$ = New(name$)
- * <module> final class name$ extends parents { self: name.type => body }
- */
- def desugarModuleDef(mdef: ModuleDef): Tree = {
- val ModuleDef(mods, name, tmpl @ Template(constr, parents, self, body)) = mdef
- 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 cls = ClassDef(mods.toTypeFlags & AccessFlags | ModuleClassCreationFlags, clsName, Nil, clsTmpl)
- Thicket(modul, cls)
- }
-
- 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)
- }
- }
- }
-
// ------- A decorator for producing a path to a location --------------
implicit class UntypedTreeDecorator(val self: Tree) extends AnyVal {