@@ -5,6 +5,8 @@ trait AsyncTransform {
5
5
6
6
import global ._
7
7
8
+ val asyncBase : AsyncBase
9
+
8
10
def asyncTransform [T ](body : Tree , execContext : Tree , cpsFallbackEnabled : Boolean )
9
11
(resultType : WeakTypeTag [T ]): Tree = {
10
12
@@ -29,6 +31,7 @@ trait AsyncTransform {
29
31
30
32
val stateMachineType = applied(" scala.async.StateMachine" , List (futureSystemOps.promType[T ](uncheckedBoundsResultTag), futureSystemOps.execContextType))
31
33
34
+ // Create `ClassDef` of state machine with empty method bodies for `resume` and `apply`.
32
35
val stateMachine : ClassDef = {
33
36
val body : List [Tree ] = {
34
37
val stateVar = ValDef (Modifiers (Flag .MUTABLE | Flag .PRIVATE | Flag .LOCAL ), name.state, TypeTree (definitions.IntTpe ), Literal (Constant (0 )))
@@ -42,24 +45,45 @@ trait AsyncTransform {
42
45
}
43
46
List (emptyConstructor, stateVar, result, execContextValDef) ++ List (resumeFunTreeDummyBody, applyDefDefDummyBody, apply0DefDef)
44
47
}
45
- val template = {
46
- Template (List (stateMachineType), emptyValDef, body)
47
- }
48
+
49
+ val template = Template (List (stateMachineType), emptyValDef, body)
50
+
48
51
val t = ClassDef (NoMods , name.stateMachineT, Nil , template)
49
52
callSiteTyper.typedPos(macroPos)(Block (t :: Nil , Literal (Constant (()))))
50
53
t
51
54
}
52
55
56
+ val stateMachineClass = stateMachine.symbol
53
57
val asyncBlock : AsyncBlock = {
54
- val symLookup = new SymLookup (stateMachine.symbol , applyDefDefDummyBody.vparamss.head.head.symbol)
58
+ val symLookup = new SymLookup (stateMachineClass , applyDefDefDummyBody.vparamss.head.head.symbol)
55
59
buildAsyncBlock(anfTree, symLookup)
56
60
}
57
61
58
62
logDiagnostics(anfTree, asyncBlock.asyncStates.map(_.toString))
59
63
64
+ val liftedFields : List [Tree ] = liftables(asyncBlock.asyncStates)
65
+
66
+ // live variables analysis
67
+ // the result map indicates in which states a given field should be nulled out
68
+ val assignsOf = fieldsToNullOut(asyncBlock.asyncStates, liftedFields)
69
+
70
+ for ((state, flds) <- assignsOf) {
71
+ val assigns = flds.map { fld =>
72
+ val fieldSym = fld.symbol
73
+ Block (
74
+ List (
75
+ asyncBase.nullOut(global)(Expr [String ](Literal (Constant (fieldSym.name.toString))), Expr [Any ](Ident (fieldSym))).tree
76
+ ),
77
+ Assign (gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), gen.mkZero(fieldSym.info))
78
+ )
79
+ }
80
+ val asyncState = asyncBlock.asyncStates.find(_.state == state).get
81
+ asyncState.stats = assigns ++ asyncState.stats
82
+ }
83
+
60
84
def startStateMachine : Tree = {
61
85
val stateMachineSpliced : Tree = spliceMethodBodies(
62
- liftables(asyncBlock.asyncStates) ,
86
+ liftedFields ,
63
87
stateMachine,
64
88
atMacroPos(asyncBlock.onCompleteHandler[T ]),
65
89
atMacroPos(asyncBlock.resumeFunTree[T ].rhs)
@@ -96,9 +120,16 @@ trait AsyncTransform {
96
120
states foreach (s => AsyncUtils .vprintln(s))
97
121
}
98
122
99
- def spliceMethodBodies (liftables : List [Tree ], tree : Tree , applyBody : Tree ,
100
- resumeBody : Tree ): Tree = {
101
-
123
+ /**
124
+ * Build final `ClassDef` tree of state machine class.
125
+ *
126
+ * @param liftables trees of definitions that are lifted to fields of the state machine class
127
+ * @param tree `ClassDef` tree of the state machine class
128
+ * @param applyBody tree of onComplete handler (`apply` method)
129
+ * @param resumeBody RHS of definition tree of `resume` method
130
+ * @return transformed `ClassDef` tree of the state machine class
131
+ */
132
+ def spliceMethodBodies (liftables : List [Tree ], tree : ClassDef , applyBody : Tree , resumeBody : Tree ): Tree = {
102
133
val liftedSyms = liftables.map(_.symbol).toSet
103
134
val stateMachineClass = tree.symbol
104
135
liftedSyms.foreach {
@@ -112,7 +143,7 @@ trait AsyncTransform {
112
143
// Replace the ValDefs in the splicee with Assigns to the corresponding lifted
113
144
// fields. Similarly, replace references to them with references to the field.
114
145
//
115
- // This transform will be only be run on the RHS of `def foo`.
146
+ // This transform will only be run on the RHS of `def foo`.
116
147
class UseFields extends MacroTypingTransformer {
117
148
override def transform (tree : Tree ): Tree = tree match {
118
149
case _ if currentOwner == stateMachineClass =>
@@ -150,6 +181,7 @@ trait AsyncTransform {
150
181
}
151
182
val treeSubst = tree
152
183
184
+ /* Fixes up DefDef: use lifted fields in `body` */
153
185
def fixup (dd : DefDef , body : Tree , ctx : analyzer.Context ): Tree = {
154
186
val spliceeAnfFixedOwnerSyms = body
155
187
val useField = new UseFields ()
@@ -171,6 +203,7 @@ trait AsyncTransform {
171
203
(ctx : analyzer.Context ) =>
172
204
val typedTree = fixup(dd, changeOwner(applyBody, callSiteTyper.context.owner, dd.symbol), ctx)
173
205
typedTree
206
+
174
207
case dd@ DefDef (_, name.resume, _, _, _, _) if dd.symbol.owner == stateMachineClass =>
175
208
(ctx : analyzer.Context ) =>
176
209
val changed = changeOwner(resumeBody, callSiteTyper.context.owner, dd.symbol)
0 commit comments