aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Namer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-06-03 11:33:53 +0200
committerMartin Odersky <odersky@gmail.com>2013-06-03 11:33:53 +0200
commit339809ed82e14699681a5a7765c87133cd681ec0 (patch)
tree283b653e9260d3feb01e19b955033de74bc53790 /src/dotty/tools/dotc/typer/Namer.scala
parent17d0e7008f62882c10193ea0db09c9b90736c320 (diff)
downloaddotty-339809ed82e14699681a5a7765c87133cd681ec0.tar.gz
dotty-339809ed82e14699681a5a7765c87133cd681ec0.tar.bz2
dotty-339809ed82e14699681a5a7765c87133cd681ec0.zip
More solid design of Namer with some Typer bits added.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Namer.scala')
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala257
1 files changed, 211 insertions, 46 deletions
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