Unwrap layouts containing void layouts as newtypes

Addresses the attempt to do so in https://github.com/roc-lang/roc/pull/3465

Co-authored-by: Folkert <folkert@folkertdev.nl>
This commit is contained in:
Ayaz Hafiz 2022-09-19 16:47:27 -05:00
parent 639c1e5fa3
commit f41936d5e5
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
9 changed files with 228 additions and 14 deletions

View file

@ -1,4 +1,5 @@
use crate::ir::Parens;
use bitvec::vec::BitVec;
use bumpalo::collections::Vec;
use bumpalo::Bump;
use roc_builtins::bitcode::{FloatWidth, IntWidth};
@ -3279,6 +3280,11 @@ pub enum UnionVariant<'a> {
tag_name: TagOrClosure,
arguments: Vec<'a, Layout<'a>>,
},
NewtypeByVoid {
data_tag_name: TagOrClosure,
data_tag_id: TagIdIntType,
data_tag_arguments: Vec<'a, Layout<'a>>,
},
Wrapped(WrappedVariant<'a>),
}
@ -3525,6 +3531,8 @@ where
Vec::with_capacity_in(tags_list.len(), env.arena);
let mut has_any_arguments = false;
let mut inhabited_tag_ids = BitVec::<usize>::repeat(true, num_tags);
for &(tag_name, arguments) in tags_list.into_iter() {
let mut arg_layouts = Vec::with_capacity_in(arguments.len() + 1, env.arena);
@ -3536,6 +3544,10 @@ where
has_any_arguments = true;
arg_layouts.push(layout);
if layout == Layout::VOID {
inhabited_tag_ids.set(answer.len(), false);
}
}
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
// If we encounter an unbound type var (e.g. `Ok *`)
@ -3560,6 +3572,18 @@ where
answer.push((tag_name.clone().into(), arg_layouts.into_bump_slice()));
}
if inhabited_tag_ids.count_ones() == 1 {
let kept_tag_id = inhabited_tag_ids.first_one().unwrap();
let kept = answer.get(kept_tag_id).unwrap();
let variant = UnionVariant::NewtypeByVoid {
data_tag_name: kept.0.clone(),
data_tag_id: kept_tag_id as _,
data_tag_arguments: Vec::from_iter_in(kept.1.iter().copied(), env.arena),
};
return Cacheable(variant, cache_criteria);
}
match num_tags {
2 if !has_any_arguments => {
// type can be stored in a boolean
@ -3680,6 +3704,7 @@ where
let mut has_any_arguments = false;
let mut nullable = None;
let mut inhabited_tag_ids = BitVec::<usize>::repeat(true, num_tags);
// only recursive tag unions can be nullable
let is_recursive = opt_rec_var.is_some();
@ -3721,6 +3746,10 @@ where
} else {
arg_layouts.push(layout);
}
if layout == Layout::VOID {
inhabited_tag_ids.set(answer.len(), false);
}
}
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
// If we encounter an unbound type var (e.g. `Ok *`)
@ -3746,6 +3775,18 @@ where
answer.push((tag_name.into(), arg_layouts.into_bump_slice()));
}
if inhabited_tag_ids.count_ones() == 1 && !is_recursive {
let kept_tag_id = inhabited_tag_ids.first_one().unwrap();
let kept = answer.get(kept_tag_id).unwrap();
let variant = UnionVariant::NewtypeByVoid {
data_tag_name: kept.0.clone(),
data_tag_id: kept_tag_id as _,
data_tag_arguments: Vec::from_iter_in(kept.1.iter().copied(), env.arena),
};
return Cacheable(variant, cache_criteria);
}
match num_tags {
2 if !has_any_arguments => {
// type can be stored in a boolean
@ -3870,6 +3911,15 @@ where
answer1
}
NewtypeByVoid {
data_tag_arguments, ..
} => {
if data_tag_arguments.len() == 1 {
data_tag_arguments[0]
} else {
Layout::struct_no_name_order(data_tag_arguments.into_bump_slice())
}
}
Wrapped(variant) => {
use WrappedVariant::*;