remove ClosureData type

This commit is contained in:
Folkert 2021-05-13 00:31:02 +02:00
parent e63eea7389
commit 051712c90b

View file

@ -300,282 +300,6 @@ impl<'a> LambdaSet<'a> {
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ClosureLayout<'a> {
/// the layout that this specific closure captures
/// uses a Vec instead of a MutMap because it's Hash
/// the vec is likely to be small, so linear search is fine
pub captured: &'a [(TagName, &'a [Layout<'a>])],
/// use with care; there is some stuff happening here re. unwrapping
/// one-element records that might cause issues
pub layout: &'a Layout<'a>,
}
impl<'a> ClosureLayout<'a> {
fn from_unit(arena: &'a Bump) -> Self {
let layout = Layout::PhantomEmptyStruct;
let layouts = arena.alloc(layout);
ClosureLayout {
captured: &[],
layout: layouts,
}
}
fn from_bool(arena: &'a Bump) -> Self {
let layout = Layout::Builtin(Builtin::Int1);
let layouts = arena.alloc(layout);
ClosureLayout {
captured: &[],
layout: layouts,
}
}
fn from_byte(arena: &'a Bump) -> Self {
let layout = Layout::Builtin(Builtin::Int8);
let layouts = arena.alloc(layout);
ClosureLayout {
captured: &[],
layout: layouts,
}
}
fn from_unwrapped(arena: &'a Bump, tag_name: TagName, layouts: &'a [Layout<'a>]) -> Self {
debug_assert!(!layouts.is_empty());
// DO NOT unwrap 1-element records here!
let layout = arena.alloc(Layout::Struct(layouts));
ClosureLayout {
captured: &*arena.alloc([(tag_name, &*arena.alloc([*layout]) as &[_])]),
layout,
}
}
fn from_tag_union(arena: &'a Bump, tags: &'a [(TagName, &'a [Layout<'a>])]) -> Self {
debug_assert!(tags.len() > 1);
// if the closed-over value is actually a layout, it should be wrapped in a 1-element record
debug_assert!(matches!(tags[0].0, TagName::Closure(_)));
let mut tag_arguments = Vec::with_capacity_in(tags.len(), arena);
for (_, tag_args) in tags.iter() {
tag_arguments.push(&tag_args[0..]);
}
ClosureLayout {
captured: tags,
layout: arena.alloc(Layout::Union(UnionLayout::NonRecursive(
tag_arguments.into_bump_slice(),
))),
}
}
pub fn get_wrapped(&self) -> crate::ir::Wrapped {
use crate::ir::Wrapped;
match self.layout {
Layout::Struct(fields) if fields.len() == 1 => Wrapped::SingleElementRecord,
Layout::Struct(_) => Wrapped::RecordOrSingleTagUnion,
Layout::Union(_) => Wrapped::MultiTagUnion,
_ => Wrapped::SingleElementRecord,
}
}
pub fn from_var(
arena: &'a Bump,
subs: &Subs,
closure_var: Variable,
) -> Result<Option<Self>, LayoutProblem> {
let mut tags = std::vec::Vec::new();
match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) {
Ok(()) | Err((_, Content::FlexVar(_))) if !tags.is_empty() => {
// otherwise, this is a closure with a payload
let variant = union_sorted_tags_help(arena, tags, None, subs);
use UnionVariant::*;
match variant {
Never | Unit | UnitWithArguments => {
// the closure layout is zero-sized, but there is something in it (e.g. `{}`)
let closure_layout = ClosureLayout::from_unit(arena);
Ok(Some(closure_layout))
}
BoolUnion { .. } => {
let closure_layout = ClosureLayout::from_bool(arena);
Ok(Some(closure_layout))
}
ByteUnion(_) => {
let closure_layout = ClosureLayout::from_byte(arena);
Ok(Some(closure_layout))
}
Unwrapped(tag_name, layouts) => {
let closure_layout = ClosureLayout::from_unwrapped(
arena,
tag_name,
layouts.into_bump_slice(),
);
Ok(Some(closure_layout))
}
Wrapped(variant) => {
use WrappedVariant::*;
match variant {
NonRecursive {
sorted_tag_layouts: tags,
} => {
let closure_layout =
ClosureLayout::from_tag_union(arena, tags.into_bump_slice());
Ok(Some(closure_layout))
}
_ => panic!("handle recursive layouts"),
}
}
}
}
Ok(()) | Err((_, Content::FlexVar(_))) => {
// a max closure size of 0 means this is a standart top-level function
Ok(None)
}
_ => panic!("called ClosureLayout.from_var on invalid input"),
}
}
pub fn extend_function_layout(
arena: &'a Bump,
argument_layouts: &'a [Layout<'a>],
closure_layout: Self,
ret_layout: &'a Layout<'a>,
) -> Layout<'a> {
let closure_data_layout = match closure_layout.layout {
Layout::Struct(fields) if fields.len() == 1 => &fields[0],
other => other,
};
// define the function pointer
let function_ptr_layout = {
let mut temp = Vec::from_iter_in(argument_layouts.iter().cloned(), arena);
temp.push(*closure_data_layout);
Layout::FunctionPointer(temp.into_bump_slice(), ret_layout)
};
function_ptr_layout
}
pub fn stack_size(&self, pointer_size: u32) -> u32 {
self.layout.stack_size(pointer_size)
}
pub fn contains_refcounted(&self) -> bool {
self.layout.contains_refcounted()
}
pub fn safe_to_memcpy(&self) -> bool {
self.layout.safe_to_memcpy()
}
pub fn as_named_layout(&self, symbol: Symbol) -> Layout<'a> {
let layouts = if self.captured.is_empty() {
match self.layout {
Layout::Struct(fields) if fields.len() == 1 => fields[0],
other => *other,
}
} else if let Some((_, tag_args)) = self
.captured
.iter()
.find(|(tn, _)| *tn == TagName::Closure(symbol))
{
if tag_args.len() == 1 {
tag_args[0]
} else {
Layout::Struct(tag_args)
}
} else {
unreachable!(
"invariant broken, TagName::Closure({:?}) is not in {:?}",
symbol, &self.captured
);
};
layouts
}
pub fn as_block_of_memory_layout(&self) -> Layout<'a> {
match self.layout {
Layout::Struct(fields) if fields.len() == 1 => fields[0],
other => *other,
}
}
pub fn internal_layout(&self) -> Layout<'a> {
*self.layout
}
pub fn build_closure_data(
&self,
original: Symbol,
symbols: &'a [Symbol],
) -> BuildClosureData<'a> {
use crate::ir::Expr;
match self.layout {
Layout::Struct(fields) if fields.len() == 1 => BuildClosureData::Alias(symbols[0]),
Layout::Struct(fields) => {
debug_assert!(fields.len() > 1);
debug_assert_eq!(fields.len(), symbols.len());
BuildClosureData::Struct(Expr::Struct(symbols))
}
Layout::Union(UnionLayout::NonRecursive(tags)) => {
// NOTE it's very important that this Union consists of Closure tags
// and is not an unpacked 1-element record
let tag_id = self
.captured
.iter()
.position(|(tn, _)| *tn == TagName::Closure(original))
.unwrap() as _;
BuildClosureData::Union {
tag_layout: Layout::Union(UnionLayout::NonRecursive(tags)),
tag_name: TagName::Closure(original),
tag_id,
union_size: tags.len() as u8,
}
}
Layout::PhantomEmptyStruct => {
debug_assert_eq!(symbols.len(), 1);
BuildClosureData::Struct(Expr::Struct(&[]))
}
_ => {
debug_assert_eq!(
symbols.len(),
1,
"symbols {:?} for layout {:?}",
&symbols,
&self.layout
);
BuildClosureData::Alias(symbols[0])
}
}
}
}
pub enum BuildClosureData<'a> {
Alias(Symbol),
Struct(crate::ir::Expr<'a>),
Union {
tag_layout: Layout<'a>,
tag_name: TagName,
tag_id: u8,
union_size: u8,
},
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)]
pub enum MemoryMode { pub enum MemoryMode {
Unique, Unique,