Deal with recursive pointers that pass through non-recursive layouts

This commit is contained in:
Ayaz Hafiz 2022-04-08 12:21:53 -04:00
parent 92dfccedff
commit 02d5cd7885
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
6 changed files with 203 additions and 105 deletions

View file

@ -78,7 +78,7 @@ impl<'a> RawFunctionLayout<'a> {
let structure_content = env.subs.get_content_without_compacting(structure);
Self::new_help(env, structure, *structure_content)
}
Structure(flat_type) => Self::layout_from_flat_type(env, flat_type),
Structure(flat_type) => Self::layout_from_flat_type(env, var, flat_type),
RangedNumber(typ, _) => Self::from_var(env, typ),
// Ints
@ -152,6 +152,7 @@ impl<'a> RawFunctionLayout<'a> {
fn layout_from_flat_type(
env: &mut Env<'a, '_>,
var: Variable,
flat_type: FlatType,
) -> Result<Self, LayoutProblem> {
use roc_types::subs::FlatType::*;
@ -195,7 +196,7 @@ impl<'a> RawFunctionLayout<'a> {
Self::from_var(env, var)
}
_ => {
let layout = layout_from_flat_type(env, flat_type)?;
let layout = layout_from_flat_type(env, var, flat_type)?;
Ok(Self::ZeroArgumentThunk(layout))
}
}
@ -959,7 +960,7 @@ impl<'a> Layout<'a> {
let structure_content = env.subs.get_content_without_compacting(structure);
Self::new_help(env, structure, *structure_content)
}
Structure(flat_type) => layout_from_flat_type(env, flat_type),
Structure(flat_type) => layout_from_flat_type(env, var, flat_type),
Alias(symbol, _args, actual_var, _) => {
if let Some(int_width) = IntWidth::try_from_symbol(symbol) {
@ -1297,6 +1298,8 @@ impl<'a> LayoutCache<'a> {
target_info: self.target_info,
};
//if true {panic!()}
Layout::from_var(&mut env, var)
}
@ -1570,6 +1573,7 @@ impl<'a> Builtin<'a> {
fn layout_from_flat_type<'a>(
env: &mut Env<'a, '_>,
var: Variable,
flat_type: FlatType,
) -> Result<Layout<'a>, LayoutProblem> {
use roc_types::subs::FlatType::*;
@ -1731,7 +1735,7 @@ fn layout_from_flat_type<'a>(
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
Ok(layout_from_tag_union(arena, &tags, subs, env.target_info))
Ok(layout_from_tag_union(env, &tags))
}
FunctionOrTagUnion(tag_name, _, ext_var) => {
debug_assert!(
@ -1742,7 +1746,7 @@ fn layout_from_flat_type<'a>(
let union_tags = UnionTags::from_tag_name_index(tag_name);
let (tags, _) = union_tags.unsorted_tags_and_ext(subs, ext_var);
Ok(layout_from_tag_union(arena, &tags, subs, env.target_info))
Ok(layout_from_tag_union(env, &tags))
}
RecursiveTagUnion(rec_var, tags, ext_var) => {
let (tags, ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);
@ -1772,6 +1776,7 @@ fn layout_from_flat_type<'a>(
}
}
env.insert_seen(var);
env.insert_seen(rec_var);
for (index, &(_name, variables)) in tags_vec.iter().enumerate() {
if matches!(nullable, Some(i) if i == index as TagIdIntType) {
@ -1801,6 +1806,7 @@ fn layout_from_flat_type<'a>(
tag_layouts.push(tag_layout.into_bump_slice());
}
env.remove_seen(rec_var);
env.insert_seen(var);
let union_layout = if let Some(tag_id) = nullable {
match tag_layouts.into_bump_slice() {
@ -2071,23 +2077,14 @@ fn is_recursive_tag_union(layout: &Layout) -> bool {
}
fn union_sorted_tags_help_new<'a>(
arena: &'a Bump,
env: &mut Env<'a, '_>,
tags_list: &[(&'_ TagName, &[Variable])],
opt_rec_var: Option<Variable>,
subs: &Subs,
target_info: TargetInfo,
) -> UnionVariant<'a> {
// sort up front; make sure the ordering stays intact!
let mut tags_list = Vec::from_iter_in(tags_list.iter(), arena);
let mut tags_list = Vec::from_iter_in(tags_list.iter(), env.arena);
tags_list.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
let mut env = Env {
arena,
subs,
seen: Vec::new_in(arena),
target_info,
};
match tags_list.len() {
0 => {
// trying to instantiate a type with no values
@ -2098,18 +2095,19 @@ fn union_sorted_tags_help_new<'a>(
let tag_name = tag_name.clone();
// just one tag in the union (but with arguments) can be a struct
let mut layouts = Vec::with_capacity_in(tags_list.len(), arena);
let mut layouts = Vec::with_capacity_in(tags_list.len(), env.arena);
// special-case NUM_AT_NUM: if its argument is a FlexVar, make it Int
match tag_name {
TagName::Private(Symbol::NUM_AT_NUM) => {
let var = arguments[0];
layouts
.push(unwrap_num_tag(subs, var, target_info).expect("invalid num layout"));
layouts.push(
unwrap_num_tag(env.subs, var, env.target_info).expect("invalid num layout"),
);
}
_ => {
for &var in arguments {
match Layout::from_var(&mut env, var) {
match Layout::from_var(env, var) {
Ok(layout) => {
layouts.push(layout);
}
@ -2129,8 +2127,8 @@ fn union_sorted_tags_help_new<'a>(
}
layouts.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(target_info);
let size1 = layout1.alignment_bytes(env.target_info);
let size2 = layout2.alignment_bytes(env.target_info);
size2.cmp(&size1)
});
@ -2151,7 +2149,7 @@ fn union_sorted_tags_help_new<'a>(
}
num_tags => {
// default path
let mut answer = Vec::with_capacity_in(tags_list.len(), arena);
let mut answer = Vec::with_capacity_in(tags_list.len(), env.arena);
let mut has_any_arguments = false;
let mut nullable: Option<(TagIdIntType, TagName)> = None;
@ -2174,17 +2172,19 @@ fn union_sorted_tags_help_new<'a>(
continue;
}
let mut arg_layouts = Vec::with_capacity_in(arguments.len() + 1, arena);
let mut arg_layouts = Vec::with_capacity_in(arguments.len() + 1, env.arena);
for &var in arguments {
match Layout::from_var(&mut env, var) {
match Layout::from_var(env, var) {
Ok(layout) => {
has_any_arguments = true;
// make sure to not unroll recursive types!
let self_recursion = opt_rec_var.is_some()
&& subs.get_root_key_without_compacting(var)
== subs.get_root_key_without_compacting(opt_rec_var.unwrap())
&& env.subs.get_root_key_without_compacting(var)
== env
.subs
.get_root_key_without_compacting(opt_rec_var.unwrap())
&& is_recursive_tag_union(&layout);
if self_recursion {
@ -2207,8 +2207,8 @@ fn union_sorted_tags_help_new<'a>(
}
arg_layouts.sort_by(|layout1, layout2| {
let size1 = layout1.alignment_bytes(target_info);
let size2 = layout2.alignment_bytes(target_info);
let size1 = layout1.alignment_bytes(env.target_info);
let size2 = layout2.alignment_bytes(env.target_info);
size2.cmp(&size1)
});
@ -2229,7 +2229,7 @@ fn union_sorted_tags_help_new<'a>(
3..=MAX_ENUM_SIZE if !has_any_arguments => {
// type can be stored in a byte
// needs the sorted tag names to determine the tag_id
let mut tag_names = Vec::with_capacity_in(answer.len(), arena);
let mut tag_names = Vec::with_capacity_in(answer.len(), env.arena);
for (tag_name, _) in answer {
tag_names.push(tag_name);
@ -2488,27 +2488,15 @@ pub fn union_sorted_tags_help<'a>(
}
}
fn layout_from_newtype<'a>(
arena: &'a Bump,
tags: &UnsortedUnionTags,
subs: &Subs,
target_info: TargetInfo,
) -> Layout<'a> {
debug_assert!(tags.is_newtype_wrapper(subs));
fn layout_from_newtype<'a>(env: &mut Env<'a, '_>, tags: &UnsortedUnionTags) -> Layout<'a> {
debug_assert!(tags.is_newtype_wrapper(env.subs));
let (tag_name, var) = tags.get_newtype(subs);
let (tag_name, var) = tags.get_newtype(env.subs);
if tag_name == &TagName::Private(Symbol::NUM_AT_NUM) {
unwrap_num_tag(subs, var, target_info).expect("invalid Num argument")
unwrap_num_tag(env.subs, var, env.target_info).expect("invalid Num argument")
} else {
let mut env = Env {
arena,
subs,
seen: Vec::new_in(arena),
target_info,
};
match Layout::from_var(&mut env, var) {
match Layout::from_var(env, var) {
Ok(layout) => layout,
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
// If we encounter an unbound type var (e.g. `Ok *`)
@ -2525,16 +2513,11 @@ fn layout_from_newtype<'a>(
}
}
fn layout_from_tag_union<'a>(
arena: &'a Bump,
tags: &UnsortedUnionTags,
subs: &Subs,
target_info: TargetInfo,
) -> Layout<'a> {
fn layout_from_tag_union<'a>(env: &mut Env<'a, '_>, tags: &UnsortedUnionTags) -> Layout<'a> {
use UnionVariant::*;
if tags.is_newtype_wrapper(subs) {
return layout_from_newtype(arena, tags, subs, target_info);
if tags.is_newtype_wrapper(env.subs) {
return layout_from_newtype(env, tags);
}
let tags_vec = &tags.tags;
@ -2545,12 +2528,11 @@ fn layout_from_tag_union<'a>(
let &var = arguments.iter().next().unwrap();
unwrap_num_tag(subs, var, target_info).expect("invalid Num argument")
unwrap_num_tag(env.subs, var, env.target_info).expect("invalid Num argument")
}
_ => {
let opt_rec_var = None;
let variant =
union_sorted_tags_help_new(arena, tags_vec, opt_rec_var, subs, target_info);
let variant = union_sorted_tags_help_new(env, tags_vec, opt_rec_var);
match variant {
Never => Layout::VOID,
@ -2576,7 +2558,7 @@ fn layout_from_tag_union<'a>(
NonRecursive {
sorted_tag_layouts: tags,
} => {
let mut tag_layouts = Vec::with_capacity_in(tags.len(), arena);
let mut tag_layouts = Vec::with_capacity_in(tags.len(), env.arena);
tag_layouts.extend(tags.iter().map(|r| r.1));
Layout::Union(UnionLayout::NonRecursive(tag_layouts.into_bump_slice()))
@ -2585,7 +2567,7 @@ fn layout_from_tag_union<'a>(
Recursive {
sorted_tag_layouts: tags,
} => {
let mut tag_layouts = Vec::with_capacity_in(tags.len(), arena);
let mut tag_layouts = Vec::with_capacity_in(tags.len(), env.arena);
tag_layouts.extend(tags.iter().map(|r| r.1));
debug_assert!(tag_layouts.len() > 1);
@ -2597,7 +2579,7 @@ fn layout_from_tag_union<'a>(
nullable_name: _,
sorted_tag_layouts: tags,
} => {
let mut tag_layouts = Vec::with_capacity_in(tags.len(), arena);
let mut tag_layouts = Vec::with_capacity_in(tags.len(), env.arena);
tag_layouts.extend(tags.iter().map(|r| r.1));
Layout::Union(UnionLayout::NullableWrapped {