Skip to content

Commit f4d0eee

Browse files
committed
implemented lifting up nested hof-transformations.
1 parent 13d2804 commit f4d0eee

File tree

2 files changed

+48
-16
lines changed

2 files changed

+48
-16
lines changed

src/main/scala/gopher/goasync/GoAsync.scala

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,26 @@ object GoAsync
4242
def goImpl[T:c.WeakTypeTag](c:Context)(body:c.Expr[T])(ec:c.Expr[ExecutionContext]):c.Expr[Future[T]] =
4343
{
4444
import c.universe._
45+
val ttype = c.weakTypeOf[T]
4546
val nbody = GoAsync.transformAsyncBody[T](c)(body.tree)
4647
val r = if (containsDefer(c)(body)) {
4748
val defers = TermName(c.freshName)
4849
val promise = TermName(c.freshName)
4950
// asyn transform wantstyped tree on entry, so we must substitute 'defers' to untyped
5051
// values after it, no before.
5152
q"""
52-
gopher.goasync.GoAsync.transformDeferMacro[${c.weakTypeOf[T]}](
53+
gopher.goasync.GoAsync.transformDeferMacro[${ttype}](
5354
{implicit val ${defers} = new Defers[${c.weakTypeOf[T]}]()
5455
val ${promise} = Promise[${c.weakTypeOf[T]}]()
55-
scala.async.Async.async(${nbody})(${ec}).onComplete( x =>
56+
scala.async.Async.async[${ttype}](${nbody})(${ec}).onComplete( x =>
5657
${promise}.complete(${defers}.tryProcess(x))
5758
)(${ec})
5859
${promise}.future
5960
}
6061
)
6162
"""
6263
} else {
63-
q"scala.async.Async.async(${nbody})(${ec})"
64+
q"scala.async.Async.async[${ttype}](${nbody})(${ec})"
6465
}
6566
c.Expr[Future[T]](r)
6667
}
@@ -125,8 +126,26 @@ object GoAsync
125126
{
126127
import c.universe._
127128
var found = false
129+
var transformed = false
128130
val transformer = new Transformer {
129131
override def transform(tree:Tree):Tree =
132+
{
133+
134+
// if subtree was transformed, try to transform again origin tree,
135+
// because await can be lifted-up from previous level.
136+
def transformAgainIfNested(tree: Tree):Tree =
137+
{
138+
val prevTransformed = transformed
139+
transformed = false
140+
val nested = super.transform(tree)
141+
if (transformed) {
142+
transform(nested)
143+
}else{
144+
transformed = prevTransformed
145+
nested
146+
}
147+
}
148+
130149
tree match {
131150
case q"${f1}(${a}=>${b})(..$a2)" =>
132151
// TODO: cache in tree.
@@ -143,25 +162,33 @@ object GoAsync
143162
} else false
144163
} else true
145164
if (isTwoParams) {
165+
transformed = true
146166
transformInlineHofCall1(c)(f1,a,b,a2)
147167
} else {
148168
super.transform(tree)
149169
}
150170
}else{
151-
super.transform(tree)
171+
// TODO: think, may-be try to transform first b instead nested [?]
172+
transformAgainIfNested(tree)
152173
}
153174
case q"${f1}(${a}=>${b})" =>
154175
found = findAwait(c)(b)
155176
if (found) {
177+
transformed = true
156178
transformInlineHofCall1(c)(f1,a,b,List())
157179
} else {
158-
super.transform(tree)
180+
// TODO: think, may-be try to transform first b instead nested [?]
181+
transformAgainIfNested(tree)
159182
}
160183
case _ =>
161184
super.transform(tree)
162185
}
186+
}
187+
163188
}
164-
val r = transformer.transform(body)
189+
190+
var r = transformer.transform(body)
191+
165192
r
166193
}
167194

@@ -178,18 +205,13 @@ object GoAsync
178205
val anb = atPos(body.pos){
179206
val nnb = transformAsyncBody(c)(nb)
180207
val ec = c.inferImplicitValue(c.weakTypeOf[ExecutionContext])
181-
q"(${param})=>scala.async.Async.async[${btype}](${nnb})($ec)"
208+
q"(${param})=>scala.async.Async.async[$btype](${nnb})($ec)"
182209
}
183210
val ar = atPos(fun.pos) {
184211
val uar = if (implicitParams.isEmpty) {
185212
q"gopher.asyncApply1(${fun})(${anb})"
186213
} else {
187-
//we can't call macros here, becouse we don't know types of implicitParams
188-
//val a = param.tpe
189-
//val b = body.tpe
190-
//AsyncApply.impl1i(c)(fun)(anb,implicitParams)(a,b)
191214
q"gopher.goasync.AsyncApply.apply1i(${fun})(${anb},${implicitParams})"
192-
//q"gopher.asyncApply1i(${fun})(${anb})(..$implicitParams)"
193215
}
194216
// typecheck is necessory
195217
// 1. to prevent runnint analysis of async over internal awaits in anb as on
@@ -229,6 +251,7 @@ object GoAsync
229251
case q"(${a}=>${b})" =>
230252
// don't touch nested functions
231253
tree
254+
//super.transform(tree)
232255
case _ =>
233256
super.transform(tree)
234257
}
@@ -240,10 +263,6 @@ object GoAsync
240263
found
241264
}
242265

243-
private def numberOfParamLists(c:Context)(obj:c.Tree,m:c.Name):Int =
244-
{
245-
???
246-
}
247266

248267
}
249268

src/test/scala/gopher/hofasyn/HofAsyncSuite.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,19 @@ class HofAsyncSuite extends FunSuite
7474
assert(r2 === Some(1) )
7575
}
7676

77+
test("nested foreach") {
78+
val a:Option[Int] = Some(1)
79+
val b:Option[Int] = Some(3)
80+
val channel = gopherApi.makeChannel[Int](10)
81+
val fin = go {
82+
for (xa <- a;
83+
xb <- b) channel.write(xa+xb)
84+
}
85+
val fout = channel.aread
86+
val r = Await.result(fout, 5.second)
87+
assert(r == 4)
88+
}
89+
7790
lazy val gopherApi = CommonTestObjects.gopherApi
7891

7992
}

0 commit comments

Comments
 (0)