aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/typer/Namer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-11-10 11:54:27 +0100
committerMartin Odersky <odersky@gmail.com>2016-12-01 13:55:12 +0100
commit2b12868070be50fb70c687bcd8a415acbe398e3e (patch)
treef3977e7e9408ff6adc14f4ef6e685e710f310410 /compiler/src/dotty/tools/dotc/typer/Namer.scala
parent4ae76f2164e91d6a26519304b5ac5df527ae9207 (diff)
downloaddotty-2b12868070be50fb70c687bcd8a415acbe398e3e.tar.gz
dotty-2b12868070be50fb70c687bcd8a415acbe398e3e.tar.bz2
dotty-2b12868070be50fb70c687bcd8a415acbe398e3e.zip
New phase for entering annotations
If we want to do annotation macros right, we need to add annotations before completing definitions. This commit achieves that by adding a new "phase" between index and typecheck.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/typer/Namer.scala')
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Namer.scala109
1 files changed, 89 insertions, 20 deletions
diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala
index 148cf1da7..9b6bad291 100644
--- a/compiler/src/dotty/tools/dotc/typer/Namer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala
@@ -528,18 +528,96 @@ class Namer { typer: Typer =>
}
}
- stats foreach expand
+ stats.foreach(expand)
mergeCompanionDefs()
val ctxWithStats = (ctx /: stats) ((ctx, stat) => indexExpanded(stat)(ctx))
createCompanionLinks(ctxWithStats)
ctxWithStats
}
+ /** Add all annotations of definitions in `stats` to the defined symbols */
+ def annotate(stats: List[Tree])(implicit ctx: Context): Unit = {
+ def recur(stat: Tree): Unit = stat match {
+ case pcl: PackageDef =>
+ annotate(pcl.stats)
+ case stat: untpd.MemberDef =>
+ stat.getAttachment(SymOfTree) match {
+ case Some(sym) =>
+ sym.infoOrCompleter match {
+ case info: Completer if !defn.isPredefClass(sym.owner) =>
+ // Annotate Predef methods only when they are completed;
+ // This is necessary to break a cyclic dependence between `Predef`
+ // and `deprecated` in test `compileStdLib`.
+ addAnnotations(sym, stat)(info.creationContext)
+ case _ =>
+ // Annotations were already added as part of the symbol's completion
+ }
+ case none =>
+ assert(stat.typeOpt.exists, i"no symbol for $stat")
+ }
+ case stat: untpd.Thicket =>
+ stat.trees.foreach(recur)
+ case _ =>
+ }
+
+ for (stat <- stats) recur(expanded(stat))
+ }
+
+ /** Add annotations of `stat` to `sym`.
+ * This method can be called twice on a symbol (e.g. once
+ * during the `annotate` phase and then again during completion).
+ * Therefore, care needs to be taken not to add annotations again
+ * that are already added to the symbol.
+ */
+ def addAnnotations(sym: Symbol, stat: MemberDef)(implicit ctx: Context) = {
+ // (1) The context in which an annotation of a top-evel class or module is evaluated
+ // is the closest enclosing context which has the enclosing package as owner.
+ // (2) The context in which an annotation for any other symbol is evaluated is the
+ // closest enclosing context which has the owner of the class enclpsing the symbol as owner.
+ // E.g in
+ //
+ // package p
+ // import a.b
+ // class C {
+ // import d.e
+ // @ann m() ...
+ // }
+ //
+ // `@ann` is evaluated in the context just outside `C`, where the `a.b`
+ // import is visible but the `d.e` import is forgotten. This measure is necessary
+ // in order to avoid cycles.
+ lazy val annotCtx = {
+ var target = sym.owner.lexicallyEnclosingClass
+ if (!target.is(PackageClass)) target = target.owner
+ var c = ctx
+ while (c.owner != target) c = c.outer
+ c
+ }
+ for (annotTree <- untpd.modsDeco(stat).mods.annotations) {
+ val cls = typedAheadAnnotation(annotTree)(annotCtx)
+ if (sym.unforcedAnnotation(cls).isEmpty) {
+ val ann = Annotation.deferred(cls, implicit ctx => typedAnnotation(annotTree))
+ sym.addAnnotation(ann)
+ if (cls == defn.InlineAnnot && sym.is(Method, butNot = Accessor))
+ sym.setFlag(Inline)
+ }
+ }
+ }
+
+ def indexAndAnnotate(stats: List[Tree])(implicit ctx: Context): Context = {
+ val localCtx = index(stats)
+ annotate(stats)
+ localCtx
+ }
+
/** The completer of a symbol defined by a member def or import (except ClassSymbols) */
class Completer(val original: Tree)(implicit ctx: Context) extends LazyType {
protected def localContext(owner: Symbol) = ctx.fresh.setOwner(owner).setTree(original)
+ /** The context with which this completer was created */
+ def creationContext = ctx
+
protected def typeSig(sym: Symbol): Type = original match {
case original: ValDef =>
if (sym is Module) moduleValSig(sym)
@@ -572,19 +650,6 @@ class Namer { typer: Typer =>
completeInCreationContext(denot)
}
- protected def addAnnotations(denot: SymDenotation): Unit = original match {
- case original: untpd.MemberDef =>
- var hasInlineAnnot = false
- for (annotTree <- untpd.modsDeco(original).mods.annotations) {
- val cls = typedAheadAnnotation(annotTree)
- val ann = Annotation.deferred(cls, implicit ctx => typedAnnotation(annotTree))
- denot.addAnnotation(ann)
- if (cls == defn.InlineAnnot && denot.is(Method, butNot = Accessor))
- denot.setFlag(Inline)
- }
- case _ =>
- }
-
private def addInlineInfo(denot: SymDenotation) = original match {
case original: untpd.DefDef if denot.isInlineMethod =>
Inliner.registerInlineInfo(
@@ -598,7 +663,10 @@ class Namer { typer: Typer =>
* to pick up the context at the point where the completer was created.
*/
def completeInCreationContext(denot: SymDenotation): Unit = {
- addAnnotations(denot)
+ original match {
+ case original: MemberDef => addAnnotations(denot.symbol, original)
+ case _ =>
+ }
addInlineInfo(denot)
denot.info = typeSig(denot.symbol)
Checking.checkWellFormed(denot.symbol)
@@ -742,7 +810,7 @@ class Namer { typer: Typer =>
ok
}
- addAnnotations(denot)
+ addAnnotations(denot.symbol, original)
val selfInfo =
if (self.isEmpty) NoType
@@ -765,9 +833,10 @@ class Namer { typer: Typer =>
// accessors, that's why the constructor needs to be completed before
// the parent types are elaborated.
index(constr)
+ annotate(constr :: params)
symbolOfTree(constr).ensureCompleted()
- index(rest)(inClassContext(selfInfo))
+ indexAndAnnotate(rest)(inClassContext(selfInfo))
val tparamAccessors = decls.filter(_ is TypeParamAccessor).toList
val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_, tparamAccessors)))
@@ -790,7 +859,7 @@ class Namer { typer: Typer =>
case Some(ttree) => ttree
case none =>
val ttree = typer.typed(tree, pt)
- xtree.pushAttachment(TypedAhead, ttree)
+ xtree.putAttachment(TypedAhead, ttree)
ttree
}
}
@@ -810,7 +879,7 @@ class Namer { typer: Typer =>
/** Enter and typecheck parameter list */
def completeParams(params: List[MemberDef])(implicit ctx: Context) = {
- index(params)
+ indexAndAnnotate(params)
for (param <- params) typedAheadExpr(param)
}
@@ -990,7 +1059,7 @@ class Namer { typer: Typer =>
// 3. Info of CP is computed (to be copied to DP).
// 4. CP is completed.
// 5. Info of CP is copied to DP and DP is completed.
- index(tparams)
+ indexAndAnnotate(tparams)
if (isConstructor) sym.owner.typeParams.foreach(_.ensureCompleted())
for (tparam <- tparams) typedAheadExpr(tparam)