1+ package dotty .tools .dotc
2+ package transform
3+
4+ import core ._
5+ import typer ._
6+ import ast .Trees ._
7+ import Contexts ._
8+ import Symbols ._
9+ import Decorators ._
10+ import collection .mutable
11+ import annotation .tailrec
12+
13+ /** A Macrotransform that maintains the necessary infrastructore to support
14+ * contxtual implicit searches (type-scope implicits are supported anyway).
15+ */
16+ abstract class MacroTransformWithImplicits extends MacroTransform {
17+ import ast .tpd ._
18+
19+ override def allowsImplicitSearch = true
20+
21+ class ImplicitsTransformer extends Transformer {
22+
23+ /** Transform statements, while maintaining import contexts and expression contexts
24+ * in the same way as Typer does. The code addresses additional concerns:
25+ * - be tail-recursive where possible
26+ * - don't re-allocate trees where nothing has changed
27+ */
28+ override def transformStats (stats : List [Tree ], exprOwner : Symbol )(implicit ctx : Context ): List [Tree ] = {
29+
30+ @ tailrec def traverse (curStats : List [Tree ])(implicit ctx : Context ): List [Tree ] = {
31+
32+ def recur (stats : List [Tree ], changed : Tree , rest : List [Tree ])(implicit ctx : Context ): List [Tree ] = {
33+ if (stats eq curStats) {
34+ val rest1 = transformStats(rest, exprOwner)
35+ changed match {
36+ case Thicket (trees) => trees ::: rest1
37+ case tree => tree :: rest1
38+ }
39+ }
40+ else stats.head :: recur(stats.tail, changed, rest)
41+ }
42+
43+ curStats match {
44+ case stat :: rest =>
45+ val statCtx = stat match {
46+ case stat : DefTree => ctx
47+ case _ => ctx.exprContext(stat, exprOwner)
48+ }
49+ val restCtx = stat match {
50+ case stat : Import => ctx.importContext(stat, stat.symbol)
51+ case _ => ctx
52+ }
53+ val stat1 = transform(stat)(statCtx)
54+ if (stat1 ne stat) recur(stats, stat1, rest)(restCtx)
55+ else traverse(rest)(restCtx)
56+ case nil =>
57+ stats
58+ }
59+ }
60+ traverse(stats)
61+ }
62+
63+ private def nestedScopeCtx (defs : List [Tree ])(implicit ctx : Context ): Context = {
64+ val nestedCtx = ctx.fresh.setNewScope
65+ defs foreach {
66+ case d : DefTree => nestedCtx.enter(d.symbol)
67+ case _ =>
68+ }
69+ nestedCtx
70+ }
71+
72+ override def transform (tree : Tree )(implicit ctx : Context ): Tree = {
73+ def localCtx = ctx.withOwner(tree.symbol)
74+ tree match {
75+ case tree : Block =>
76+ super .transform(tree)(nestedScopeCtx(tree.stats))
77+ case tree : DefDef =>
78+ implicit val ctx = localCtx
79+ cpy.DefDef (tree)(
80+ tree.name,
81+ transformSub(tree.tparams),
82+ tree.vparamss mapConserve (transformSub(_)),
83+ transform(tree.tpt),
84+ transform(tree.rhs)(nestedScopeCtx(tree.vparamss.flatten)))
85+ case _ =>
86+ super .transform(tree)
87+ }
88+ }
89+ }
90+ }
0 commit comments