@@ -7,6 +7,9 @@ package scala.async
7
7
import scala .language .experimental .macros
8
8
import scala .reflect .macros .Context
9
9
import scala .reflect .internal .annotations .compileTimeOnly
10
+ import scala .tools .nsc .Global
11
+ import language .reflectiveCalls
12
+ import scala .concurrent .ExecutionContext
10
13
11
14
object Async extends AsyncBase {
12
15
@@ -15,18 +18,22 @@ object Async extends AsyncBase {
15
18
lazy val futureSystem = ScalaConcurrentFutureSystem
16
19
type FS = ScalaConcurrentFutureSystem .type
17
20
18
- def async [T ](body : T ) = macro asyncImpl[T ]
21
+ def async [T ](body : T )( implicit execContext : ExecutionContext ) : Future [ T ] = macro asyncImpl[T ]
19
22
20
- override def asyncImpl [T : c.WeakTypeTag ](c : Context )(body : c.Expr [T ]): c.Expr [Future [T ]] = super .asyncImpl[T ](c)(body)
23
+ override def asyncImpl [T : c.WeakTypeTag ](c : Context )
24
+ (body : c.Expr [T ])
25
+ (execContext : c.Expr [futureSystem.ExecContext ]): c.Expr [Future [T ]] = {
26
+ super .asyncImpl[T ](c)(body)(execContext)
27
+ }
21
28
}
22
29
23
30
object AsyncId extends AsyncBase {
24
31
lazy val futureSystem = IdentityFutureSystem
25
32
type FS = IdentityFutureSystem .type
26
33
27
- def async [T ](body : T ) = macro asyncImpl [T ]
34
+ def async [T ](body : T ) = macro asyncIdImpl [T ]
28
35
29
- override def asyncImpl [T : c.WeakTypeTag ](c : Context )(body : c.Expr [T ]): c.Expr [T ] = super . asyncImpl[T ](c)(body)
36
+ def asyncIdImpl [T : c.WeakTypeTag ](c : Context )(body : c.Expr [T ]): c.Expr [T ] = asyncImpl[T ](c)(body)(c.literalUnit )
30
37
}
31
38
32
39
/**
@@ -62,124 +69,26 @@ abstract class AsyncBase {
62
69
63
70
protected [async] def fallbackEnabled = false
64
71
65
- def asyncImpl [T : c.WeakTypeTag ](c : Context )(body : c.Expr [T ]): c.Expr [futureSystem.Fut [T ]] = {
72
+ def asyncImpl [T : c.WeakTypeTag ](c : Context )
73
+ (body : c.Expr [T ])
74
+ (execContext : c.Expr [futureSystem.ExecContext ]): c.Expr [futureSystem.Fut [T ]] = {
66
75
import c .universe ._
67
76
68
- val analyzer = AsyncAnalysis [c.type ](c, this )
69
- val utils = TransformUtils [c.type ](c)
70
- import utils .{name , defn }
71
-
72
- analyzer.reportUnsupportedAwaits(body.tree)
73
-
74
- // Transform to A-normal form:
75
- // - no await calls in qualifiers or arguments,
76
- // - if/match only used in statement position.
77
- val anfTree : Block = {
78
- val anf = AnfTransform [c.type ](c)
79
- val restored = utils.restorePatternMatchingFunctions(body.tree)
80
- val stats1 :+ expr1 = anf(restored)
81
- val block = Block (stats1, expr1)
82
- c.typeCheck(block).asInstanceOf [Block ]
83
- }
84
-
85
- // Analyze the block to find locals that will be accessed from multiple
86
- // states of our generated state machine, e.g. a value assigned before
87
- // an `await` and read afterwards.
88
- val renameMap : Map [Symbol , TermName ] = {
89
- analyzer.defTreesUsedInSubsequentStates(anfTree).map {
90
- vd =>
91
- (vd.symbol, name.fresh(vd.name.toTermName))
92
- }.toMap
93
- }
94
-
95
- val builder = ExprBuilder [c.type , futureSystem.type ](c, self.futureSystem, anfTree)
96
- import builder .futureSystemOps
97
- val asyncBlock : builder.AsyncBlock = builder.build(anfTree, renameMap)
98
- import asyncBlock .asyncStates
99
- logDiagnostics(c)(anfTree, asyncStates.map(_.toString))
100
-
101
- // Important to retain the original declaration order here!
102
- val localVarTrees = anfTree.collect {
103
- case vd@ ValDef (_, _, tpt, _) if renameMap contains vd.symbol =>
104
- utils.mkVarDefTree(tpt.tpe, renameMap(vd.symbol))
105
- case dd@ DefDef (mods, name, tparams, vparamss, tpt, rhs) if renameMap contains dd.symbol =>
106
- DefDef (mods, renameMap(dd.symbol), tparams, vparamss, tpt, c.resetAllAttrs(utils.substituteNames(rhs, renameMap)))
107
- }
108
-
109
- val onCompleteHandler = {
110
- Function (
111
- List (ValDef (Modifiers (Flag .PARAM ), name.tr, TypeTree (defn.TryAnyType ), EmptyTree )),
112
- asyncBlock.onCompleteHandler)
113
- }
114
- val resumeFunTree = asyncBlock.resumeFunTree[T ]
115
-
116
- val stateMachineType = utils.applied(" scala.async.StateMachine" , List (futureSystemOps.promType[T ], futureSystemOps.execContextType))
117
-
118
- lazy val stateMachine : ClassDef = {
119
- val body : List [Tree ] = {
120
- val stateVar = ValDef (Modifiers (Flag .MUTABLE ), name.state, TypeTree (definitions.IntTpe ), Literal (Constant (0 )))
121
- val result = ValDef (NoMods , name.result, TypeTree (futureSystemOps.promType[T ]), futureSystemOps.createProm[T ].tree)
122
- val execContext = ValDef (NoMods , name.execContext, TypeTree (), futureSystemOps.execContext.tree)
123
- val applyDefDef : DefDef = {
124
- val applyVParamss = List (List (ValDef (Modifiers (Flag .PARAM ), name.tr, TypeTree (defn.TryAnyType ), EmptyTree )))
125
- val applyBody = asyncBlock.onCompleteHandler
126
- DefDef (NoMods , name.apply, Nil , applyVParamss, TypeTree (definitions.UnitTpe ), applyBody)
127
- }
128
- val apply0DefDef : DefDef = {
129
- // We extend () => Unit so we can pass this class as the by-name argument to `Future.apply`.
130
- // See SI-1247 for the the optimization that avoids creatio
131
- val applyVParamss = List (List (ValDef (Modifiers (Flag .PARAM ), name.tr, TypeTree (defn.TryAnyType ), EmptyTree )))
132
- val applyBody = asyncBlock.onCompleteHandler
133
- DefDef (NoMods , name.apply, Nil , Nil , TypeTree (definitions.UnitTpe ), Apply (Ident (name.resume), Nil ))
134
- }
135
- List (utils.emptyConstructor, stateVar, result, execContext) ++ localVarTrees ++ List (resumeFunTree, applyDefDef, apply0DefDef)
136
- }
137
- val template = {
138
- Template (List (stateMachineType), emptyValDef, body)
139
- }
140
- ClassDef (NoMods , name.stateMachineT, Nil , template)
141
- }
142
-
143
- def selectStateMachine (selection : TermName ) = Select (Ident (name.stateMachine), selection)
144
-
145
- val code : c.Expr [futureSystem.Fut [T ]] = {
146
- val isSimple = asyncStates.size == 1
147
- val tree =
148
- if (isSimple)
149
- Block (Nil , futureSystemOps.spawn(body.tree)) // generate lean code for the simple case of `async { 1 + 1 }`
150
- else {
151
- Block (List [Tree ](
152
- stateMachine,
153
- ValDef (NoMods , name.stateMachine, stateMachineType, Apply (Select (New (Ident (name.stateMachineT)), nme.CONSTRUCTOR ), Nil )),
154
- futureSystemOps.spawn(Apply (selectStateMachine(name.apply), Nil ))
155
- ),
156
- futureSystemOps.promiseToFuture(c.Expr [futureSystem.Prom [T ]](selectStateMachine(name.result))).tree)
157
- }
158
- c.Expr [futureSystem.Fut [T ]](tree)
159
- }
160
-
161
- AsyncUtils .vprintln(s " async state machine transform expands to: \n ${code.tree}" )
162
- code
163
- }
77
+ val asyncMacro = AsyncMacro (c, futureSystem)
78
+
79
+ val code = asyncMacro.asyncTransform[T ](
80
+ body.tree.asInstanceOf [asyncMacro.global.Tree ],
81
+ execContext.tree.asInstanceOf [asyncMacro.global.Tree ],
82
+ fallbackEnabled)(implicitly[c.WeakTypeTag [T ]].asInstanceOf [asyncMacro.global.WeakTypeTag [T ]])
164
83
165
- def logDiagnostics (c : Context )(anfTree : c.Tree , states : Seq [String ]) {
166
- def location = try {
167
- c.macroApplication.pos.source.path
168
- } catch {
169
- case _ : UnsupportedOperationException =>
170
- c.macroApplication.pos.toString
171
- }
172
-
173
- AsyncUtils .vprintln(s " In file ' $location': " )
174
- AsyncUtils .vprintln(s " ${c.macroApplication}" )
175
- AsyncUtils .vprintln(s " ANF transform expands to: \n $anfTree" )
176
- states foreach (s => AsyncUtils .vprintln(s))
84
+ AsyncUtils .vprintln(s " async state machine transform expands to: \n ${code}" )
85
+ c.Expr [futureSystem.Fut [T ]](code.asInstanceOf [Tree ])
177
86
}
178
87
}
179
88
180
89
/** Internal class used by the `async` macro; should not be manually extended by client code */
181
90
abstract class StateMachine [Result , EC ] extends (scala.util.Try [Any ] => Unit ) with (() => Unit ) {
182
- def result$async : Result
91
+ def result : Result
183
92
184
- def execContext$async : EC
93
+ def execContext : EC
185
94
}
0 commit comments