diff --git a/src/eval/StackValue.zig b/src/eval/StackValue.zig index 3a57856c12..ad6058791b 100644 --- a/src/eval/StackValue.zig +++ b/src/eval/StackValue.zig @@ -941,6 +941,33 @@ pub fn decref(self: StackValue, layout_cache: *LayoutStore, ops: *RocOps) void { slot.* = 0; return; }, + .tuple => { + if (self.ptr == null) return; + const tuple_data = layout_cache.getTupleData(self.layout.data.tuple.idx); + if (tuple_data.fields.count == 0) return; + + const element_layouts = layout_cache.tuple_fields.sliceRange(tuple_data.getFields()); + const base_ptr = @as([*]u8, @ptrCast(self.ptr.?)); + + var elem_index: usize = 0; + while (elem_index < element_layouts.len) : (elem_index += 1) { + const elem_info = element_layouts.get(elem_index); + const elem_layout = layout_cache.getLayout(elem_info.layout); + + const elem_offset = layout_cache.getTupleElementOffset(self.layout.data.tuple.idx, @intCast(elem_index)); + const elem_ptr = @as(*anyopaque, @ptrCast(base_ptr + elem_offset)); + + const elem_value = StackValue{ + .layout = elem_layout, + .ptr = elem_ptr, + .is_initialized = true, + }; + + elem_value.decref(layout_cache, ops); + } + + return; + }, else => {}, } diff --git a/src/eval/interpreter.zig b/src/eval/interpreter.zig index f6118301a4..4a3606b129 100644 --- a/src/eval/interpreter.zig +++ b/src/eval/interpreter.zig @@ -1495,11 +1495,10 @@ pub const Interpreter = struct { return error.NotImplemented; }, .e_match => |m| { - // Evaluate scrutinee once + // Evaluate scrutinee once and protect from stack corruption + // Use pushCopy to allocate a new stack location for the scrutinee header, + // preventing it from being corrupted by pattern match bindings const scrutinee_temp = try self.evalExprMinimal(m.cond, roc_ops, null); - - // Make a copy to protect from stack reuse during pattern matching - // pushCopy increments refcount, so we only decref the copy, not the temp const scrutinee = try self.pushCopy(scrutinee_temp, roc_ops); defer scrutinee.decref(&self.runtime_layout_store, roc_ops);