Skip to content

Commit d663d81

Browse files
committed
Fixed forward in closure and added tests
1 parent 84b763f commit d663d81

19 files changed

+267
-78
lines changed

src/back/CodeGen/Closure.hs

+10-6
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,13 @@ translateClosure closure typeVars table
4343
params = A.eparams closure
4444
body = A.body closure
4545
id = Meta.getMetaId . A.getMeta $ closure
46+
idAsync = id ++ "_async"
4647
funName = closureFunName id
48+
funNameAsync = closureFunName idAsync
4749
nameForwarding = forwardingClosureImplName $ (ID.Name . show) funName
4850
envName = closureEnvName id
4951
traceName = closureTraceName id
52+
traceNameAsync = closureTraceName idAsync
5053
boundVars = map (ID.qName . show . A.pname) params
5154
freeVars = map (first ID.qnlocal) $
5255
filter (ID.isLocalQName . fst) $
@@ -79,7 +82,7 @@ translateClosure closure typeVars table
7982
,returnStmnt bodyName resultType]
8083
)
8184
forwardingClosureImpl =
82-
Function (Static $ Typ "value_t") funName
85+
Function (Static $ Typ "value_t") funNameAsync
8386
[(Ptr (Ptr encoreCtxT), encoreCtxVar),
8487
(Ptr (Ptr ponyTypeT), encoreRuntimeType),
8588
(Typ "value_t", Var "_args[]"),
@@ -92,12 +95,13 @@ translateClosure closure typeVars table
9295
,dtraceClosureExit
9396
,returnStmnt forwardingBodyName unitType])
9497
in
95-
Concat $ [buildEnvironmentForward envName freeVars fTypeVars] ++
98+
Concat $ [buildEnvironmentForward envName freeVars fTypeVars] ++
99+
[tracefunDecl traceName envName freeVars fTypeVars extractEnvironment,
100+
normalClosureImpl] ++
96101
if null $ Util.filter A.isForward body
97-
then [tracefunDecl traceName envName freeVars fTypeVars extractEnvironment,
98-
normalClosureImpl]
99-
else [tracefunDecl traceName envName freeVars fTypeVars extractEnvironmentForward,
100-
forwardingClosureImpl]
102+
then []
103+
else [tracefunDecl traceNameAsync envName freeVars fTypeVars extractEnvironmentForward,
104+
forwardingClosureImpl]
101105
| otherwise =
102106
error
103107
"Tried to translate a closure from something that was not a closure"

src/back/CodeGen/Expr.hs

+47-32
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
221221
let string = head args
222222
rest = tail args
223223
unless (Ty.isStringType $ A.getType string) $
224-
error "Expr.hs: Print expects first argument to be a string literal"
224+
error $ "Expr.hs: Print expects first argument to be a string literal"
225225
targs <- mapM translate rest
226226
let argNames = map (AsExpr . fst) targs
227227
argDecls = map snd targs
@@ -1032,7 +1032,8 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
10321032
If futVar
10331033
(Seq [Statement forwardingCall])
10341034
(Seq [Statement oneWayMsg])] ++
1035-
result)
1035+
result
1036+
)
10361037
else do
10371038
(sendn, sendt) <- translate A.MessageSend{A.emeta
10381039
,A.target
@@ -1059,18 +1060,19 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
10591060
isAsyncForward <- gets Ctx.isAsyncForward
10601061
let ty = getRuntimeType chain
10611062
dtraceExit = getDtraceExit eCtx
1062-
result =
1063-
case eCtx of
1064-
Ctx.ClosureContext clos -> []
1065-
_ -> [dtraceExit, Return Skip]
1063+
result = case eCtx of
1064+
Ctx.ClosureContext clos -> []
1065+
_ -> [dtraceExit, Return Skip]
10661066
futureChain =
10671067
if Util.isForwardInExpr chain
1068-
then
1069-
Call futureChainActor
1070-
[AsExpr encoreCtxVar, AsExpr nfuture, ty, AsExpr nchain]
1071-
else
1072-
Call futureChainWithFut
1073-
[AsExpr encoreCtxVar, AsExpr nfuture, ty, AsExpr nchain, AsExpr futVar]
1068+
then Call futureChainActor
1069+
[AsExpr encoreCtxVar, AsExpr nfuture, ty, AsExpr nchain]
1070+
else Call futureChainWithFut
1071+
[AsExpr encoreCtxVar, AsExpr nfuture, ty, AsExpr nchain
1072+
,AsExpr futVar, AsExpr $ AsLval $ Nam "false"]
1073+
when (A.isVarAccess chain) $
1074+
unless (A.isIdClosure chain) $
1075+
error $ "Expr.hs: The closure that contains forward must be defined in chain."
10741076
if isAsyncForward
10751077
then do
10761078
return (unit, Seq $
@@ -1146,15 +1148,21 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
11461148
(nfuture,tfuture) <- translate future
11471149
(nchain, tchain) <- translate chain
11481150
result <- Ctx.genSym
1151+
isAsyncForward <- gets Ctx.isAsyncForward
11491152
let ty = getRuntimeType chain
11501153
return $ (Var result,
11511154
Seq $ [tfuture,
11521155
tchain,
1153-
(Assign (Decl (C.future, Var result))
1154-
(Call futureChainActor
1155-
[AsExpr encoreCtxVar, AsExpr nfuture, ty, AsExpr nchain]
1156-
))] ++
1157-
if (Util.isForwardInExpr chain) then [assignVar futNam (Nam result)]
1156+
if (Util.isForwardInExpr chain && isAsyncForward)
1157+
then Statement $
1158+
(Call futureChainWithFut
1159+
[AsExpr encoreCtxVar, AsExpr nfuture, ty, AsExpr nchain,
1160+
AsExpr ((Deref envName) `Dot` futNam), AsExpr $ AsLval $ Nam "true"])
1161+
else Assign (Decl (C.future, Var result))
1162+
(Call futureChainActor [AsExpr encoreCtxVar, AsExpr nfuture, ty, AsExpr nchain])
1163+
] ++
1164+
if (Util.isForwardInExpr chain && isAsyncForward)
1165+
then [assignVar futNam (Decl (C.future, Var result))]
11581166
else [])
11591167
where
11601168
metaId = Meta.getMetaId . A.getMeta $ chain
@@ -1163,31 +1171,38 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
11631171

11641172
translate clos@(A.Closure{A.eparams, A.body}) = do
11651173
tmp <- Ctx.genSym
1166-
fut <- Ctx.genNamedSym "fut"
1174+
futClos <- Ctx.genNamedSym "fut_closure"
11671175
globalFunctionNames <- gets Ctx.getGlobalFunctionNames
11681176
isAsyncForward <- gets Ctx.isAsyncForward
11691177
let bound = map (ID.qLocal . A.pname) eparams
11701178
freeVars = filter (ID.isLocalQName . fst) $
11711179
Util.freeVariables bound body
11721180
ty = runtimeType . A.getType $ body
1173-
futArg = if isAsyncForward
1174-
then futVar
1175-
else (Var fut)
11761181
fillEnv <- insertAllVars freeVars fTypeVars
11771182
return
11781183
(Var tmp,
1179-
Seq $
1180-
mkEnv envName : fillEnv ++
1181-
(if isAsyncForward || (not $ Util.isForwardInExpr body)
1182-
then []
1183-
else [Assign (Decl (future, Var fut))
1184-
(Call futureMkFn [AsExpr encoreCtxVar, ty])]) ++
1185-
(if Util.isForwardInExpr body
1186-
then [assignVar futNam futArg]
1187-
else []) ++
1188-
[Assign (Decl (closure, Var tmp))
1189-
(Call closureMkFn [encoreCtxName, funName, envName, traceName, nullName])])
1184+
Seq $
1185+
mkEnv envName : fillEnv ++
1186+
if isAsyncForward then
1187+
if forwardInBody
1188+
then [Assign (Decl (future, Var futClos))
1189+
(Call futureMkFn [AsExpr encoreCtxVar, ty])
1190+
,assignVar futNam (Var futClos)
1191+
,Assign (Decl (closure, Var tmp))
1192+
(Call closureMkFn [encoreCtxName, funNameAsync, envName, traceNameAsync, nullName])]
1193+
else [Assign (Decl (closure, Var tmp))
1194+
(Call closureMkFn [encoreCtxName, funName, envName, traceName, nullName])]
1195+
else
1196+
[Assign (Decl (closure, Var tmp))
1197+
(Call closureMkFn [encoreCtxName, funName, envName, traceName, nullName])])
11901198
where
1199+
forwardInBody = Util.isForwardInExpr body
1200+
metaIdAsync = metaId ++ "_async"
1201+
idClos = A.isIdClosure body
1202+
funNameAsync = if idClos || not forwardInBody then funName
1203+
else closureFunName metaIdAsync
1204+
traceNameAsync = if idClos || not forwardInBody then traceName
1205+
else closureTraceName metaIdAsync
11911206
metaId = Meta.getMetaId . A.getMeta $ clos
11921207
funName = closureFunName metaId
11931208
envName = closureEnvName metaId

src/back/CodeGen/MethodDecl.hs

+12-2
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,14 @@ translateGeneral mdecl@(A.Method {A.mbody, A.mlocals})
7373
,returnStatement mType bodyn])
7474
forwardingMethodImpl =
7575
Function void nameForwarding (args ++ [(future, futVar)])
76-
(Seq [dtraceMethodEntry thisVar mName argNames
76+
(Seq $[dtraceMethodEntry thisVar mName argNames
7777
,parametricMethodTypeVars
7878
,extractTypeVars
7979
,forwardingBody
8080
,dtraceMethodExit thisVar mName
81-
,Return Skip])
81+
,Statement $ returnForForwardingMethod returnType
82+
,Return Skip]
83+
)
8284
in
8385
code ++ return (Concat $ locals ++ closures ++
8486
[normalMethodImpl] ++
@@ -133,6 +135,14 @@ translateGeneral mdecl@(A.Method {A.mbody, A.mlocals})
133135
show oldName
134136
in A.setFunctionName newName fun
135137

138+
returnForForwardingMethod returnType =
139+
let fulfilArgs = [AsExpr encoreCtxVar
140+
,AsExpr $ futVar
141+
,asEncoreArgT returnType
142+
(Cast returnType forwardingBodyName)]
143+
in
144+
If futVar (Statement $ Call futureFulfil fulfilArgs) Skip
145+
136146
callMethodWithFuture m cdecl@(A.Class {A.cname}) code
137147
| A.isActive cdecl ||
138148
A.isShared cdecl =

src/ir/AST/AST.hs

+13-1
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ data Expr = Skip {emeta :: Meta Expr}
676676
val :: Expr}
677677
| Suspend {emeta :: Meta Expr}
678678
| FutureChain {emeta :: Meta Expr,
679-
future :: Expr,
679+
future :: Expr,
680680
chain :: Expr}
681681
| FieldAccess {emeta :: Meta Expr,
682682
target :: Expr,
@@ -765,14 +765,26 @@ isThisAccess :: Expr -> Bool
765765
isThisAccess VarAccess {qname = QName{qnlocal}} = qnlocal == Name "this"
766766
isThisAccess _ = False
767767

768+
isIdClos :: Expr -> Bool
769+
isIdClos VarAccess{qname = QName{qnlocal}} = qnlocal == Name "_id_fun_tmp"
770+
isIdClos _ = False
771+
768772
isClosure :: Expr -> Bool
769773
isClosure Closure {} = True
770774
isClosure _ = False
771775

776+
isIdClosure :: Expr -> Bool
777+
isIdClosure VarAccess{qname = QName{qnlocal}} = qnlocal == Name "_id_fun_tmp"
778+
isIdClosure _ = False
779+
772780
isForward :: Expr -> Bool
773781
isForward Forward {} = True
774782
isForward _ = False
775783

784+
isVarAccess :: Expr -> Bool
785+
isVarAccess VarAccess{} = True
786+
isVarAccess _ = False
787+
776788
isNull :: Expr -> Bool
777789
isNull Null{} = True
778790
isNull _ = False

src/runtime/future/future.c

+18-7
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ static void future_finalizer(future_t *fut);
102102
static inline void future_gc_send_value(pony_ctx_t *ctx, future_t *fut);
103103
static inline void future_gc_recv_value(pony_ctx_t *ctx, future_t *fut);
104104
static void future_chain(pony_ctx_t **ctx, future_t *fut, pony_type_t *type,
105-
closure_t *c, future_t *r);
105+
closure_t *c, future_t *r, bool withForward);
106106

107107
pony_type_t future_type = {
108108
.id = ID_FUTURE,
@@ -197,6 +197,12 @@ static inline encore_arg_t run_closure(pony_ctx_t **ctx, closure_t *c, encore_ar
197197
return closure_call(ctx, c, (value_t[1]) { value });
198198
}
199199

200+
static inline void run_closure_fwd(pony_ctx_t **ctx, closure_t *c, encore_arg_t value)
201+
{
202+
closure_call(ctx, c, (value_t[1]) { value });
203+
return;
204+
}
205+
200206
bool future_fulfilled(future_t *fut)
201207
{
202208
perr("future_fulfilled");
@@ -305,30 +311,35 @@ future_t *future_chain_actor(pony_ctx_t **ctx, future_t *fut, pony_type_t *type,
305311
{
306312
ENC_DTRACE3(FUTURE_CHAINING, (uintptr_t) *ctx, (uintptr_t) fut, (uintptr_t) type);
307313
future_t *r = future_mk(ctx, type);
308-
future_chain(ctx, fut, type, c, r);
314+
future_chain(ctx, fut, type, c, r, false);
309315
return r;
310316
}
311317

312318
void future_chain_with_fut(pony_ctx_t **ctx, future_t *fut, pony_type_t *type,
313-
closure_t *c, future_t *r)
319+
closure_t *c, future_t *r, bool keepFwd)
314320
{
315321
ENC_DTRACE3(FUTURE_CHAINING, (uintptr_t) *ctx, (uintptr_t) fut, (uintptr_t) type);
316322
(void)type;
317-
future_chain(ctx, fut, type, c, r);
323+
future_chain(ctx, fut, type, c, r, keepFwd);
318324
return;
319325
}
320326

321327
static void future_chain(pony_ctx_t **ctx, future_t *fut, pony_type_t *type,
322-
closure_t *c, future_t *r)
328+
closure_t *c, future_t *r, bool withForward)
323329
{
324330
(void)type;
325331
perr("future_chain_actor");
326332
BLOCK;
327333

328334
if (fut->fulfilled) {
329335
acquire_future_value(ctx, fut);
330-
value_t result = run_closure(ctx, c, fut->value);
331-
future_fulfil(ctx, r, result);
336+
if (withForward) {
337+
run_closure_fwd(ctx, c, fut->value);
338+
}
339+
else {
340+
value_t result = run_closure(ctx, c, fut->value);
341+
future_fulfil(ctx, r, result);
342+
}
332343
UNBLOCK;
333344
return;
334345
}

src/runtime/future/future.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ future_t *future_chain_actor(pony_ctx_t **ctx, future_t *fut, pony_type_t *type,
5555
closure_t *c);
5656

5757
void future_chain_with_fut(pony_ctx_t **ctx, future_t *fut, pony_type_t *type,
58-
closure_t *c, future_t *r);
58+
closure_t *c, future_t *r, bool keepFwd);
5959

6060
/** Registers a callback and returns void
6161
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
-- Error related to unknown _enc_type_t in method produce()
2+
-- read class Bar
3+
-- val v : int
4+
-- def init(v : int) : unit
5+
-- this.v = v
6+
-- end
7+
-- def getter() : int
8+
-- this.v
9+
-- end
10+
-- end
11+
active class Foo[t]
12+
stream produce(var n : int, v : t) : t
13+
while n>0 do
14+
yield(v)
15+
n -= 1
16+
end
17+
end
18+
end
19+
active class Main
20+
def main() : unit
21+
val foo = new Foo[int]
22+
val s = foo!produce(10, 42)
23+
end
24+
end
25+
26+
-- With the concrete type of stream, it works properly.
27+
{-
28+
read class Bar
29+
val v : int
30+
def init(v : int) : unit
31+
this.v = v
32+
end
33+
def getter() : int
34+
this.v
35+
end
36+
end
37+
active class Foo
38+
stream produce(var n : int) : Bar
39+
while n>0 do
40+
yield(new Bar(n))
41+
n -= 1
42+
end
43+
end
44+
end
45+
active class Main
46+
def printStream(var s : Stream[Bar]) : unit
47+
while not(eos(s)) do
48+
println("{}", (get(s)).getter())
49+
s = getNext(s)
50+
end
51+
end
52+
def main() : unit
53+
val foo = new Foo
54+
val s = foo!produce(10)
55+
this.printStream(s)
56+
end
57+
end
58+
-}

src/tests/encore/forward/forwardArgInClosure.enc

+5-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ end
66

77
active class Foo
88
def join(ff : Fut[Fut[int]]) : int
9-
(ff ~~> (fun (f : Fut[int]) : unit => forward(f)))
10-
0 -- Will be disregarded since it is used to bypass the typechecker.
9+
await(ff)
10+
get(ff ~~> fun (f : Fut[int]) : int
11+
await(f)
12+
forward(f)
13+
end)
1114
end
1215

1316
def duplicate() : Fut[int]

src/tests/encore/forward/forwardClosMaybe.enc

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ active class Crop
99
end
1010
active class Pepper
1111
def green(arg : Fut[Maybe[int]]) : Maybe[int]
12-
get(arg ~~> fun(x : Maybe[int]) : unit => forward((new Crop(x)) ! collect()))
13-
Nothing : Maybe[int]
12+
get(arg ~~> fun(x : Maybe[int]) : Maybe[int] => forward((new Crop(x)) ! collect()))
1413
end
1514
end
1615
active class Main

0 commit comments

Comments
 (0)