authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-29 13:37:58-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-01-29 13:37:58-05:00
log4fad16284ec30962689723c7eaca05a77df14673
tree9972dea0bfea56c23aacf3ffe7afa6f110a2f009
parent34706dad3ff22f73197fbf5e9cbf4628f698a74d
parent9a0a378e2f957f6acf5fbb37818d1cc0e3a38d33
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4320 from fengb/while-spills

Add async spills to while captured variables

2 files changed, 44 insertions(+), 4 deletions(-)

src/ir.cpp+8-4
......@@ -8111,6 +8111,7 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
81118111 } else {
81128112 payload_scope = subexpr_scope;
81138113 }
8114 ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, payload_scope);
81148115 IrInstSrc *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope,
81158116 LValPtr, nullptr);
81168117 if (err_val_ptr == irb->codegen->invalid_inst_src)
......@@ -8134,10 +8135,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
81348135
81358136 ir_set_cursor_at_end_and_append_block(irb, body_block);
81368137 if (var_symbol) {
8137 IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, payload_scope, symbol_node,
8138 IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, &spill_scope->base, symbol_node,
81388139 err_val_ptr, false, false);
81398140 IrInstSrc *var_ptr = node->data.while_expr.var_is_ptr ?
8140 ir_build_ref_src(irb, payload_scope, symbol_node, payload_ptr, true, false) : payload_ptr;
8141 ir_build_ref_src(irb, &spill_scope->base, symbol_node, payload_ptr, true, false) : payload_ptr;
81418142 ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_ptr);
81428143 }
81438144
......@@ -8152,6 +8153,7 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
81528153 loop_scope->incoming_values = &incoming_values;
81538154 loop_scope->lval = lval;
81548155 loop_scope->peer_parent = peer_parent;
8156 loop_scope->spill_scope = spill_scope;
81558157
81568158 // Note the body block of the loop is not the place that lval and result_loc are used -
81578159 // it's actually in break statements, handled similarly to return statements.
......@@ -8222,6 +8224,7 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
82228224 ZigVar *payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol,
82238225 true, false, false, is_comptime);
82248226 Scope *child_scope = payload_var->child_scope;
8227 ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, child_scope);
82258228 IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope,
82268229 LValPtr, nullptr);
82278230 if (maybe_val_ptr == irb->codegen->invalid_inst_src)
......@@ -8244,9 +8247,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
82448247 is_comptime);
82458248
82468249 ir_set_cursor_at_end_and_append_block(irb, body_block);
8247 IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false, false);
8250 IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, &spill_scope->base, symbol_node, maybe_val_ptr, false, false);
82488251 IrInstSrc *var_ptr = node->data.while_expr.var_is_ptr ?
8249 ir_build_ref_src(irb, child_scope, symbol_node, payload_ptr, true, false) : payload_ptr;
8252 ir_build_ref_src(irb, &spill_scope->base, symbol_node, payload_ptr, true, false) : payload_ptr;
82508253 ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_ptr);
82518254
82528255 ZigList<IrInstSrc *> incoming_values = {0};
......@@ -8260,6 +8263,7 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
82608263 loop_scope->incoming_values = &incoming_values;
82618264 loop_scope->lval = lval;
82628265 loop_scope->peer_parent = peer_parent;
8266 loop_scope->spill_scope = spill_scope;
82638267
82648268 // Note the body block of the loop is not the place that lval and result_loc are used -
82658269 // it's actually in break statements, handled similarly to return statements.
test/stage1/behavior/async_fn.zig+36
......@@ -1182,6 +1182,42 @@ test "suspend in for loop" {
11821182 S.doTheTest();
11831183}
11841184
1185test "suspend in while loop" {
1186 const S = struct {
1187 var global_frame: ?anyframe = null;
1188
1189 fn doTheTest() void {
1190 _ = async atest();
1191 while (global_frame) |f| resume f;
1192 }
1193
1194 fn atest() void {
1195 expect(optional(6) == 6);
1196 expect(errunion(6) == 6);
1197 }
1198 fn optional(stuff: ?u32) u32 {
1199 global_frame = @frame();
1200 defer global_frame = null;
1201 while (stuff) |val| {
1202 suspend;
1203 return val;
1204 }
1205 return 0;
1206 }
1207 fn errunion(stuff: anyerror!u32) u32 {
1208 global_frame = @frame();
1209 defer global_frame = null;
1210 while (stuff) |val| {
1211 suspend;
1212 return val;
1213 } else |err| {
1214 return 0;
1215 }
1216 }
1217 };
1218 S.doTheTest();
1219}
1220
11851221test "correctly spill when returning the error union result of another async fn" {
11861222 const S = struct {
11871223 var global_frame: anyframe = undefined;