@@ -7,6 +7,9 @@ package scala.async
77import scala .language .experimental .macros
88import scala .reflect .macros .Context
99import scala .reflect .internal .annotations .compileTimeOnly
10+ import scala .tools .nsc .Global
11+ import language .reflectiveCalls
12+ import scala .concurrent .ExecutionContext
1013
1114object Async extends AsyncBase {
1215
@@ -15,18 +18,22 @@ object Async extends AsyncBase {
1518 lazy val futureSystem = ScalaConcurrentFutureSystem
1619 type FS = ScalaConcurrentFutureSystem .type
1720
18- def async [T ](body : T ) = macro asyncImpl[T ]
21+ def async [T ](body : T )( implicit execContext : ExecutionContext ) : Future [ T ] = macro asyncImpl[T ]
1922
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+ }
2128}
2229
2330object AsyncId extends AsyncBase {
2431 lazy val futureSystem = IdentityFutureSystem
2532 type FS = IdentityFutureSystem .type
2633
27- def async [T ](body : T ) = macro asyncImpl [T ]
34+ def async [T ](body : T ) = macro asyncIdImpl [T ]
2835
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 )
3037}
3138
3239/**
@@ -62,124 +69,26 @@ abstract class AsyncBase {
6269
6370 protected [async] def fallbackEnabled = false
6471
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 ]] = {
6675 import c .universe ._
6776
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 ]])
16483
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 ])
17786 }
17887}
17988
18089/** Internal class used by the `async` macro; should not be manually extended by client code */
18190abstract class StateMachine [Result , EC ] extends (scala.util.Try [Any ] => Unit ) with (() => Unit ) {
182- def result$async : Result
91+ def result : Result
18392
184- def execContext$async : EC
93+ def execContext : EC
18594}
0 commit comments