aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-06-04 18:00:37 +0200
committerMartin Odersky <odersky@gmail.com>2013-06-04 18:00:37 +0200
commitb28c9ef75e274bdc54e9502e56c95b505495de5b (patch)
tree84b350bffb77d521d7c8393096b43deca78f5e5f /src
parent4fc1d8501a3937547e05f14aa4f4423a2c0d6a1d (diff)
downloaddotty-b28c9ef75e274bdc54e9502e56c95b505495de5b.tar.gz
dotty-b28c9ef75e274bdc54e9502e56c95b505495de5b.tar.bz2
dotty-b28c9ef75e274bdc54e9502e56c95b505495de5b.zip
Refactoring: breaking out desugaring into its own object.
Also, changing the maps in Namer. More commenting needs to be done. Pushing now to get off this machine and back to the new one, which just came back form repair.
Diffstat (limited to 'src')
-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
13 files changed, 680 insertions, 684 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)
}
}