From 24d197b037f93d57e5c9b7d1c84cdc9ec7313081 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 8 Feb 2020 15:27:45 -0500 Subject: [PATCH] solve previous commit a better way --- src/all_types.hpp | 3 +++ src/analyze.cpp | 5 ++++- src/ir.cpp | 7 +++++-- test/stage1/behavior/async_fn.zig | 24 ++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 58a753c545..5eb569263c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2490,6 +2490,9 @@ struct ScopeExpr { size_t children_len; MemoizedBool need_spill; + // This is a hack. I apologize for this, I need this to work so that I + // can make progress on other fronts. I'll pay off this tech debt eventually. + bool spill_harder; }; // synchronized with code in define_builtin_compile_vars diff --git a/src/analyze.cpp b/src/analyze.cpp index 70352a2c18..7d99ca92da 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6104,11 +6104,14 @@ static void mark_suspension_point(Scope *scope) { continue; } case ScopeIdExpr: { + ScopeExpr *parent_expr_scope = reinterpret_cast(scope); if (!looking_for_exprs) { + if (parent_expr_scope->spill_harder) { + parent_expr_scope->need_spill = MemoizedBoolTrue; + } // Now we're only looking for a block, to see if it's in a loop (see the case ScopeIdBlock) continue; } - ScopeExpr *parent_expr_scope = reinterpret_cast(scope); if (child_expr_scope != nullptr) { for (size_t i = 0; parent_expr_scope->children_ptr[i] != child_expr_scope; i += 1) { assert(i < parent_expr_scope->children_len); diff --git a/src/ir.cpp b/src/ir.cpp index ef3426d111..2f0c52347c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8874,7 +8874,10 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo AstNode *else_node = node->data.test_expr.else_node; bool var_is_ptr = node->data.test_expr.var_is_ptr; - IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); + ScopeExpr *spill_scope = create_expr_scope(irb->codegen, expr_node, scope); + spill_scope->spill_harder = true; + + IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, &spill_scope->base, LValPtr, nullptr); if (maybe_val_ptr == irb->codegen->invalid_inst_src) return maybe_val_ptr; @@ -8899,7 +8902,7 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo ir_set_cursor_at_end_and_append_block(irb, then_block); - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime); Scope *var_scope; if (var_symbol) { bool is_shadowable = false; diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index 4bfc4f4ee4..fb17d5740c 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1416,3 +1416,27 @@ test "async function call resolves target fn frame, runtime func" { resume S.global_frame; expect(S.global_int == 10); } + +test "properly spill optional payload capture value" { + const S = struct { + var global_frame: anyframe = undefined; + var global_int: usize = 2; + + fn foo() void { + var opt: ?usize = 1234; + if (opt) |x| { + bar(); + global_int += x; + } + } + + fn bar() void { + global_frame = @frame(); + suspend; + global_int += 1; + } + }; + _ = async S.foo(); + resume S.global_frame; + expect(S.global_int == 1237); +}