Merge pull request #6356 from roc-lang/box-rc

Fix RC for unions with non-refcounted fields
This commit is contained in:
Brendan Hansknecht 2024-01-06 10:45:30 -08:00 committed by GitHub
commit 2466e2eb3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 10 deletions

View file

@ -1295,15 +1295,25 @@ fn build_rec_union_recursive_decrement<'a, 'ctx>(
_ => tag_id,
};
let block = env.context.append_basic_block(parent, "tag_id_decrement");
env.builder.position_at_end(block);
// if none of the fields are or contain anything refcounted, just move on
if fields_need_no_refcounting(layout_interner, field_layouts) {
// Still make sure to decrement the refcount of the union as a whole.
if let DecOrReuse::Dec = decrement_or_reuse {
let union_layout = LayoutRepr::Union(union_layout);
refcount_ptr.modify(call_mode, union_layout, env, layout_interner);
}
// this function returns void
builder.new_build_return(None);
cases.push((tag_id_int_type.const_int(tag_id as u64, false), block));
continue;
}
let block = env.context.append_basic_block(parent, "tag_id_decrement");
env.builder.position_at_end(block);
let fields_struct = LayoutRepr::struct_(field_layouts);
let wrapper_type = basic_type_from_layout(env, layout_interner, fields_struct);
@ -1370,12 +1380,9 @@ fn build_rec_union_recursive_decrement<'a, 'ctx>(
// and store them on the stack, then modify (and potentially free) the current cell, then
// actually inc/dec the fields.
match decrement_or_reuse {
DecOrReuse::Reuse => {}
DecOrReuse::Dec => {
let union_layout = LayoutRepr::Union(union_layout);
refcount_ptr.modify(call_mode, union_layout, env, layout_interner);
}
if let DecOrReuse::Dec = decrement_or_reuse {
let union_layout = LayoutRepr::Union(union_layout);
refcount_ptr.modify(call_mode, union_layout, env, layout_interner);
}
for (field, field_layout) in deferred_nonrec {

View file

@ -550,3 +550,29 @@ fn joinpoint_nullpointer() {
"#
));
}
#[test]
fn freeing_boxes() {
valgrind_test(indoc!(
r#"
(
# Without refcounted field
a : I32
a = 7
|> Box.box
|> Box.unbox
# With refcounted field
b : Str
b =
"Testing123. This will definitely be a large string that is on the heap."
|> Box.box
|> Box.unbox
a
|> Num.toStr
|> Str.concat b
)
"#
));
}