From 339809ed82e14699681a5a7765c87133cd681ec0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 3 Jun 2013 11:33:53 +0200 Subject: More solid design of Namer with some Typer bits added. --- src/dotty/tools/dotc/ast/Desugar.scala | 17 ++ src/dotty/tools/dotc/ast/Trees.scala | 17 +- src/dotty/tools/dotc/ast/UntypedTrees.scala | 58 ++++-- src/dotty/tools/dotc/core/Decorators.scala | 32 +++ src/dotty/tools/dotc/core/Denotations.scala | 11 ++ src/dotty/tools/dotc/core/Flags.scala | 5 + src/dotty/tools/dotc/core/SymDenotations.scala | 10 +- src/dotty/tools/dotc/core/Types.scala | 37 +++- src/dotty/tools/dotc/parsing/Parsers.scala | 10 +- src/dotty/tools/dotc/typer/Namer.scala | 257 ++++++++++++++++++++----- src/dotty/tools/dotc/typer/Typer.scala | 87 ++++++++- 11 files changed, 454 insertions(+), 87 deletions(-) create mode 100644 src/dotty/tools/dotc/ast/Desugar.scala (limited to 'src/dotty/tools') diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala new file mode 100644 index 000000000..1fc62f7ce --- /dev/null +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -0,0 +1,17 @@ +package dotty.tools +package dotc +package ast + +import core._ +import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ +import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ +import TreeInfo._ +import Decorators._ +import language.higherKinds +import collection.mutable.ListBuffer + +trait Desugar { this: untpd.type => + + + +} \ No newline at end of file diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 6dfaa9c7b..7e1e70d57 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -313,6 +313,12 @@ object Trees { override def envelope: Position = mods.pos union pos union initialPos } + /** A ValDef or DefDef tree */ + trait ValOrDefDef[T >: Untyped] extends ModDefTree[T] { + def tpt: Tree[T] + def rhs: Tree[T] + } + // ----------- Tree case classes ------------------------------------ /** name */ @@ -550,14 +556,14 @@ object Trees { /** mods val name: tpt = rhs */ case class ValDef[T >: Untyped](mods: Modifiers[T], name: TermName, tpt: Tree[T], rhs: Tree[T]) - extends ModDefTree[T] { + extends ValOrDefDef[T] { type ThisTree[T >: Untyped] = ValDef[T] def withName(name: Name) = this.derivedValDef(mods, name.toTermName, tpt, rhs) } /** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */ case class DefDef[T >: Untyped](mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T]) - extends ModDefTree[T] { + extends ValOrDefDef[T] { type ThisTree[T >: Untyped] = DefDef[T] def withName(name: Name) = this.derivedDefDef(mods, name.toTermName, tparams, vparamss, tpt, rhs) } @@ -650,9 +656,13 @@ object Trees { } object Thicket { - def apply[T >: Untyped](): Tree[T] = emptyTree() + def apply[T >: Untyped](): Thicket[T] = emptyTree() def apply[T >: Untyped](x1: Tree[T], x2: Tree[T]): Thicket[T] = Thicket(List(x1, x2)) def apply[T >: Untyped](x1: Tree[T], x2: Tree[T], x3: Tree[T]): Thicket[T] = Thicket(List(x1, x2, x3)) + def make[T >: Untyped](xs: List[Tree[T]]): Tree[T] = flatten(xs) match { + case x :: Nil => x + case _ => apply(xs) + } } // ----- Auxiliary creation methods ------------------ @@ -678,6 +688,7 @@ object Trees { type RefTree = Trees.RefTree[T] type DefTree = Trees.DefTree[T] type ModDefTree = Trees.ModDefTree[T] + type ValOrDefDef = Trees.ValOrDefDef[T] type Ident = Trees.Ident[T] type Select = Trees.Select[T] diff --git a/src/dotty/tools/dotc/ast/UntypedTrees.scala b/src/dotty/tools/dotc/ast/UntypedTrees.scala index 7e3c906b2..befb5e85c 100644 --- a/src/dotty/tools/dotc/ast/UntypedTrees.scala +++ b/src/dotty/tools/dotc/ast/UntypedTrees.scala @@ -323,8 +323,19 @@ object untpd extends Trees.Instance[Untyped] { If(cond, thenp, unitLiteral) case Match(EmptyTree, cases) => makeCaseClosure(cases) - case _: DefDef | _: ClassDef => - desugarContextBounds(tree) + 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)) => // val name: name$ = New(name$) // final class name$ extends parents { self: name.type => body } @@ -431,20 +442,35 @@ object untpd extends Trees.Instance[Untyped] { } } - def desugarContextBounds(tree: Tree): Tree = tree match { - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - val (tparams1, vparamss1) = - desugarContextBounds(tparams, vparamss, ofClass = false) - tree.derivedDefDef(mods, name, tparams1, vparamss1, tpt, rhs) - case ClassDef( - mods, name, tparams, templ @ Template(constr, parents, self, body)) => - val (tparams1, vparamss1) = - desugarContextBounds(tparams, constr.vparamss, ofClass = true) - val constr1 = constr.derivedDefDef( - constr.mods, constr.name, constr.tparams, vparamss1, constr.tpt, constr.rhs) - val templ1 = templ.derivedTemplate(constr1, parents, self, body) - tree.derivedClassDef(mods, name, tparams1, templ1) - case _ => tree + 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: diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala index 094aa7b4a..476b97ec2 100644 --- a/src/dotty/tools/dotc/core/Decorators.scala +++ b/src/dotty/tools/dotc/core/Decorators.scala @@ -4,6 +4,8 @@ package core import annotation.tailrec import Symbols._ import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer +import util.Positions.Position, util.SourcePosition +import collection.mutable.ListBuffer /** This object provides useful implicit decorators for types defined elsewhere */ object Decorators { @@ -35,6 +37,33 @@ object Decorators { */ implicit class ListDecorator[T](val xs: List[T]) extends AnyVal { + @inline final def mapconserve[U](f: T => U): List[U] = { + @tailrec + def loop(mapped: ListBuffer[U], unchanged: List[U], pending: List[T]): List[U] = + if (pending.isEmpty) { + if (mapped eq null) unchanged + else mapped.prependToList(unchanged) + } else { + val head0 = pending.head + val head1 = f(head0) + + if (head1.asInstanceOf[AnyRef] eq head0.asInstanceOf[AnyRef]) + loop(mapped, unchanged, pending.tail) + else { + val b = if (mapped eq null) new ListBuffer[U] else mapped + var xc = unchanged + while (xc ne pending) { + b += xc.head + xc = xc.tail + } + b += head1 + val tail0 = pending.tail + loop(b, tail0.asInstanceOf[List[U]], tail0) + } + } + loop(null, xs.asInstanceOf[List[U]], xs) + } + /** Like `xs filter p` but returns list `xs` itself - instead of a copy - * if `p` is true for all elements and `xs` is not longer * than `MaxFilterRecursions`. @@ -86,5 +115,8 @@ object Decorators { def containsPhase(phase: Phase) = names exists (phase.name.startsWith) } + + implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition = + ctx.source.atPos(pos) } diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 97b25be00..9c89a28cf 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -197,6 +197,17 @@ object Denotations { def requiredMethod(name: PreName)(implicit ctx: Context): TermSymbol = info.member(name.toTermName).requiredSymbol(_ is Method).asTerm + /** The denotation that has a type matching `targetType` when seen + * as a member of type `site`, `NoDenotation` if none exists. + */ + def matchingDenotation(site: Type, targetType: Type)(implicit ctx: Context): SingleDenotation = + if (isOverloaded) + atSignature(targetType.signature).matchingDenotation(site, targetType) + else if (exists && !(site.memberInfo(symbol) matches targetType)) + NoDenotation + else + this.asInstanceOf[SingleDenotation] + /** Form a denotation by conjoining with denotation `that` */ def & (that: Denotation)(implicit ctx: Context): Denotation = if (this eq that) this diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index f22c2a0f2..1b918cfcd 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -63,6 +63,8 @@ object Flags { */ def is(flags: FlagConjunction, butNot: FlagSet): Boolean = is(flags) && !is(butNot) + def isEmpty = (bits & ~KINDFLAGS) == 0 + /** Is this flag set a subset of that one? */ def <= (that: FlagSet) = (bits & that.bits) == bits @@ -434,6 +436,9 @@ object Flags { /** Labeled private[this] */ final val PrivateLocal = allOf(Private, Local) + /** A private parameter accessor */ + final val PrivateLocalParamAccessor = allOf(Private, Local, ParamAccessor) + /** A local parameter */ final val ParamAndLocal = allOf(Param, Local) diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 56b168102..e1550d529 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -533,17 +533,11 @@ object SymDenotations { * inClass <-- find denot.symbol class C { <-- symbol is here * * site: Subtype of both inClass and C - * */ final def matchingSymbol(inClass: Symbol, site: Type)(implicit ctx: Context): Symbol = { var denot = inClass.info.nonPrivateDecl(name) - if (denot.isTerm) { // types of the same name always match - val targetType = site.memberInfo(symbol) - if (denot.isOverloaded) - denot = denot.atSignature(targetType.signature) // seems we need two kinds of signatures here - if (!(site.memberInfo(denot.symbol) matches targetType)) - denot = NoDenotation - } + if (denot.isTerm) // types of the same name always match + denot = denot.matchingDenotation(site, site.memberInfo(symbol)) denot.symbol } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index c0e338ef1..c78b876b4 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -411,6 +411,22 @@ object Types { ctx.typeComparer.matchesType( this, that, alwaysMatchSimple = !ctx.phase.erasedTypes) + /** The non-private symbol with given name in the given class that matches this type. + * @param inClass The class containing the symbol's definition + * @param name The name of the symbol we are looking for + * @param site The base type from which member types are computed + */ + def matchingTermSymbol(inClass: Symbol, name: Name, site: Type)(implicit ctx: Context): Symbol = { + var denot = inClass.info.nonPrivateDecl(name) + if (denot.isTerm) { // types of the same name always match + if (denot.isOverloaded) + denot = denot.atSignature(this.signature) // seems we need two kinds of signatures here + if (!(site.memberInfo(denot.symbol) matches this)) + denot = NoDenotation + } + denot.symbol + } + /** The basetype of this type with given class symbol */ final def baseType(base: Symbol)(implicit ctx: Context): Type = base.denot match { case classd: ClassDenotation => classd.baseTypeOf(this) @@ -505,6 +521,15 @@ object Types { /** The resultType of a PolyType, MethodType, or ExprType, the type itself for others */ def resultType: Type = this + /** The final result type of a PolyType, MethodType, or ExprType, after skipping + * all parameter sections, the type itself for all others. + */ + def finalResultType: Type = resultType match { + case mt: MethodType => mt.resultType.finalResultType + case pt: PolyType => pt.resultType.finalResultType + case _ => resultType + } + /** This type seen as a TypeBounds */ final def bounds(implicit ctx: Context): TypeBounds = this match { case tp: TypeBounds => tp @@ -1369,13 +1394,15 @@ object Types { } object PolyType { - def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) = { - def transform(pt: PolyType, tp: Type) = - tp.subst(tparams, (0 until tparams.length).toList map (PolyParam(pt, _))) - apply(tparams map (_.name.asTypeName))( + def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) = + if (tparams.isEmpty) resultType + else { + def transform(pt: PolyType, tp: Type) = + tp.subst(tparams, (0 until tparams.length).toList map (PolyParam(pt, _))) + apply(tparams map (_.name.asTypeName))( pt => tparams map (tparam => transform(pt, tparam.info).bounds), pt => transform(pt, resultType)) - } + } } abstract class BoundType extends UncachedProxyType with ValueType { diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 20f0f1df1..5c585cacb 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1455,18 +1455,18 @@ object Parsers { val modStart = in.offset var mods = annotsAsMods() if (owner.isTypeName) { - mods = modifiers(start = mods) + mods = modifiers(start = mods) | ParamAccessor mods = atPos(modStart, in.offset) { if (in.token == VAL) { in.nextToken() - mods | Param + mods } else if (in.token == VAR) { in.nextToken() - addFlag(mods | Param, Mutable) + addFlag(mods, Mutable) } else { - if (mods.hasFlags) syntaxError("`val' or `var' expected") - if (firstClauseOfCaseClass) mods | Param else mods | Param | PrivateLocal + if ((mods.flags &~ ParamAccessor).isEmpty) syntaxError("`val' or `var' expected") + if (firstClauseOfCaseClass) mods else mods | PrivateLocal } } } diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 84a82044b..e0a65bb52 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -19,15 +19,68 @@ trait NamerContextOps { ctx: Context => } } -class Namer(val typer: Typer) { +abstract class Namer { typer: Typer => import untpd._ - val expandedTrees = new mutable.WeakHashMap[Tree, Tree]() - val symOfTree = mutable.Map[Tree, Symbol]() + /** There are three maps at play here: + * + * + * Original tree ------------> Expanded tree(s) + * expandedTree : ^ + * (weak) : | + * : | + * symOfUntypedTree : | untypedTreeOfSym + * : | + * v | typedTreeOfSym + * Symbol --------------> Typed tree + * <:::::::::::::: + * symOfTypedTree + * + * The expandedTree map is weak, the others are strong. + * + * The untypedTreeOfSym map can be inverted to a map from untyped trees + * to the symbols they define. The function `symOfUntypedTree` looks up a + * symbol in the current context with the name of the tree and which points + * back (via untypedTreeOfSym) to the tree. Similarly, `typedTreeOfSym` can be + * inverted to `symofTypedTree`. + * + * Timeline: + * + * During enter, trees are expanded as necessary, populating the expandedTree map. + * Symbols are created, and the untypedTreeOfSym link is set up. + * + * Symbol completion causes some trees to be already typechecked and typedTreeOfSym + * entries are created to associate the typed trees with the untyped expanded originals. + * + * During typer, original trees are first expanded using expandedTree. For each + * expanded definition tree, we make sure the corresponding symbol is completed + * and remove its untypedTreeOfSym link. We then consult the typedTreeOfSym map. + * If a typed tree exists, it replaces the original untyped tree, and the corresponding + * entry in the typedTree map is removed. Otherwise the untyped tree is typechecked, + * yielding the typed tree. + * + * Dealing with shared tree nodes: + * + * The scheme is designed to allow arbitrary sharing of nodes: (1) The expansion of + * a tree is context free, so expanding trees several times yields the same result + * as expanding once. No need to lock or duplicate expandedTree items. (2) + * Each `enterSyms` pass over a shared node creates new symbols and the two remaining + * maps are indexed with these symbols, so no sharing occurs for them. + * + * Memory reclamation: + * + * expandedTrees is a weak map, so entries will be reclaimed once the original + * untyped tree is no longer referenced. typedTreeOfSym and untypedTreeOfSym + * entries are both removed by the time a definition is integrated in the typed tree + * during phase typer. + */ - implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition = - ctx.source.atPos(pos) + val expandedTree = new mutable.WeakHashMap[Tree, Tree] + + val untypedTreeOfSym = mutable.Map[Symbol, Tree]() + + val typedTreeOfSym = new mutable.HashMap[Symbol, tpd.Tree] implicit def posToCoord(pos: Position): Coord = positionCoord(pos) @@ -50,10 +103,20 @@ class Namer(val typer: Typer) { } } + def symOfTree(tree: Trees.NameTree[_], treeMap: collection.Map[Symbol, Trees.Tree[_]])(implicit ctx: Context): Symbol = { + var e = ctx.scope.lookupEntry(tree.name) + while (e != null && treeMap(e.sym) != tree) + e = ctx.scope.lookupNextEntry(e) + if (e == null) NoSymbol else e.sym + } + + 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(original), privateWithin, original.pos) - symOfTree(original) = sym + val sym = ctx.newSymbol(ctx.owner, name, flags, new Completer, privateWithin, original.pos) + untypedTreeOfSym(sym) = tree sym } tree match { @@ -81,14 +144,14 @@ class Namer(val typer: Typer) { New(classTypeRef(cdef), cdef.impl.constr.vparamss.nestedMap(refOfDef)) def methTypeParams(cdef: ClassDef) = - for (tparam <- cdef.tparams) yield - tparam.derivedTypeDef(Modifiers(TypeParam), tparam.name, tparam.tparams, tparam.rhs) + 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 methParamss(cdef: ClassDef) = - cdef.impl.constr.vparamss.nestedMap(vparam => - vparam.derivedValDef(Modifiers(TermParam), vparam.name, vparam.tpt, vparam.rhs)) + 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 expandCaseClass(cdef: ClassDef): ClassDef = { + def expandCaseClass(cdef: ClassDef): Tree = { val ClassDef(mods, cname, tparams, impl @ Template(constr, parents, self, stats)) = cdef val constr1 = if (constr.vparamss.nonEmpty) constr @@ -107,23 +170,52 @@ class Namer(val typer: Typer) { if (mods is Abstract) (Nil, Nil) else { val copyFirstParams = caseParams.map(vparam => - vparam.derivedValDef(Modifiers(TermParam), vparam.name, vparam.tpt, refOfDef(vparam))) + ValDef(Modifiers(TermParam), vparam.name, vparam.tpt, refOfDef(vparam)).withPos(vparam.pos)) val copyRestParamss = constr1.vparamss.tail.nestedMap(vparam => - vparam.derivedValDef(Modifiers(TermParam), vparam.name, vparam.tpt, EmptyTree)) + ValDef(Modifiers(TermParam), vparam.name, vparam.tpt, EmptyTree).withPos(vparam.pos)) val applyParamss = constr1.vparamss.nestedMap(vparam => - vparam.derivedValDef(Modifiers(TermParam), vparam.name, vparam.tpt, vparam.rhs)) + 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)) } - updateCompanion(cname.toTermName, applyMeths ::: unapplyMeth :: Nil) - addToClass(cdef, copyMeths ::: isDefinedMeth :: productArityMeth :: productElemMeths.toList) + 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)) + 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 = @@ -135,16 +227,6 @@ class Namer(val typer: Typer) { def addToModule(mdef: ModuleDef, stats: List[Tree]): ModuleDef = mdef.derivedModuleDef(mdef.mods, mdef.name, addToTemplate(mdef.impl, stats)) - def updateCompanion(name: TermName, newDefs: List[Tree]) = - for (companion @ ModuleDef(_, `name`, _) <- enclosingStats) { - expandedTrees(companion) = expandedTrees get companion match { - case Some(Thicket(vdef :: (cdef: ClassDef) :: Nil)) => - Thicket(vdef, addToClass(cdef, newDefs)) - case none => - addToModule(companion, newDefs) - } - } - def implicitWrapper(cdef: ClassDef) = DefDef(Modifiers(Synthetic | Implicit), cdef.name.toTermName, methTypeParams(cdef), methParamss(cdef), EmptyTree, creator(cdef)) @@ -164,29 +246,36 @@ class Namer(val typer: Typer) { 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 { - expandedTrees get mdef match { + expandedTree get mdef match { case Some(mdef1: ModuleDef) => mdef case _ => mdef } } case cdef: ClassDef => - val result = if (cdef.mods is Case) expandCaseClass(cdef) else cdef + 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(result :: implicitWrapper(cdef) :: Nil) + Thicket(cdef2 :: implicitWrapper(cdef) :: Nil) } - else result + else cdef2 case _ => tree } - if (tree1 ne tree) expandedTrees(tree) = tree1 + if (tree1 ne tree) expandedTree(tree) = tree1 tree1 } - def enterSyms(stats: List[Tree])(implicit ctx: Context): Unit = stats match { + 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))) @@ -194,27 +283,103 @@ class Namer(val typer: Typer) { for (expanded <- expansion(stat).toList) createSymbol(expanded, stat) enterSyms(rest) case Nil => + ctx } + 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(tree: Tree)(implicit ctx: Context) extends LazyType { - def complete(sym: SymDenotation): Unit = { - for (defn <- expandedTrees.getOrElse(tree, tree).toList if symOfTree(defn) == sym) - defn match { - case ValDef(mods, name, tpt, rhs) => - val (tpt1, rhs1) = - if (tpt.isEmpty) { - val rhs1 = typer.typedExpr(rhs) - (TypeTree().withType(rhs1.tpe), TypedSplice(rhs1)) - } - else (typer.typedType(tpt), rhs) - defn.derivedValDef(mods, name, TypedSplice(tpt1), rhs1) + 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) + + def inheritedResultType(paramFn: Type => Type): Type = { + lazy val schema = paramFn(WildcardType) + val site = sym.owner.symTypeRef + ((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) => + val itpe = cls.info + .nonPrivateDecl(sym.name) + .matchingDenotation(site, schema) + .asSeenFrom(site) + .info.finalResultType + tp & itpe + } + } + + def typedDefn(tree: Tree, sym: Symbol)(implicit ctx: Context): tpd.Tree = { + val tree1 = typer.typed(tree, sym.symRef) + typedTreeOfSym(sym) = tree1 + tree1 + } + + def valOrDefDefTypeSig[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 + else { + val inherited = inheritedResultType(paramFn) + if (inherited.exists) typer.typed(defn.tpt, inherited).tpe + else aheadDef(defn, op).tpt.tpe + } + } + def completeParams[UT <: untpd.NameTree, T <: tpd.Tree] + (params: List[UT], completer: DefTyper[UT, T])(implicit ctx: Context): Unit = { + enterSyms(params) + for (param <- params) aheadDef(param, completer) + } + def defDefTypeSig(defn: DefDef)(implicit ctx: Context) = { + val DefDef(_, _, tparams, vparamss, _, _) = defn + completeParams(tparams, completeTypeDef) + for (vparams <- vparamss) completeParams(vparams, completeValDef) + def wrapMethType(restpe: Type): Type = { + val monotpe = + (restpe /: vparamss) { (restpe, params) => + val creator = + if (params.nonEmpty && (params.head.mods is Implicit)) ImplicitMethodType else MethodType + creator.fromSymbols(params map symOfUntypedTree, restpe) + } + if (tparams.nonEmpty) PolyType.fromSymbols(tparams map symOfUntypedTree, monotpe) + else if (vparamss.isEmpty) ExprType(monotpe) + else monotpe } + valOrDefDefTypeSig(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 typeSig(defn: Tree): Type = defn match { + case defn: ValDef => + valOrDefDefTypeSig(defn, completeValDef, identity)(ctx.fresh.withOwner(sym)) + case defn: DefDef => + defDefTypeSig(defn)(localContext(sym)) + 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! + case defn: ClassDef => + classDefTypeSig(defn)(ctx.fresh.withOwner(sym)) + case imp: Import => + val expr1 = typedDefn(imp.expr, sym) + ImportType(SharedTree(expr1)) } + + sym.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 c9405af86..44cefe5e6 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -14,8 +14,87 @@ import language.implicitConversions trait TyperContextOps { ctx: Context => } -class Typer { - def typed(tree: untpd.Tree, pt: Type)(implicit ctx: Context): tpd.Tree = ??? - def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree = ??? - def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree = ??? +class Typer extends Namer { + + import tpd._ + + def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = ??? + def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = ??? + def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = ??? + + type DefTyper[UT <: untpd.NameTree, T <: tpd.Tree] = (UT, NamedType) => Context => T + + def lateDef[UT <: untpd.NameTree, T <: tpd.Tree](defn: UT, op: DefTyper[UT, T])(implicit ctx: Context): T = { + val sym = symOfUntypedTree(defn) + sym.ensureCompleted() + untypedTreeOfSym -= sym + typedTreeOfSym remove sym match { + case Some(tree) => tree.asInstanceOf[T] + case None => op(defn, sym.symRef)(ctx) + } + } + + def aheadDef[UT <: untpd.NameTree, T <: tpd.Tree](defn: UT, op: DefTyper[UT, T])(implicit ctx: Context): T = { + val sym = symOfUntypedTree(defn) + val tree1 = op(defn, sym.symRef)(ctx) + typedTreeOfSym(sym) = tree1 + tree1 + } + + def noDefTyper: DefTyper[untpd.NameTree, Nothing] = { (tdef, pt) => implicit ctx => ??? } + + val completeTypeDef: DefTyper[untpd.TypeDef, TypeDef] = { (tdef, pt) => implicit ctx => + val Trees.TypeDef(mods, name, tparams, rhs) = tdef + val mods1 = typedModifiers(mods) + val tparams1 = reEnterParams(tparams) + val rhs1 = typedType(rhs) + tdef.withType(pt).derivedTypeDef(mods1, name, tparams1, rhs1) + } + + def typedTypedDef(tdef: untpd.TypeDef)(implicit ctx: Context): TypeDef = + lateDef(tdef, completeTypeDef) + + def typedTptRhs(tpt: untpd.Tree, rhs: untpd.Tree)(implicit ctx: Context): (Tree, Tree) = { + var tpt1: Tree = EmptyTree + var rhs1: Tree = EmptyTree + if (tpt.isEmpty) { + rhs1 = typedExpr(rhs) + tpt1 = tpt.withType(rhs1.tpe) + } else { + tpt1 = typedType(tpt) + rhs1 = typedExpr(rhs, tpt1.tpe) + } + (tpt1, rhs1) + } + + val completeValDef: DefTyper[untpd.ValDef, ValDef] = { (vdef, pt) => implicit ctx: Context => + val Trees.ValDef(mods, name, tpt, rhs) = vdef + val mods1 = typedModifiers(mods) + val (tpt1, rhs1) = typedTptRhs(tpt, rhs) + vdef.withType(tpt1.tpe).derivedValDef(mods1, name, tpt1, rhs1) + } + + 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) + lateDef(param, noDefTyper) + } + } + + val completeDefDef: DefTyper[untpd.DefDef, DefDef] = { (ddef, pt) => implicit ctx: Context => + val Trees.DefDef(mods, name, tparams, vparamss, tpt, rhs) = ddef + val mods1 = typedModifiers(mods) + val tparams1: List[TypeDef] = reEnterParams(tparams) + val vparamss1: List[List[ValDef]] = vparamss.mapconserve(reEnterParams) + val (tpt1, rhs1) = typedTptRhs(tpt, rhs) + ddef.withType(tpt1.tpe).derivedDefDef(mods1, name, tparams1, vparamss1, tpt1, rhs1) + } + + def typedImport(imp: untpd.Import, pt: Type)(implicit ctx: Context): Import = { + val expr1 = typed(imp.expr) + imp.withType(pt).derivedImport(expr1, imp.selectors) + } + + def typedModifiers(mods: untpd.Modifiers): Modifiers = ??? } \ No newline at end of file -- cgit v1.2.3