don't unroll recursive layouts

This commit is contained in:
Folkert 2021-07-03 13:43:04 +02:00
parent ee67ee546a
commit 5250e930aa
2 changed files with 30 additions and 12 deletions

View file

@ -1508,6 +1508,18 @@ fn get_recursion_var(subs: &Subs, var: Variable) -> Option<Variable> {
} }
} }
fn is_recursive_tag_union(layout: &Layout) -> bool {
match layout {
Layout::Union(
UnionLayout::NullableUnwrapped { .. }
| UnionLayout::Recursive(_)
| UnionLayout::NullableWrapped { .. }
| UnionLayout::NonNullableUnwrapped { .. },
) => true,
_ => false,
}
}
pub fn union_sorted_tags_help<'a>( pub fn union_sorted_tags_help<'a>(
arena: &'a Bump, arena: &'a Bump,
mut tags_vec: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>, mut tags_vec: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
@ -1623,10 +1635,12 @@ pub fn union_sorted_tags_help<'a>(
for var in arguments { for var in arguments {
match Layout::from_var(&mut env, var) { match Layout::from_var(&mut env, var) {
Ok(layout) => { Ok(layout) => {
// Drop any zero-sized arguments like {} has_any_arguments = true;
if !layout.is_dropped_because_empty() {
has_any_arguments = true;
// make sure to not unroll recursive types!
if opt_rec_var.is_some() && is_recursive_tag_union(&layout) {
arg_layouts.push(Layout::RecursivePointer);
} else {
arg_layouts.push(layout); arg_layouts.push(layout);
} }
} }

View file

@ -32,20 +32,24 @@ struct CtorInfo<'a> {
} }
fn may_reuse(tag_layout: UnionLayout, tag_id: u8, other: &CtorInfo) -> bool { fn may_reuse(tag_layout: UnionLayout, tag_id: u8, other: &CtorInfo) -> bool {
// if tag_layout != other.layout { if tag_layout != other.layout {
// return false; return false;
// } }
// if the tag id is represented as NULL, there is no memory to re-use
match tag_layout { match tag_layout {
UnionLayout::NonRecursive(_) UnionLayout::NonRecursive(_)
| UnionLayout::Recursive(_) | UnionLayout::Recursive(_)
| UnionLayout::NonNullableUnwrapped(_) => true, | UnionLayout::NonNullableUnwrapped(_) => true,
UnionLayout::NullableWrapped { nullable_id, .. } => tag_id as i64 != nullable_id, UnionLayout::NullableWrapped { nullable_id, .. } => {
UnionLayout::NullableUnwrapped { // if the source tag id is represented as NULL, there is no memory to re-use
nullable_id, // if the current tag id is represented as NULL, then we don't need to re-use the
other_fields, // memory here and can use it somewhere else
} => (tag_id != 0) != nullable_id, other.id as i64 != nullable_id && tag_id as i64 != nullable_id
}
UnionLayout::NullableUnwrapped { nullable_id, .. } => {
// idem
(other.id != 0) != nullable_id && (tag_id != 0) != nullable_id
}
} }
} }