create NullableUnion in some cases

This commit is contained in:
Folkert 2021-01-15 01:02:34 +01:00
parent b47ccb20fd
commit 51cad15399
3 changed files with 41 additions and 2 deletions

View file

@ -1007,6 +1007,22 @@ fn path_to_expr_help<'a>(
Layout::Union(layouts) | Layout::RecursiveUnion(layouts) => { Layout::Union(layouts) | Layout::RecursiveUnion(layouts) => {
layouts[*tag_id as usize] layouts[*tag_id as usize]
} }
Layout::NullableUnion {
nullable_id,
nullable_layout,
foo: layouts,
..
} => {
use std::cmp::Ordering;
match (*tag_id as usize).cmp(&(*nullable_id as usize)) {
Ordering::Equal => {
&*env.arena.alloc([Layout::Builtin(nullable_layout.clone())])
}
Ordering::Less => layouts[*tag_id as usize],
Ordering::Greater => layouts[*tag_id as usize - 1],
}
}
Layout::Struct(layouts) => layouts, Layout::Struct(layouts) => layouts,
other => env.arena.alloc([other.clone()]), other => env.arena.alloc([other.clone()]),
}; };

View file

@ -827,6 +827,7 @@ impl Wrapped {
}, },
_ => Some(Wrapped::MultiTagUnion), _ => Some(Wrapped::MultiTagUnion),
}, },
Layout::NullableUnion { .. } => Some(Wrapped::MultiTagUnion),
_ => None, _ => None,
} }
} }

View file

@ -1019,7 +1019,21 @@ fn layout_from_flat_type<'a>(
let mut tags_vec: std::vec::Vec<_> = tags.into_iter().collect(); let mut tags_vec: std::vec::Vec<_> = tags.into_iter().collect();
tags_vec.sort(); tags_vec.sort();
for (_name, variables) in tags_vec { let mut nullable = None;
for (index, (_name, variables)) in tags_vec.iter().enumerate() {
if variables.is_empty() {
nullable = Some((index as i64, TAG_SIZE));
break;
}
}
for (index, (_name, variables)) in tags_vec.into_iter().enumerate() {
if matches!(nullable, Some((i, _)) if i == index as i64) {
// don't add the
continue;
}
let mut tag_layout = Vec::with_capacity_in(variables.len() + 1, arena); let mut tag_layout = Vec::with_capacity_in(variables.len() + 1, arena);
// store the discriminant // store the discriminant
@ -1047,7 +1061,15 @@ fn layout_from_flat_type<'a>(
tag_layouts.push(tag_layout.into_bump_slice()); tag_layouts.push(tag_layout.into_bump_slice());
} }
Ok(Layout::RecursiveUnion(tag_layouts.into_bump_slice())) if let Some((tag_id, tag_id_layout)) = nullable {
Ok(Layout::NullableUnion {
nullable_id: tag_id,
nullable_layout: tag_id_layout,
foo: tag_layouts.into_bump_slice(),
})
} else {
Ok(Layout::RecursiveUnion(tag_layouts.into_bump_slice()))
}
} }
EmptyTagUnion => { EmptyTagUnion => {
panic!("TODO make Layout for empty Tag Union"); panic!("TODO make Layout for empty Tag Union");