1
1
package dotty .tools .dotc
2
2
package transform
3
3
4
+ import ast .tpd
5
+ import ast .Trees .*
6
+ import ast .TreeMapWithImplicits
4
7
import core .*
5
8
import Flags .*
9
+ import Decorators .*
6
10
import Contexts .*
7
11
import Symbols .*
12
+ import Decorators .*
13
+ import config .Printers .inlining
14
+ import DenotTransformers .IdentityDenotTransformer
15
+ import inlines .Inlines
16
+ import quoted .*
17
+ import staging .StagingLevel
8
18
9
- import dotty .tools .dotc .ast .tpd
10
- import dotty .tools .dotc .ast .Trees .*
11
- import dotty .tools .dotc .quoted .*
12
- import dotty .tools .dotc .inlines .Inlines
13
- import dotty .tools .dotc .ast .TreeMapWithImplicits
14
- import dotty .tools .dotc .core .DenotTransformers .IdentityDenotTransformer
15
- import dotty .tools .dotc .staging .StagingLevel
16
-
17
- import scala .collection .mutable .ListBuffer
19
+ import scala .collection .mutable
18
20
19
21
/** Inlines all calls to inline methods that are not in an inline method or a quote */
20
22
class Inlining extends MacroTransform , IdentityDenotTransformer {
@@ -56,38 +58,82 @@ class Inlining extends MacroTransform, IdentityDenotTransformer {
56
58
57
59
def newTransformer (using Context ): Transformer = new Transformer {
58
60
override def transform (tree : tpd.Tree )(using Context ): tpd.Tree =
59
- new InliningTreeMap ().transform(tree)
61
+ InliningTreeMap ().transform(tree)
62
+ }
63
+
64
+ private class MemoizeStatsTreeMap extends TreeMapWithImplicits {
65
+
66
+ // It is safe to assume that the companion of a tree is in the same scope
67
+ // Therefore, when expanding MacroAnnotations, we will only keep track of
68
+ // the trees in the same scope as the current transformed tree
69
+
70
+ override def transform (tree : Tree )(using Context ): Tree =
71
+ tree match
72
+ case PackageDef (_, stats) =>
73
+ // Phase I: Collect and memoize all the stats
74
+ val treesToTrack = stats.collect { case m : MemberDef => (m.symbol, m) }
75
+ val withTrackedTreeCtx = MacroAnnotations .trackedTreesCtx(mutable.Map (treesToTrack* ))
76
+ // Phase II & III: Transform the tree with this definitions and reconcile them with the tracked trees
77
+ super .transform(tree)(using withTrackedTreeCtx) match
78
+ case pkg@ PackageDef (pid, stats) =>
79
+ val trackedTree = MacroAnnotations .trackedTrees(using withTrackedTreeCtx)
80
+ val updatedStats = stats.mapConserve:
81
+ case tree : MemberDef if trackedTree.contains(tree.symbol) =>
82
+ trackedTree(tree.symbol)
83
+ case stat => stat
84
+ cpy.PackageDef (pkg)(pid = pid, stats = updatedStats)
85
+ case tree => tree
86
+ case block : Block =>
87
+ // Phase I: Fetch all the member definitions in the block
88
+ val trackedTrees = block.stats.collect { case m : MemberDef => (m.symbol, m) }
89
+ val withTrackedTreeCtx = MacroAnnotations .trackedTreesCtx(mutable.Map (trackedTrees* ))
90
+
91
+ // Phase II / III: Transform the tree and Reconcile between the symbols in syms and the tree
92
+ // TODO: Should we define a substitution method where we change the trees
93
+ // and not the symbols (see Tree::subst)
94
+ // result.subst(MacroAnnotations.trackedTrees(using withTrackedTreeCtx))
95
+ super .transform(tree)(using withTrackedTreeCtx) match
96
+ case b@ Block (stats, expr) =>
97
+ val trackedTree = MacroAnnotations .trackedTrees(using withTrackedTreeCtx)
98
+ cpy.Block (b)(
99
+ expr = expr,
100
+ stats = stats.mapConserve:
101
+ case ddef : MemberDef if trackedTree.contains(ddef.symbol) =>
102
+ trackedTree(ddef.symbol)
103
+ case stat => stat
104
+ )
105
+ case tree => tree
106
+ case TypeDef (_, impl : Template ) =>
107
+ // Phase I: Collect and memoize all the stats
108
+ val treesToTrack = impl.body.collect { case m : MemberDef => (m.symbol, m) }
109
+ val withTrackedTreeCtx = MacroAnnotations .trackedTreesCtx(mutable.Map (treesToTrack* ))
110
+ // Phase II / III: Transform the tree and Reconcile between the symbols in syms and the tree
111
+ super .transform(tree)(using withTrackedTreeCtx) match
112
+ case tree@ TypeDef (name, impl : Template ) =>
113
+ val trackedTree = MacroAnnotations .trackedTrees(using withTrackedTreeCtx)
114
+ cpy.TypeDef (tree)(
115
+ name = name,
116
+ rhs = cpy.Template (impl)(
117
+ body = impl.body.mapConserve:
118
+ case ddef : MemberDef if trackedTree.contains(ddef.symbol) =>
119
+ trackedTree(ddef.symbol)
120
+ case stat => stat
121
+ )
122
+ )
123
+ case tree => tree
124
+ case _ => super .transform(tree)
60
125
}
61
126
62
- private class InliningTreeMap extends TreeMapWithImplicits {
127
+ private class InliningTreeMap extends MemoizeStatsTreeMap {
63
128
64
129
/** List of top level classes added by macro annotation in a package object.
65
130
* These are added to the PackageDef that owns this particular package object.
66
131
*/
67
- private val newTopClasses = MutableSymbolMap [ListBuffer [Tree ]]()
132
+ private val newTopClasses = MutableSymbolMap [mutable. ListBuffer [Tree ]]()
68
133
69
134
override def transform (tree : Tree )(using Context ): Tree = {
70
135
tree match
71
- case tree : MemberDef =>
72
- if tree.symbol.is(Inline ) then tree
73
- else if tree.symbol.is(Param ) then super .transform(tree)
74
- else if
75
- ! tree.symbol.isPrimaryConstructor
76
- && StagingLevel .level == 0
77
- && MacroAnnotations .hasMacroAnnotation(tree.symbol)
78
- then
79
- val trees = (new MacroAnnotations (self)).expandAnnotations(tree)
80
- val trees1 = trees.map(super .transform)
81
-
82
- // Find classes added to the top level from a package object
83
- val (topClasses, trees2) =
84
- if ctx.owner.isPackageObject then trees1.partition(_.symbol.owner == ctx.owner.owner)
85
- else (Nil , trees1)
86
- if topClasses.nonEmpty then
87
- newTopClasses.getOrElseUpdate(ctx.owner.owner, new ListBuffer ) ++= topClasses
88
-
89
- flatTree(trees2)
90
- else super .transform(tree)
136
+ case tree : MemberDef => transformMemberDef(tree)
91
137
case _ : Typed | _ : Block =>
92
138
super .transform(tree)
93
139
case _ : PackageDef =>
@@ -113,7 +159,61 @@ class Inlining extends MacroTransform, IdentityDenotTransformer {
113
159
else Inlines .inlineCall(tree1)
114
160
else super .transform(tree)
115
161
}
162
+
163
+ private def transformMemberDef (tree : MemberDef )(using Context ) : Tree =
164
+ if tree.symbol.is(Inline ) then tree
165
+ else if tree.symbol.is(Param ) then
166
+ super .transform(tree)
167
+ else if
168
+ ! tree.symbol.isPrimaryConstructor
169
+ && StagingLevel .level == 0
170
+ && MacroAnnotations .hasMacroAnnotation(tree.symbol)
171
+ then
172
+ // Fetch the companion's tree
173
+ val companionSym =
174
+ if tree.symbol.is(ModuleClass ) then tree.symbol.companionClass
175
+ else if tree.symbol.is(ModuleVal ) then NoSymbol
176
+ else tree.symbol.companionModule.moduleClass
177
+
178
+ val companionTree = MacroAnnotations .findTrackedTree(companionSym)
179
+
180
+ // Fetch the latest tracked tree (It might have already been processed by its companion)
181
+ val latestTree = MacroAnnotations .findTrackedTree(tree.symbol)
182
+ .getOrElse(tree)
183
+
184
+ // Expand and process MacroAnnotations
185
+ val (trees, companion) =
186
+ MacroAnnotations (self).expandAnnotations(latestTree, companionTree)
187
+
188
+ // Update the tracked trees
189
+ for case tree : MemberDef <- trees do
190
+ MacroAnnotations .updateTrackedTree(tree.symbol, tree)
191
+ for tree <- companion do
192
+ MacroAnnotations .updateTrackedTree(tree.symbol, tree)
193
+
194
+ // Perform inlining on the expansion of the annotations
195
+ val trees1 = trees.map(super .transform)
196
+
197
+ for case tree : MemberDef <- trees1 do
198
+ MacroAnnotations .updateTrackedTree(tree.symbol, tree)
199
+
200
+ // Find classes added to the top level from a package object
201
+ val (topClasses, trees2) =
202
+ if ctx.owner.isPackageObject then trees1.partition(_.symbol.owner == ctx.owner.owner)
203
+ else (Nil , trees1)
204
+ if topClasses.nonEmpty then
205
+ newTopClasses.getOrElseUpdate(ctx.owner.owner, new mutable.ListBuffer ) ++= topClasses
206
+ flatTree(trees2)
207
+ else
208
+ super .transform(tree) match
209
+ case tree : MemberDef =>
210
+ MacroAnnotations .updateTrackedTree(tree.symbol, tree)
211
+ tree
212
+ case tree => tree
213
+ end transformMemberDef
214
+
116
215
}
216
+
117
217
}
118
218
119
219
object Inlining :
0 commit comments