aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/ast/CheckTrees.scala2
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala529
-rw-r--r--src/dotty/tools/dotc/ast/TreeInfo.scala8
-rw-r--r--src/dotty/tools/dotc/ast/Trees.scala22
-rw-r--r--src/dotty/tools/dotc/ast/TypedTrees.scala4
-rw-r--r--src/dotty/tools/dotc/ast/UntypedTrees.scala465
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala1
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala3
-rw-r--r--src/dotty/tools/dotc/core/Types.scala3
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala12
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala12
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala301
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala2
-rw-r--r--test/test/DeSugarTest.scala8
-rw-r--r--test/test/showTree.scala6
15 files changed, 689 insertions, 689 deletions
diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala
index 0249c3afa..ae7fc5fc1 100644
--- a/src/dotty/tools/dotc/ast/CheckTrees.scala
+++ b/src/dotty/tools/dotc/ast/CheckTrees.scala
@@ -225,7 +225,7 @@ object CheckTrees {
case TypeDef(mods, name, _, tpt) =>
check(tpt.tpe.isInstanceOf[TypeBounds])
case Template(constr, parents, selfType, body) =>
- case ClassDef(mods, name, tparams, impl) =>
+ case ClassDef(mods, names, impl) =>
case Import(expr, selectors) =>
check(expr.isValue)
check(expr.tpe.termSymbol.isStable)
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index 1fc62f7ce..cb6e00ebf 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -10,8 +10,533 @@ import Decorators._
import language.higherKinds
import collection.mutable.ListBuffer
-trait Desugar { this: untpd.type =>
+object desugar {
+ import untpd._
+ private type VarInfo = (NameTree, Tree)
-} \ No newline at end of file
+ object Mode extends Enumeration {
+ val Type, Expr, Pattern = Value
+ }
+
+ def valDef(vdef: ValDef)(implicit ctx: Context): Tree = {
+ val ValDef(mods, name, tpt, rhs) = vdef
+ if (!ctx.owner.isClass || (mods is Private)) vdef
+ else {
+ val lname = name.toLocalName
+ val field = vdef.derivedValDef(mods, lname, tpt, rhs)
+ val getter = vdef.derivedDefDef(mods, name, Nil, Nil, tpt, Ident(lname))
+ if (!(mods is Mutable)) Thicket(field, getter)
+ else {
+ val setterParam = makeSyntheticParameter(tpt = TypeTree(field))
+ val setter = vdef.derivedDefDef(
+ mods, name.getterToSetter, Nil, (setterParam :: Nil) :: Nil, EmptyTree, refOfDef(setterParam))
+ Thicket(field, getter, setter)
+ }
+ }
+ }
+
+ def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false): DefDef = {
+ val DefDef(mods, name, tparams, vparamss, tpt, rhs) = meth
+ 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 paramFlags: FlagSet = if (isPrimaryConstructor) PrivateLocalParamAccessor else Param
+ val epname = (nme.EVIDENCE_PARAM_PREFIX.toString + epbuf.length).toTermName
+ epbuf +=
+ ValDef(Modifiers(paramFlags | Implicit), epname, cxbound, EmptyTree)
+ }
+ tparam.derivedTypeDef(mods, name, ttparams, tbounds)
+ case tparam =>
+ tparam
+ }
+ epbuf.toList match {
+ case Nil =>
+ meth
+ case evidenceParams =>
+ val vparamss1 = vparamss.reverse match {
+ case (vparams @ (vparam :: _)) :: rvparamss if vparam.mods is Implicit =>
+ ((vparams ++ evidenceParams) :: rvparamss).reverse
+ case _ =>
+ vparamss :+ evidenceParams
+ }
+ meth.derivedDefDef(mods, name, tparams1, vparamss1, tpt, rhs)
+ }
+ }
+
+ def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = {
+ val TypeDef(mods, name, tparams, rhs) = tdef
+ if (mods is PrivateLocalParamAccessor) {
+ val tparam = tdef.derivedTypeDef(
+ tdef.mods &~ PrivateLocal | ExpandedName, tdef.name.expandedName(ctx.owner), tdef.tparams, tdef.rhs)
+ val alias = tdef.derivedTypeDef(
+ Modifiers(PrivateLocal | Synthetic), tdef.name, Nil, refOfDef(tparam))
+ Thicket(tparam :: alias :: Nil)
+ }
+ else tdef
+ }
+
+ private val synthetic = Modifiers(Synthetic)
+
+ def classDef(cdef: ClassDef)(implicit ctx: Context): Tree = {
+ val ClassDef(
+ mods, name, impl @ Template(constr0, parents, self, body)) = cdef
+
+ val constr1 = defDef(constr0, isPrimaryConstructor = true)
+
+ val tparams = constr1.tparams.map(tparam => tparam.derivedTypeDef(
+ Modifiers(Param), tparam.name, tparam.tparams, tparam.rhs))
+
+ // ensure parameter list is non-empty
+ val vparamss =
+ if (constr1.vparamss.isEmpty) {
+ if (mods is Case)
+ ctx.error("case class needs to have at least one parameter list", cdef.pos)
+ ListOfNil
+ } else
+ constr1.vparamss.nestedMap(vparam => vparam.derivedValDef(
+ Modifiers(Param), vparam.name, vparam.tpt, vparam.rhs))
+
+ val constr = constr1.derivedDefDef(
+ constr1.mods, constr1.name, tparams, vparamss, constr1.tpt, constr1.rhs)
+
+ val classTypeRef = {
+ val tycon = Ident(cdef.name)
+ val tparams = cdef.impl.constr.tparams
+ if (tparams.isEmpty) tycon else AppliedTypeTree(tycon, tparams map refOfDef)
+ }
+
+ val creatorExpr = New(classTypeRef, vparamss nestedMap refOfDef)
+
+ val caseClassMeths =
+ if (mods is Case) {
+ val caseParams = vparamss.head.toArray
+ def syntheticProperty(name: TermName, rhs: Tree) =
+ DefDef(synthetic, name, Nil, Nil, EmptyTree, rhs)
+ val isDefinedMeth = syntheticProperty(nme.isDefined, Literal(Constant(true)))
+ val productArityMeth = syntheticProperty(nme.productArity, Literal(Constant(caseParams.length)))
+ val productElemMeths = for (i <- 0 until caseParams.length) yield
+ syntheticProperty(("_" + (i + 1)).toTermName, Select(This(EmptyTypeName), caseParams(i).name))
+ val copyMeths =
+ if (mods is Abstract) Nil
+ else {
+ val copyFirstParams = vparamss.head.map(vparam =>
+ vparam.derivedValDef(vparam.mods, vparam.name, vparam.tpt, refOfDef(vparam)))
+ val copyRestParamss = vparamss.tail.nestedMap(vparam =>
+ vparam.derivedValDef(vparam.mods, vparam.name, vparam.tpt, EmptyTree))
+ DefDef(synthetic, nme.copy, tparams, copyFirstParams :: copyRestParamss, EmptyTree, creatorExpr) :: Nil
+ }
+ copyMeths ::: isDefinedMeth :: productArityMeth :: productElemMeths.toList
+ }
+ else Nil
+
+ val caseCompanions =
+ if (mods is Case) {
+ val parent =
+ if (tparams.nonEmpty) ref(defn.AnyRefAlias.typeConstructor)
+ else (vparamss :\ classTypeRef) ((vparams, restpe) => Function(vparams map (_.tpt), restpe))
+ val applyMeths =
+ if (mods is Abstract) Nil
+ else DefDef(synthetic, nme.apply, tparams, vparamss, EmptyTree, creatorExpr) :: Nil
+ val unapplyMeth = {
+ val unapplyParam = makeSyntheticParameter(tpt = classTypeRef)
+ DefDef(synthetic, nme.unapply, tparams, (unapplyParam :: Nil) :: Nil, EmptyTree, This(EmptyTypeName))
+ }
+ moduleDef(
+ ModuleDef(
+ Modifiers(Synthetic), name.toTermName,
+ Template(emptyConstructor, parent :: Nil, EmptyValDef(), applyMeths ::: unapplyMeth :: Nil))
+ ).toList
+ }
+ else Nil
+
+ val implicitWrappers =
+ if (mods is Implicit) {
+ if (ctx.owner is Package)
+ ctx.error("implicit classes may not be toplevel", cdef.pos)
+ if (mods is Case)
+ ctx.error("implicit classes may not case classes", cdef.pos)
+ DefDef(Modifiers(Synthetic | Implicit), name.toTermName,
+ tparams, vparamss, EmptyTree, creatorExpr) :: Nil
+ }
+ else Nil
+
+ val cdef1 = cdef.derivedClassDef(mods, name,
+ impl.derivedTemplate(constr, parents, self,
+ constr1.tparams ::: constr1.vparamss.flatten ::: body ::: caseClassMeths))
+ Thicket(cdef1 :: caseCompanions ::: implicitWrappers)
+ }
+
+ /** Expand to:
+ * <module> val name: name$ = New(name$)
+ * <module> final class name$ extends parents { self: name.type => body }
+ */
+ def moduleDef(mdef: ModuleDef)(implicit ctx: Context): 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, clsTmpl)
+ Thicket(cls :: valDef(modul).toList)
+ }
+
+ def memberDef(tree: Tree)(implicit ctx: Context): Tree = tree match {
+ case tree: ValDef => valDef(tree)
+ case tree: TypeDef => typeDef(tree)
+ case tree: DefDef => defDef(tree)
+ case tree: ClassDef => classDef(tree)
+ case tree: ModuleDef => moduleDef(tree)
+ }
+
+ def apply(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) =>
+ val x = tpnme.ANON_CLASS
+ val clsDef = ClassDef(Modifiers(Final), x, templ)
+ Block(clsDef, New(Ident(x), Nil))
+ 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 tree: MemberDef =>
+ memberDef(tree)
+ 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)
+
+ /** 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)
+ }
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala
index 2d14e6dab..cfb175e0b 100644
--- a/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -37,10 +37,10 @@ abstract class TreeInfo {
*/
def isIdempotentDef(tree: Tree[Type])(implicit ctx: Context): Boolean = tree match {
case EmptyTree
- | ClassDef(_, _, _, _)
- | TypeDef(_, _, _, _)
- | Import(_, _)
- | DefDef(_, _, _, _, _, _) =>
+ | ClassDef(_, _, _)
+ | TypeDef(_, _, _, _)
+ | Import(_, _)
+ | DefDef(_, _, _, _, _, _) =>
true
case ValDef(mods, _, _, rhs) =>
!(mods is Mutable) && isIdempotentExpr(rhs)
diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala
index c5fe093d2..ded027e42 100644
--- a/src/dotty/tools/dotc/ast/Trees.scala
+++ b/src/dotty/tools/dotc/ast/Trees.scala
@@ -584,10 +584,10 @@ object Trees {
}
/** mods class name[tparams] impl */
- case class ClassDef[T >: Untyped](mods: Modifiers[T], name: TypeName, tparams: List[TypeDef[T]], impl: Template[T])
+ case class ClassDef[T >: Untyped](mods: Modifiers[T], name: TypeName, impl: Template[T])
extends MemberDef[T] {
type ThisTree[T >: Untyped] = ClassDef[T]
- def withName(name: Name) = this.derivedClassDef(mods, name.toTypeName, tparams, impl)
+ def withName(name: Name) = this.derivedClassDef(mods, name.toTypeName, impl)
}
/** import expr.selectors
@@ -884,9 +884,9 @@ object Trees {
case tree: Template[_] if (constr eq tree.constr) && (parents eq tree.parents) && (self eq tree.self) && (body eq tree.body) => tree
case _ => Template(constr, parents, self, body).copyAttr(tree)
}
- def derivedClassDef(mods: Modifiers[T], name: TypeName, tparams: List[TypeDef[T]], impl: Template[T]): ClassDef[T] = tree match {
- case tree: ClassDef[_] if (mods == tree.mods) && (name == tree.name) && (tparams eq tree.tparams) && (impl eq tree.impl) => tree
- case _ => ClassDef(mods, name, tparams, impl).copyAttr(tree)
+ def derivedClassDef(mods: Modifiers[T], name: TypeName, impl: Template[T]): ClassDef[T] = tree match {
+ case tree: ClassDef[_] if (mods == tree.mods) && (name == tree.name) && (impl eq tree.impl) => tree
+ case _ => ClassDef(mods, name, impl).copyAttr(tree)
}
def derivedImport(expr: Tree[T], selectors: List[Tree[Untyped]]): Import[T] = tree match {
case tree: Import[_] if (expr eq tree.expr) && (selectors eq tree.selectors) => tree
@@ -986,8 +986,8 @@ object Trees {
finishTypeDef(tree.derivedTypeDef(mods, name, transformSub(tparams, c), transform(rhs, c)), tree, c, plugins)
case Template(constr, parents, self, body) =>
finishTemplate(tree.derivedTemplate(transformSub(constr, c), transform(parents, c), transformSub(self, c), transform(body, c)), tree, c, plugins)
- case ClassDef(mods, name, tparams, impl) =>
- finishClassDef(tree.derivedClassDef(mods, name, transformSub(tparams, c), transformSub(impl, c)), tree, c, plugins)
+ case ClassDef(mods, name, impl) =>
+ finishClassDef(tree.derivedClassDef(mods, name, transformSub(impl, c)), tree, c, plugins)
case Import(expr, selectors) =>
finishImport(tree.derivedImport(transform(expr, c), selectors), tree, c, plugins)
case PackageDef(pid, stats) =>
@@ -1159,8 +1159,8 @@ object Trees {
tree.derivedTypeDef(mods, name, transformSub(tparams), transform(rhs))
case Template(constr, parents, self, body) =>
tree.derivedTemplate(transformSub(constr), transform(parents), transformSub(self), transformStats(body))
- case ClassDef(mods, name, tparams, impl) =>
- tree.derivedClassDef(mods, name, transformSub(tparams), transformSub(impl))
+ case ClassDef(mods, name, impl) =>
+ tree.derivedClassDef(mods, name, transformSub(impl))
case Import(expr, selectors) =>
tree.derivedImport(transform(expr), selectors)
case PackageDef(pid, stats) =>
@@ -1267,8 +1267,8 @@ object Trees {
this(this(x, tparams), rhs)
case Template(constr, parents, self, body) =>
this(this(this(this(x, constr), parents), self), body)
- case ClassDef(mods, name, tparams, impl) =>
- this(this(x, tparams), impl)
+ case ClassDef(mods, name, impl) =>
+ this(x, impl)
case Import(expr, selectors) =>
this(x, expr)
case PackageDef(pid, stats) =>
diff --git a/src/dotty/tools/dotc/ast/TypedTrees.scala b/src/dotty/tools/dotc/ast/TypedTrees.scala
index b8b54873e..e52c7d538 100644
--- a/src/dotty/tools/dotc/ast/TypedTrees.scala
+++ b/src/dotty/tools/dotc/ast/TypedTrees.scala
@@ -231,7 +231,7 @@ object tpd extends Trees.Instance[Type] {
.orElse(ctx.newLocalDummy(cls))
val impl = Trees.Template(constr, parents, selfType, rest)
.withType(refType(localDummy)).checked
- Trees.ClassDef(Modifiers(cls), cls.name, tparams, impl)
+ Trees.ClassDef(Modifiers(cls), cls.name, impl) // !!! todo: revise
.withType(refType(cls)).checked
}
@@ -246,7 +246,7 @@ object tpd extends Trees.Instance[Type] {
val EmptyTree: Tree = emptyTree[Type]()
- val EmptyValDef: ValDef = Trees.EmptyValDef[Type]
+ val EmptyValDef: ValDef = Trees.EmptyValDef().withType(NoType)
def SharedTree(tree: Tree): SharedTree =
Trees.SharedTree(tree).withType(tree.tpe)
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 {
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index 98cf7e801..6d566cdbd 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -253,6 +253,7 @@ object Contexts {
def withPlainPrinter(printer: Context => Printer): this.type = { this.plainPrinter = printer; this }
def withRefinedPrinter(printer: Context => Printer): this.type = { this.refinedPrinter = printer; this }
def withOwner(owner: Symbol): this.type = { this.owner = owner; this }
+ def withNewScope: this.type = { this.scope = newScope; this }
def withSettings(sstate: SettingsState): this.type = { this.sstate = sstate; this }
def withTree(tree: Tree[_ >: Untyped]): this.type = { this.tree = tree; this }
def withScope(scope: Scope): this.type = { this.scope = scope; this }
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 1b918cfcd..e15ca04d3 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -430,6 +430,9 @@ object Flags {
/** A type parameter with synthesized name */
final val ExpandedTypeParam = allOf(ExpandedName, TypeParam)
+ /** A parameter or parameter accessor */
+ final val ParamOrAccessor = Param | Accessor
+
/** A Java interface */
final val JavaInterface = allOf(JavaDefined, Trait)
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index c78b876b4..3a25fe889 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -243,6 +243,9 @@ object Types {
Nil
}
+ def uninstantiatedTypeParams(implicit ctx: Context): List[TypeSymbol] =
+ typeParams filter (tparam => member(tparam.name) == tparam)
+
// ----- Member access -------------------------------------------------
/** The scope of all declarations of this type.
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index b6411f7cc..13e5494cb 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -284,9 +284,7 @@ object Parsers {
tree
}
- def emptyConstructor() = atPos(in.offset) {
- makeConstructor(Modifiers(), Nil)
- }
+ def emptyConstructor() = atPos(in.offset) { ast.untpd.emptyConstructor }
/* -------------- XML ---------------------------------------------------- */
@@ -1653,7 +1651,7 @@ object Parsers {
accept(EQUALS)
atPos(in.offset) { constrExpr() }
}
- makeConstructor(mods, vparamss, rhs)
+ makeConstructor(mods, Nil, vparamss, rhs)
} else {
val name = ident()
val tparams = typeParamClauseOpt(ParamOwner.Def)
@@ -1744,14 +1742,14 @@ object Parsers {
*/
def classDef(mods: Modifiers): ClassDef = atPos(tokenRange) {
val name = ident().toTypeName
- val tparams = typeParamClauseOpt(ParamOwner.Class)
val constr = atPos(in.offset) {
+ val tparams = typeParamClauseOpt(ParamOwner.Class)
val cmods = constrModsOpt()
val vparamss = paramClauses(name, mods is Case)
- makeConstructor(cmods, vparamss)
+ makeConstructor(cmods, tparams, vparamss)
}
val templ = templateOpt(constr)
- ClassDef(mods, name, tparams, templ)
+ ClassDef(mods, name, templ)
}
/** ConstrMods ::= AccessModifier
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 9a3baa03f..23482b773 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -222,13 +222,14 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
modText(mods, "type") ~~ toText(name) ~ tparamsText(tparams) ~ rhsText
}
- case Template(DefDef(mods, _, _, vparamss, _, _), parents, self, stats) =>
+ case Template(DefDef(mods, _, tparams, vparamss, _, _), parents, self, stats) =>
+ val tparamsTxt = tparamsText(tparams)
val prefix: Text =
- if (vparamss.isEmpty) ""
+ if (vparamss.isEmpty) tparamsTxt
else {
var modsText = modText(mods, "")
if (mods.hasAnnotations && !mods.hasFlags) modsText = modsText ~~ " this"
- addVparamssText(modsText, vparamss)
+ addVparamssText(tparamsTxt ~~ modsText, vparamss)
}
val parentsText = Text(parents map constrText, " with ")
val selfText = {
@@ -237,10 +238,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
} provided !self.isEmpty
val bodyText = "{" ~~ selfText ~~ toTextGlobal(stats, "\n") ~ "}"
prefix ~~ (" extends" provided ownerIsClass) ~~ parentsText ~~ bodyText
- case ClassDef(mods, name, tparams, impl) =>
+ case ClassDef(mods, name, impl) =>
atOwner(tree) {
- modText(mods, if (mods is Trait) "trait" else "class") ~~
- toText(name) ~ tparamsText(tparams) ~ toText(impl)
+ modText(mods, if (mods is Trait) "trait" else "class") ~~ toText(name) ~ toText(impl)
}
case Import(expr, selectors) =>
def selectorText(sel: Tree): Text = sel match {
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 45f788e15..d5b63a703 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -6,16 +6,20 @@ import core._
import ast._
import Trees._, Constants._, StdNames._, Scopes._
import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._
+import ast.desugar, ast.desugar._
import util.Positions._
import util.SourcePosition
import collection.mutable
import language.implicitConversions
-trait NamerContextOps { ctx: Context =>
+trait NamerContextOps { this: Context =>
- def enterSym(sym: Symbol) = ctx.owner match {
- case cls: ClassSymbol => cls.enter(sym)
- case _ => this.scope.asInstanceOf[MutableScope].enter(sym)
+ def enter(sym: Symbol): Symbol = {
+ ctx.owner match {
+ case cls: ClassSymbol => cls.enter(sym)
+ case _ => this.scope.asInstanceOf[MutableScope].enter(sym)
+ }
+ sym
}
}
@@ -76,7 +80,7 @@ abstract class Namer { typer: Typer =>
* during phase typer.
*/
- val expandedTree = new mutable.WeakHashMap[Tree, Tree]
+ val expandedTree = new mutable.WeakHashMap[MemberDef, Tree]
val untypedTreeOfSym = mutable.Map[Symbol, Tree]()
@@ -113,201 +117,90 @@ abstract class Namer { typer: Typer =>
def symOfTypedTree(tree: tpd.NameTree)(implicit ctx: Context) = symOfTree(tree, typedTreeOfSym)(ctx)
def symOfUntypedTree (tree: NameTree)(implicit ctx: Context) = symOfTree(tree, untypedTreeOfSym)(ctx)
- def createSymbol(tree: Tree, original: Tree)(implicit ctx: Context): Symbol = {
- def createSym(name: Name, flags: FlagSet, privateWithin: Symbol) = {
- val sym = ctx.newSymbol(ctx.owner, name, flags, new Completer, privateWithin, original.pos)
- untypedTreeOfSym(sym) = tree
- sym
- }
- tree match {
+ def createSymbol(tree: Tree)(implicit ctx: Context): Symbol = {
+ val sym = tree match {
+ case tree: ClassDef =>
+ ctx.enter(ctx.newClassSymbol(
+ ctx.owner, tree.name, tree.mods.flags, new Completer,
+ privateWithinClass(tree.mods), tree.pos, ctx.source.file))
case tree: MemberDef =>
- val sym = createSym(tree.name, tree.mods.flags, privateWithinClass(tree.mods))
- ctx.enterSym(sym)
- sym
+ ctx.enter(ctx.newSymbol(
+ ctx.owner, tree.name, tree.mods.flags, new Completer,
+ privateWithinClass(tree.mods), tree.pos))
case imp: Import =>
- createSym(nme.IMPORT, Synthetic, NoSymbol)
+ ctx.newSymbol(
+ ctx.owner, nme.IMPORT, Synthetic, new Completer, NoSymbol, tree.pos)
case _ =>
NoSymbol
}
+ if (sym.exists) untypedTreeOfSym(sym) = tree
+ sym
}
- val synthetic = Modifiers(Synthetic)
-
- def expansion(tree: Tree)(implicit ctx: Context): Tree = {
-
- def classTypeRef(cdef: ClassDef) = {
- val tycon = Ident(cdef.name)
- if (cdef.tparams.isEmpty) tycon else AppliedTypeTree(tycon, cdef.tparams map refOfDef)
- }
+ def expansion(defn: MemberDef)(implicit ctx: Context): Tree = {
+ val expanded = desugar.memberDef(defn)
+ if (expanded ne defn) expandedTree(defn) = expanded
+ expanded
+ }
- def creator(cdef: ClassDef) =
- New(classTypeRef(cdef), cdef.impl.constr.vparamss.nestedMap(refOfDef))
+ def enterSym(stat: Tree)(implicit ctx: Context): Context = stat match {
+ case imp: Import =>
+ val sym = createSymbol(imp)
+ ctx.fresh.withImport(ImportInfo(sym, imp.selectors, ctx.scopeNestingLevel))
+ case defn: MemberDef =>
+ expansion(defn).toList foreach createSymbol
+ ctx
+ case _ =>
+ ctx
+ }
- def methTypeParams(cdef: ClassDef) =
- for (tparam <- cdef.tparams) yield // don't use derivedTypeDef; parameters have to be unique
- TypeDef(Modifiers(TypeParam), tparam.name, tparam.tparams, tparam.rhs).withPos(tparam.pos)
+ def enterSyms(stats: List[Tree])(implicit ctx: Context): Context = {
- def methParamss(cdef: ClassDef) =
- cdef.impl.constr.vparamss.nestedMap(vparam => // don't use derivedValDef; parameters have to be unique
- ValDef(Modifiers(TermParam), vparam.name, vparam.tpt, vparam.rhs).withPos(vparam.pos))
+ def traverse(stats: List[Tree])(implicit ctx: Context): Context = stats match {
+ case stat :: stats1 =>
+ traverse(stats)(enterSym(stat))
+ case nil =>
+ ctx
+ }
- def expandCaseClass(cdef: ClassDef): Tree = {
- val ClassDef(mods, cname, tparams, impl @ Template(constr, parents, self, stats)) = cdef
- val constr1 =
- if (constr.vparamss.nonEmpty) constr
- else {
- ctx.error("case class needs to have at least one parameter list", cdef.pos)
- constr.derivedDefDef(constr.mods, constr.name, constr.tparams, ListOfNil, constr.tpt, constr.rhs)
- }
- val caseParams = constr1.vparamss.head
- val caseParamsArray = caseParams.toArray
- def syntheticProperty(name: TermName, rhs: Tree) = DefDef(synthetic, name, Nil, Nil, EmptyTree, rhs)
- val isDefinedMeth = syntheticProperty(nme.isDefined, Literal(Constant(true)))
- val productArityMeth = syntheticProperty(nme.productArity, Literal(Constant(caseParamsArray.length)))
- val productElemMeths = for (i <- 0 until caseParamsArray.length) yield
- syntheticProperty(("_" + (i + 1)).toTermName, Select(This(EmptyTypeName), caseParamsArray(i).name))
- val (copyMeths, applyMeths) =
- if (mods is Abstract) (Nil, Nil)
- else {
- val copyFirstParams = caseParams.map(vparam =>
- ValDef(Modifiers(TermParam), vparam.name, vparam.tpt, refOfDef(vparam)).withPos(vparam.pos))
- val copyRestParamss = constr1.vparamss.tail.nestedMap(vparam =>
- ValDef(Modifiers(TermParam), vparam.name, vparam.tpt, EmptyTree).withPos(vparam.pos))
- val applyParamss = constr1.vparamss.nestedMap(vparam =>
- ValDef(Modifiers(TermParam), vparam.name, vparam.tpt, vparam.rhs).withPos(vparam.pos))
- val copyMeth =
- DefDef(synthetic, nme.copy, methTypeParams(cdef), copyFirstParams :: copyRestParamss, EmptyTree, creator(cdef))
- val applyMeth =
- DefDef(synthetic, nme.apply, methTypeParams(cdef), methParamss(cdef), EmptyTree, creator(cdef))
- (copyMeth :: Nil, applyMeth :: Nil)
- }
- val unapplyMeth = {
- val unapplyParam = makeSyntheticParameter(tpt = classTypeRef(cdef))
- DefDef(synthetic, nme.unapply, methTypeParams(cdef), (unapplyParam :: Nil) :: Nil, EmptyTree, This(EmptyTypeName))
- }
- val classMeths = copyMeths ::: isDefinedMeth :: productArityMeth :: productElemMeths.toList
- val cls1 = addToClass(cdef, classMeths)
-
- // update or create companion object:
- val companionMeths = applyMeths ::: unapplyMeth :: Nil
- val companionName = cname.toTermName
- var companionFound = false
- for (companion @ ModuleDef(_, `companionName`, _) <- enclosingStats) {
- // Add `companionDefs` to either the expanded or unexpanded version of
- // the companion object with given `companionName`, and update its expandedTree map
- // with the result.
- expandedTree(companion) = expandedTree get companion match {
- case Some(Thicket(vdef :: (cdef: ClassDef) :: Nil)) =>
- Thicket(vdef, addToClass(cdef, companionMeths))
+ def mergeCompanionDefs() = {
+ val caseClassDef = mutable.Map[TypeName, ClassDef]()
+ for (cdef @ ClassDef(mods, name, _) <- stats)
+ if (mods is Case) caseClassDef(name) = cdef
+ for (mdef @ ModuleDef(_, name, _) <- stats)
+ caseClassDef get name.toTypeName match {
+ case Some(cdef) =>
+ val Thicket((mcls @ ClassDef(_, _, impl)) :: mrest) = expandedTree(mdef)
+ val Thicket(cls :: (companion: ClassDef) :: crest) = expandedTree(cdef)
+ val mcls1 = mcls.derivedClassDef(mcls.mods, mcls.name,
+ impl.derivedTemplate(impl.constr, impl.parents, impl.self,
+ companion.impl.body ++ impl.body))
+ expandedTree(mdef) = Thicket(mcls1 :: mrest)
+ expandedTree(cdef) = Thicket(cls :: crest)
case none =>
- addToModule(companion, companionMeths)
}
- companionFound = true
}
- val syntheticCompanions =
- if (companionFound) Nil
- else {
- val parent =
- if (tparams.nonEmpty) ref(defn.AnyRefAlias.typeConstructor)
- else (constr1.vparamss :\ classTypeRef(cdef)) ((vparams, restpe) =>
- Function(vparams map (_.tpt), restpe))
- ModuleDef(
- Modifiers(Synthetic), companionName,
- Template(emptyConstructor, parent :: Nil, EmptyValDef(), companionMeths)) :: Nil
- }
- Thicket.make(cls1 :: syntheticCompanions)
- }
-
- def addToTemplate(templ: Template, stats: List[Tree]): Template =
- templ.derivedTemplate(templ.constr, templ.parents, templ.self, templ.body ++ stats)
-
- def addToClass(cdef: ClassDef, stats: List[Tree]): ClassDef =
- cdef.derivedClassDef(cdef.mods, cdef.name, cdef.tparams, addToTemplate(cdef.impl, stats))
-
- def addToModule(mdef: ModuleDef, stats: List[Tree]): ModuleDef =
- mdef.derivedModuleDef(mdef.mods, mdef.name, addToTemplate(mdef.impl, stats))
-
- def implicitWrapper(cdef: ClassDef) =
- DefDef(Modifiers(Synthetic | Implicit), cdef.name.toTermName,
- methTypeParams(cdef), methParamss(cdef), EmptyTree, creator(cdef))
-
- val tree1 = tree match {
- case ValDef(mods, name, tpt, rhs) =>
- if (!ctx.owner.isClass || (mods is Private)) tree
- else {
- val lname = name.toLocalName
- val field = tree.derivedValDef(mods, lname, tpt, rhs)
- val getter = tree.derivedDefDef(mods, name, Nil, Nil, tpt, Ident(lname))
- if (!(mods is Mutable)) Thicket(field, getter)
- else {
- val setterParam = makeSyntheticParameter(tpt = TypeTree(field))
- val setter = tree.derivedDefDef(
- mods, name.getterToSetter, Nil, (setterParam :: Nil) :: Nil, EmptyTree, refOfDef(setterParam))
- Thicket(field, getter, setter)
- }
- }
- case tdef: TypeDef if tdef.mods is PrivateLocalParamAccessor =>
- val tparam = tdef.derivedTypeDef(
- tdef.mods &~ PrivateLocal | ExpandedName, tdef.name.expandedName(ctx.owner), tdef.tparams, tdef.rhs)
- val alias = tdef.derivedTypeDef(
- Modifiers(PrivateLocal | Synthetic), tdef.name, Nil, refOfDef(tparam))
- Thicket(tparam :: alias :: Nil)
- case mdef: ModuleDef =>
- desugarModuleDef {
- expandedTree get mdef match {
- case Some(mdef1: ModuleDef) => mdef
- case _ => mdef
- }
- }
- case cdef: ClassDef =>
- val cdef1: ClassDef = desugarClassDef(cdef)
- val cdef2 = if (cdef1.mods is Case) expandCaseClass(cdef1) else cdef1
- if (cdef.mods is Implicit) {
- if (ctx.owner is Package)
- ctx.error("implicit classes may not be toplevel", cdef.pos)
- Thicket(cdef2 :: implicitWrapper(cdef) :: Nil)
- }
- else cdef2
- case _ =>
- tree
- }
- if (tree1 ne tree) expandedTree(tree) = tree1
- tree1
- }
- def enterSyms(stats: List[Tree])(implicit ctx: Context): Context = stats match {
- case (imp @ Import(expr, selectors)) :: rest =>
- val sym = createSymbol(imp, imp)
- enterSyms(rest)(ctx.fresh.withImport(ImportInfo(sym, selectors, ctx.scopeNestingLevel)))
- case stat :: rest =>
- for (expanded <- expansion(stat).toList) createSymbol(expanded, stat)
- enterSyms(rest)
- case Nil =>
- ctx
+ val result = traverse(stats)
+ mergeCompanionDefs()
+ result
}
- def localContext(owner: Symbol)(implicit ctx: Context) =
- ctx.fresh.withOwner(owner).withScope(newScope)
-
def enterParams(ddef: DefDef)(ctx: Context): Context =
(enterSyms(ddef.tparams)(ctx) /: ddef.vparamss) ((ctx, params) => enterSyms(params)(ctx))
class Completer(implicit ctx: Context) extends LazyType {
- def registerTyped(originals: List[NameTree], trees: List[tpd.Tree]): Unit =
- for ((original, tree) <- (originals, trees).zipped)
- typedTreeOfSym(symOfTree(original, untypedTreeOfSym)) = tree
-
def complete(denot: SymDenotation): Unit = {
- val sym = denot.symbol
- val original = untypedTreeOfSym(sym)
+ val symToComplete = denot.symbol
+ val original = untypedTreeOfSym(symToComplete)
- def inheritedResultType(paramFn: Type => Type): Type = {
+ def inheritedResultType(paramFn: Type => Type)(implicit ctx: Context): Type = {
lazy val schema = paramFn(WildcardType)
- val site = sym.owner.symTypeRef
- ((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) =>
+ val site = symToComplete.owner.symTypeRef
+ ((NoType: Type) /: symToComplete.owner.info.baseClasses.tail) { (tp, cls) =>
val itpe = cls.info
- .nonPrivateDecl(sym.name)
+ .nonPrivateDecl(symToComplete.name)
.matchingDenotation(site, schema)
.asSeenFrom(site)
.info.finalResultType
@@ -321,7 +214,7 @@ abstract class Namer { typer: Typer =>
tree1
}
- def valOrDefDefTypeSig[UT <: untpd.ValOrDefDef, T <: tpd.ValOrDefDef]
+ def valOrDefDefSig[UT <: untpd.ValOrDefDef, T <: tpd.ValOrDefDef]
(defn: UT, op: DefTyper[UT, T], paramFn: Type => Type)(implicit ctx: Context): Type =
paramFn {
if (!defn.tpt.isEmpty) typer.typed(defn.tpt).tpe
@@ -338,7 +231,7 @@ abstract class Namer { typer: Typer =>
for (param <- params) aheadDef(param, completer)
}
- def defDefTypeSig(defn: DefDef)(implicit ctx: Context) = {
+ def defDefSig(defn: DefDef)(implicit ctx: Context) = {
val DefDef(_, _, tparams, vparamss, _, _) = defn
completeParams(tparams, completeTypeDef)
for (vparams <- vparamss) completeParams(vparams, completeValDef)
@@ -353,33 +246,61 @@ abstract class Namer { typer: Typer =>
else if (vparamss.isEmpty) ExprType(monotpe)
else monotpe
}
- valOrDefDefTypeSig(defn, completeDefDef, wrapMethType)
+ valOrDefDefSig(defn, completeDefDef, wrapMethType)
}
- def classDefTypeSig(defn: ClassDef)(implicit ctx: Context): Type = {
- val ClassDef(_, _, tparams, impl @ Template(constr, parents, self, body)) = defn
- val localCtx = ctx.fresh.withOwner(sym)
- ???
+ def typeDefSig(defn: TypeDef)(implicit ctx: Context): Type = {
+ val lctx = localContext
+ completeParams(defn.tparams, completeTypeDef)(lctx)
+ val TypeDef(_, _, _, rhs) = aheadDef(defn, completeTypeDef)(lctx)
+ rhs.tpe // !!! do something about parameters!
}
+ def classDefSig(defn: ClassDef)(implicit ctx: Context): Type = {
+
+ def parentType(constr: untpd.Tree): Type = {
+ val Trees.Select(Trees.New(tpt), _) = TreeInfo.methPart(constr)
+ val ptype = typedType(tpt).tpe
+ if (ptype.uninstantiatedTypeParams.isEmpty) ptype else typedExpr(constr).tpe
+ }
+
+ def enterSelfSym(name: TermName, tpe: Type): Unit =
+ ctx.enter(ctx.newSymbol(ctx.owner, name, Synthetic, tpe, coord = symToComplete.coord))
+
+ val ClassDef(_, _, impl @ Template(constr, parents, self, body)) = defn
+
+ val decls = newScope
+ val (params, rest) = body span {
+ case td: TypeDef => td.mods is ParamOrAccessor
+ case _ => false
+ }
+ enterSyms(params)
+ val parentTypes = parents map parentType
+ val parentRefs = ctx.normalizeToRefs(parentTypes, symToComplete.asClass, decls)
+ val selfTypeOpt = if (self.tpt.isEmpty) NoType else typedType(self.tpt).tpe
+ if (self.name != nme.WILDCARD)
+ enterSelfSym(self.name, selfTypeOpt orElse symToComplete.typeConstructor)
+ enterSyms(rest)
+ ClassInfo(denot.owner.thisType, symToComplete.asClass, parentRefs, decls, selfTypeOpt)
+ }
+
+ def localContext = ctx.fresh.withOwner(symToComplete)
+
def typeSig(defn: Tree): Type = defn match {
case defn: ValDef =>
- valOrDefDefTypeSig(defn, completeValDef, identity)(ctx.fresh.withOwner(sym))
+ valOrDefDefSig(defn, completeValDef, identity)(localContext)
case defn: DefDef =>
- defDefTypeSig(defn)(localContext(sym))
+ defDefSig(defn)(localContext.withNewScope)
case defn: TypeDef =>
- val localCtx = localContext(sym)
- completeParams(defn.tparams, completeTypeDef)(localCtx)
- val TypeDef(_, _, _, rhs) = aheadDef(defn, completeTypeDef)(localCtx)
- rhs.tpe // !!! do something about parameters!
+ typeDefSig(defn)(localContext.withNewScope)
case defn: ClassDef =>
- classDefTypeSig(defn)(ctx.fresh.withOwner(sym))
+ classDefSig(defn)(localContext)
case imp: Import =>
- val expr1 = typedDefn(imp.expr, sym)
+ val expr1 = typedDefn(imp.expr, symToComplete)
ImportType(SharedTree(expr1))
}
- sym.info = typeSig(original)
+ symToComplete.info = typeSig(original)
}
}
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 44cefe5e6..ee221f9f2 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -77,7 +77,7 @@ class Typer extends Namer {
def reEnterParams[UT <: untpd.NameTree, T <: tpd.Tree](params: List[UT])(implicit ctx: Context): List[T] = {
for (param <- params) yield {
val sym = symOfUntypedTree(param)
- ctx.enterSym(sym)
+ ctx.enter(sym)
lateDef(param, noDefTyper)
}
}
diff --git a/test/test/DeSugarTest.scala b/test/test/DeSugarTest.scala
index 71274674b..ef0c34ec3 100644
--- a/test/test/DeSugarTest.scala
+++ b/test/test/DeSugarTest.scala
@@ -8,6 +8,8 @@ import Tokens._, Parsers._
import org.junit.Test
import dotty.tools.dotc._
import ast.Trees._
+import ast.desugar
+import ast.desugar._
import scala.collection.mutable.ListBuffer
@@ -64,8 +66,8 @@ class DeSugarTest extends ParserTest {
tree1.derivedTypeDef(mods, name, transformSub(tparams), transform(rhs, Type))
case Template(constr, parents, self, body) =>
tree1.derivedTemplate(transformSub(constr), transform(parents), transformSub(self), transform(body, Expr))
- case ClassDef(mods, name, tparams, impl) =>
- tree1.derivedClassDef(mods, name, transformSub(tparams), transformSub(impl))
+ case ClassDef(mods, name, impl) =>
+ tree1.derivedClassDef(mods, name, transformSub(impl))
case tree1 =>
super.transform(tree1)
}
@@ -74,7 +76,7 @@ class DeSugarTest extends ParserTest {
def firstClass(stats: List[Tree]): String = stats match {
case Nil => "<empty>"
- case ClassDef(_, name, _, _) :: _ => name.toString
+ case ClassDef(_, name, _) :: _ => name.toString
case ModuleDef(_, name, _) :: _ => name.toString
case (pdef: PackageDef) :: _ => firstClass(pdef)
case stat :: stats => firstClass(stats)
diff --git a/test/test/showTree.scala b/test/test/showTree.scala
index 69530a046..5d2710715 100644
--- a/test/test/showTree.scala
+++ b/test/test/showTree.scala
@@ -1,6 +1,8 @@
package test
import dotty.tools.dotc._
import ast.Trees._
+import ast.desugar
+import ast.desugar._
object showTree extends ParserTest {
@@ -55,8 +57,8 @@ object showTree extends ParserTest {
tree1.derivedTypeDef(mods, name, transformSub(tparams), transform(rhs, Type))
case Template(constr, parents, self, body) =>
tree1.derivedTemplate(transformSub(constr), transform(parents), transformSub(self), transform(body, Expr))
- case ClassDef(mods, name, tparams, impl) =>
- tree1.derivedClassDef(mods, name, transformSub(tparams), transformSub(impl))
+ case ClassDef(mods, name, impl) =>
+ tree1.derivedClassDef(mods, name, transformSub(impl))
case tree1 =>
super.transform(tree1)
}