diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/ast/CheckTrees.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/Desugar.scala | 529 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/Trees.scala | 22 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/TypedTrees.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/UntypedTrees.scala | 465 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Contexts.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Flags.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/parsing/Parsers.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/printing/RefinedPrinter.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 301 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 2 |
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) } } |