| author | |
| committer | |
| log | 24d197b037f93d57e5c9b7d1c84cdc9ec7313081 |
| tree | 55740974a4b81fdb768ca49366ddec51ecca7ba1 |
| parent | d80db3546cf49b8af434005de0e74509d07b4855 |
| signature |
4 files changed, 36 insertions(+), 3 deletions(-)
src/all_types.hpp+3| ... | @@ -2490,6 +2490,9 @@ struct ScopeExpr { | ... | @@ -2490,6 +2490,9 @@ struct ScopeExpr { |
| 2490 | size_t children_len; | 2490 | size_t children_len; |
| 2491 | 2491 | ||
| 2492 | MemoizedBool need_spill; | 2492 | MemoizedBool need_spill; |
| 2493 | // This is a hack. I apologize for this, I need this to work so that I | ||
| 2494 | // can make progress on other fronts. I'll pay off this tech debt eventually. | ||
| 2495 | bool spill_harder; | ||
| 2493 | }; | 2496 | }; |
| 2494 | 2497 | ||
| 2495 | // synchronized with code in define_builtin_compile_vars | 2498 | // synchronized with code in define_builtin_compile_vars |
src/analyze.cpp+4-1| ... | @@ -6104,11 +6104,14 @@ static void mark_suspension_point(Scope *scope) { | ... | @@ -6104,11 +6104,14 @@ static void mark_suspension_point(Scope *scope) { |
| 6104 | continue; | 6104 | continue; |
| 6105 | } | 6105 | } |
| 6106 | case ScopeIdExpr: { | 6106 | case ScopeIdExpr: { |
| 6107 | ScopeExpr *parent_expr_scope = reinterpret_cast<ScopeExpr *>(scope); | ||
| 6107 | if (!looking_for_exprs) { | 6108 | if (!looking_for_exprs) { |
| 6109 | if (parent_expr_scope->spill_harder) { | ||
| 6110 | parent_expr_scope->need_spill = MemoizedBoolTrue; | ||
| 6111 | } | ||
| 6108 | // Now we're only looking for a block, to see if it's in a loop (see the case ScopeIdBlock) | 6112 | // Now we're only looking for a block, to see if it's in a loop (see the case ScopeIdBlock) |
| 6109 | continue; | 6113 | continue; |
| 6110 | } | 6114 | } |
| 6111 | ScopeExpr *parent_expr_scope = reinterpret_cast<ScopeExpr *>(scope); | ||
| 6112 | if (child_expr_scope != nullptr) { | 6115 | if (child_expr_scope != nullptr) { |
| 6113 | for (size_t i = 0; parent_expr_scope->children_ptr[i] != child_expr_scope; i += 1) { | 6116 | for (size_t i = 0; parent_expr_scope->children_ptr[i] != child_expr_scope; i += 1) { |
| 6114 | assert(i < parent_expr_scope->children_len); | 6117 | assert(i < parent_expr_scope->children_len); |
src/ir.cpp+5-2| ... | @@ -8874,7 +8874,10 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo | ... | @@ -8874,7 +8874,10 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo |
| 8874 | AstNode *else_node = node->data.test_expr.else_node; | 8874 | AstNode *else_node = node->data.test_expr.else_node; |
| 8875 | bool var_is_ptr = node->data.test_expr.var_is_ptr; | 8875 | bool var_is_ptr = node->data.test_expr.var_is_ptr; |
| 8876 | 8876 | ||
| 8877 | IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); | 8877 | ScopeExpr *spill_scope = create_expr_scope(irb->codegen, expr_node, scope); |
| 8878 | spill_scope->spill_harder = true; | ||
| 8879 | |||
| 8880 | IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, &spill_scope->base, LValPtr, nullptr); | ||
| 8878 | if (maybe_val_ptr == irb->codegen->invalid_inst_src) | 8881 | if (maybe_val_ptr == irb->codegen->invalid_inst_src) |
| 8879 | return maybe_val_ptr; | 8882 | return maybe_val_ptr; |
| 8880 | 8883 | ||
| ... | @@ -8899,7 +8902,7 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo | ... | @@ -8899,7 +8902,7 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo |
| 8899 | 8902 | ||
| 8900 | ir_set_cursor_at_end_and_append_block(irb, then_block); | 8903 | ir_set_cursor_at_end_and_append_block(irb, then_block); |
| 8901 | 8904 | ||
| 8902 | Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); | 8905 | Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime); |
| 8903 | Scope *var_scope; | 8906 | Scope *var_scope; |
| 8904 | if (var_symbol) { | 8907 | if (var_symbol) { |
| 8905 | bool is_shadowable = false; | 8908 | bool is_shadowable = false; |
test/stage1/behavior/async_fn.zig+24| ... | @@ -1416,3 +1416,27 @@ test "async function call resolves target fn frame, runtime func" { | ... | @@ -1416,3 +1416,27 @@ test "async function call resolves target fn frame, runtime func" { |
| 1416 | resume S.global_frame; | 1416 | resume S.global_frame; |
| 1417 | expect(S.global_int == 10); | 1417 | expect(S.global_int == 10); |
| 1418 | } | 1418 | } |
| 1419 | |||
| 1420 | test "properly spill optional payload capture value" { | ||
| 1421 | const S = struct { | ||
| 1422 | var global_frame: anyframe = undefined; | ||
| 1423 | var global_int: usize = 2; | ||
| 1424 | |||
| 1425 | fn foo() void { | ||
| 1426 | var opt: ?usize = 1234; | ||
| 1427 | if (opt) |x| { | ||
| 1428 | bar(); | ||
| 1429 | global_int += x; | ||
| 1430 | } | ||
| 1431 | } | ||
| 1432 | |||
| 1433 | fn bar() void { | ||
| 1434 | global_frame = @frame(); | ||
| 1435 | suspend; | ||
| 1436 | global_int += 1; | ||
| 1437 | } | ||
| 1438 | }; | ||
| 1439 | _ = async S.foo(); | ||
| 1440 | resume S.global_frame; | ||
| 1441 | expect(S.global_int == 1237); | ||
| 1442 | } |