refactor union layout

This commit is contained in:
Folkert 2021-01-16 16:31:43 +01:00
parent c85fa58648
commit de666c575f
6 changed files with 266 additions and 193 deletions

View file

@ -9,8 +9,8 @@ use crate::llvm::build_str::{
};
use crate::llvm::compare::{build_eq, build_neq};
use crate::llvm::convert::{
basic_type_from_builtin, basic_type_from_layout, block_of_memory, block_of_memory_slice,
collection, get_fn_type, get_ptr_type, ptr_int,
basic_type_from_builtin, basic_type_from_layout, block_of_memory, collection, get_fn_type,
get_ptr_type, ptr_int,
};
use crate::llvm::refcounting::{
decrement_refcount_layout, increment_refcount_layout, refcount_is_one_comparison,
@ -42,7 +42,7 @@ use roc_module::ident::TagName;
use roc_module::low_level::LowLevel;
use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_mono::ir::{CallType, JoinPointId, Wrapped};
use roc_mono::layout::{Builtin, ClosureLayout, Layout, LayoutIds, MemoryMode};
use roc_mono::layout::{Builtin, ClosureLayout, Layout, LayoutIds, MemoryMode, UnionLayout};
use target_lexicon::CallingConvention;
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
@ -859,13 +859,13 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
Tag {
arguments,
tag_layout: Layout::Union(fields),
tag_layout: Layout::Union(UnionLayout::NonRecursive(fields)),
union_size,
tag_id,
tag_name,
..
} => {
let tag_layout = Layout::Union(fields);
let tag_layout = Layout::Union(UnionLayout::NonRecursive(fields));
debug_assert!(*union_size > 1);
let ptr_size = env.ptr_bytes;
@ -960,13 +960,13 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
}
Tag {
arguments,
tag_layout: Layout::RecursiveUnion(fields),
tag_layout: Layout::Union(UnionLayout::Recursive(fields)),
union_size,
tag_id,
tag_name,
..
} => {
let tag_layout = Layout::Union(fields);
let tag_layout = Layout::Union(UnionLayout::NonRecursive(fields));
debug_assert!(*union_size > 1);
let ptr_size = env.ptr_bytes;
@ -1042,17 +1042,17 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
Tag {
arguments,
tag_layout:
Layout::NullableUnion {
Layout::Union(UnionLayout::NullableWrapped {
nullable_id,
nullable_layout: _,
foo: fields,
},
other_tags: fields,
}),
union_size,
tag_id,
tag_name,
..
} => {
let tag_layout = Layout::Union(fields);
let tag_layout = Layout::Union(UnionLayout::NonRecursive(fields));
let tag_struct_type =
basic_type_from_layout(env.arena, env.context, &tag_layout, env.ptr_bytes);
if *tag_id == *nullable_id as u8 {
@ -1251,11 +1251,11 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
}
PointerValue(value) => {
match structure_layout {
Layout::NullableUnion {
Layout::Union(UnionLayout::NullableWrapped {
nullable_id,
foo: fields,
other_tags: fields,
..
} if *index == 0 => {
}) if *index == 0 => {
let ptr = value;
let is_null = env.builder.build_is_null(ptr, "is_null");

View file

@ -4,7 +4,7 @@ use inkwell::context::Context;
use inkwell::types::BasicTypeEnum::{self, *};
use inkwell::types::{ArrayType, BasicType, FunctionType, IntType, PointerType, StructType};
use inkwell::AddressSpace;
use roc_mono::layout::{Builtin, Layout};
use roc_mono::layout::{Builtin, Layout, UnionLayout};
/// TODO could this be added to Inkwell itself as a method on BasicValueEnum?
pub fn get_ptr_type<'ctx>(
@ -132,18 +132,17 @@ pub fn basic_type_from_layout<'ctx>(
.into(),
PhantomEmptyStruct => context.struct_type(&[], false).into(),
Struct(sorted_fields) => basic_type_from_record(arena, context, sorted_fields, ptr_bytes),
// Union(tags) if tags.len() == 1 => {
// let sorted_fields = tags.iter().next().unwrap();
//
// basic_type_from_record(arena, context, sorted_fields, ptr_bytes)
// }
RecursiveUnion(_) => block_of_memory(context, layout, ptr_bytes)
.ptr_type(AddressSpace::Generic)
.into(),
NullableUnion { .. } => block_of_memory(context, layout, ptr_bytes)
.ptr_type(AddressSpace::Generic)
.into(),
Union(_) => block_of_memory(context, layout, ptr_bytes),
Union(variant) => {
let block = block_of_memory(context, layout, ptr_bytes);
use UnionLayout::*;
match variant {
Recursive(_) | NullableWrapped { .. } => {
block.ptr_type(AddressSpace::Generic).into()
}
NonRecursive(_) => block,
}
}
RecursivePointer => {
// TODO make this dynamic
context
@ -183,20 +182,6 @@ pub fn basic_type_from_builtin<'ctx>(
}
}
pub fn block_of_memory_slice<'ctx>(
context: &'ctx Context,
layouts: &[Layout<'_>],
ptr_bytes: u32,
) -> BasicTypeEnum<'ctx> {
let mut union_size = 0;
for layout in layouts {
union_size += layout.stack_size(ptr_bytes as u32);
}
block_of_memory_help(context, union_size)
}
pub fn block_of_memory<'ctx>(
context: &'ctx Context,
layout: &Layout<'_>,

View file

@ -12,7 +12,7 @@ use inkwell::types::{AnyTypeEnum, BasicTypeEnum};
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue};
use inkwell::{AddressSpace, IntPredicate};
use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds, MemoryMode};
use roc_mono::layout::{Builtin, Layout, LayoutIds, MemoryMode, UnionLayout};
pub const REFCOUNT_MAX: usize = 0_usize;
@ -338,20 +338,28 @@ pub fn decrement_refcount_layout<'a, 'ctx, 'env>(
}
RecursivePointer => todo!("TODO implement decrement layout of recursive tag union"),
Union(tags) => {
Union(variant) => {
use UnionLayout::*;
match variant {
NonRecursive(tags) => {
build_dec_union(env, layout_ids, tags, value);
}
NullableUnion { foo: tags, .. } => {
NullableWrapped {
other_tags: tags, ..
} => {
debug_assert!(value.is_pointer_value());
build_dec_rec_union(env, layout_ids, tags, value.into_pointer_value(), true);
}
RecursiveUnion(tags) => {
Recursive(tags) => {
debug_assert!(value.is_pointer_value());
build_dec_rec_union(env, layout_ids, tags, value.into_pointer_value(), false);
}
}
}
FunctionPointer(_, _) | Pointer(_) => {}
}
@ -433,16 +441,28 @@ pub fn increment_refcount_layout<'a, 'ctx, 'env>(
increment_refcount_builtin(env, parent, layout_ids, value, layout, builtin)
}
NullableUnion { foo: tags, .. } => {
Union(variant) => {
use UnionLayout::*;
match variant {
NullableWrapped {
other_tags: tags, ..
} => {
debug_assert!(value.is_pointer_value());
build_inc_rec_union(env, layout_ids, tags, value.into_pointer_value(), true);
}
RecursiveUnion(tags) => {
Recursive(tags) => {
debug_assert!(value.is_pointer_value());
build_inc_rec_union(env, layout_ids, tags, value.into_pointer_value(), false);
}
NonRecursive(tags) => {
build_inc_union(env, layout_ids, tags, value);
}
}
}
Closure(_, closure_layout, _) => {
if closure_layout.contains_refcounted() {
let wrapper_struct = value.into_struct_value();
@ -1053,7 +1073,7 @@ pub fn build_dec_rec_union<'a, 'ctx, 'env>(
value: PointerValue<'ctx>,
is_nullable: bool,
) {
let layout = Layout::RecursiveUnion(fields);
let layout = Layout::Union(UnionLayout::Recursive(fields));
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
@ -1130,7 +1150,7 @@ pub fn build_dec_rec_union_help<'a, 'ctx, 'env>(
let parent = fn_val;
let layout = Layout::RecursiveUnion(tags);
let layout = Layout::Union(UnionLayout::Recursive(tags));
debug_assert!(arg_val.is_pointer_value());
let value_ptr = arg_val.into_pointer_value();
@ -1270,7 +1290,7 @@ pub fn build_dec_union<'a, 'ctx, 'env>(
fields: &'a [&'a [Layout<'a>]],
value: BasicValueEnum<'ctx>,
) {
let layout = Layout::Union(fields);
let layout = Layout::Union(UnionLayout::NonRecursive(fields));
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
@ -1435,7 +1455,7 @@ pub fn build_inc_rec_union<'a, 'ctx, 'env>(
value: PointerValue<'ctx>,
is_nullable: bool,
) {
let layout = Layout::RecursiveUnion(fields);
let layout = Layout::Union(UnionLayout::Recursive(fields));
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
@ -1531,7 +1551,7 @@ pub fn build_inc_rec_union_help<'a, 'ctx, 'env>(
let parent = fn_val;
let layout = Layout::RecursiveUnion(tags);
let layout = Layout::Union(UnionLayout::Recursive(tags));
debug_assert!(arg_val.is_pointer_value());
let value_ptr = arg_val.into_pointer_value();
@ -1663,7 +1683,7 @@ pub fn build_inc_union<'a, 'ctx, 'env>(
fields: &'a [&'a [Layout<'a>]],
value: BasicValueEnum<'ctx>,
) {
let layout = Layout::Union(fields);
let layout = Layout::Union(UnionLayout::NonRecursive(fields));
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
@ -1737,7 +1757,7 @@ pub fn build_inc_union_help<'a, 'ctx, 'env>(
let parent = fn_val;
let layout = Layout::RecursiveUnion(tags);
let layout = Layout::Union(UnionLayout::Recursive(tags));
let before_block = env.builder.get_insert_block().expect("to be in a function");
let wrapper_struct = arg_val.into_struct_value();
@ -1880,9 +1900,7 @@ pub fn refcount_offset<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layou
match layout {
Layout::Builtin(Builtin::List(_, _)) => env.ptr_bytes as u64,
Layout::Builtin(Builtin::Str) => env.ptr_bytes as u64,
Layout::RecursivePointer | Layout::Union(_) | Layout::RecursiveUnion(_) => {
env.ptr_bytes as u64
}
Layout::RecursivePointer | Layout::Union(_) => env.ptr_bytes as u64,
_ => (env.ptr_bytes as u64).max(value_bytes),
}
}

View file

@ -2,7 +2,7 @@ use crate::exhaustive::{Ctor, RenderAs, TagId, Union};
use crate::ir::{
DestructType, Env, Expr, JoinPointId, Literal, Param, Pattern, Procs, Stmt, Wrapped,
};
use crate::layout::{Builtin, Layout, LayoutCache};
use crate::layout::{Builtin, Layout, LayoutCache, UnionLayout};
use roc_collections::all::{MutMap, MutSet};
use roc_module::ident::TagName;
use roc_module::low_level::LowLevel;
@ -228,7 +228,9 @@ fn flatten<'a>(
tag_id,
tag_name,
layout,
} if union.alternatives.len() == 1 && !matches!(layout, Layout::NullableUnion { .. } ) => {
} if union.alternatives.len() == 1
&& !matches!(layout, Layout::Union(UnionLayout::NullableWrapped { .. })) =>
{
// TODO ^ do we need to check that guard.is_none() here?
let path = path_pattern.0;
@ -1005,25 +1007,29 @@ fn path_to_expr_help<'a>(
}
Some(wrapped) => {
let field_layouts = match &layout {
Layout::Union(layouts) | Layout::RecursiveUnion(layouts) => {
layouts[*tag_id as usize]
}
Layout::NullableUnion {
Layout::Union(variant) => {
use UnionLayout::*;
match variant {
NonRecursive(layouts) | Recursive(layouts) => layouts[*tag_id as usize],
NullableWrapped {
nullable_id,
nullable_layout,
foo: layouts,
other_tags: layouts,
..
} => {
use std::cmp::Ordering;
dbg!(nullable_id, tag_id);
match (*tag_id as usize).cmp(&(*nullable_id as usize)) {
Ordering::Equal => {
&*env.arena.alloc([Layout::Builtin(nullable_layout.clone())])
}
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,
other => env.arena.alloc([other.clone()]),

View file

@ -1,7 +1,8 @@
use self::InProgressProc::*;
use crate::exhaustive::{Ctor, Guard, RenderAs, TagId};
use crate::layout::{
Builtin, ClosureLayout, Layout, LayoutCache, LayoutProblem, WrappedVariant, TAG_SIZE,
Builtin, ClosureLayout, Layout, LayoutCache, LayoutProblem, UnionLayout, WrappedVariant,
TAG_SIZE,
};
use bumpalo::collections::Vec;
use bumpalo::Bump;
@ -820,7 +821,11 @@ impl Wrapped {
_ => Some(Wrapped::RecordOrSingleTagUnion),
},
Layout::Union(tags) | Layout::RecursiveUnion(tags) => match tags {
Layout::Union(variant) => {
use UnionLayout::*;
match variant {
Recursive(tags) | NonRecursive(tags) => match tags {
[] => todo!("how to handle empty tag unions?"),
[single] => match single.len() {
0 => Some(Wrapped::EmptyRecord),
@ -829,7 +834,9 @@ impl Wrapped {
},
_ => Some(Wrapped::MultiTagUnion),
},
Layout::NullableUnion { .. } => Some(Wrapped::MultiTagUnion),
NullableWrapped { .. } => Some(Wrapped::MultiTagUnion),
}
}
_ => None,
}
}
@ -2742,7 +2749,8 @@ pub fn with_hole<'a>(
layouts.push(arg_layouts);
}
let layout = Layout::RecursiveUnion(layouts.into_bump_slice());
let layout =
Layout::Union(UnionLayout::Recursive(layouts.into_bump_slice()));
let tag = Expr::Tag {
tag_layout: layout.clone(),
@ -2775,7 +2783,8 @@ pub fn with_hole<'a>(
layouts.push(arg_layouts);
}
let layout = Layout::Union(layouts.into_bump_slice());
let layout =
Layout::Union(UnionLayout::NonRecursive(layouts.into_bump_slice()));
let tag = Expr::Tag {
tag_layout: layout.clone(),
@ -2812,11 +2821,11 @@ pub fn with_hole<'a>(
layouts.push(arg_layouts);
}
let layout = Layout::NullableUnion {
let layout = Layout::Union(UnionLayout::NullableWrapped {
nullable_id,
nullable_layout: TAG_SIZE,
foo: layouts.into_bump_slice(),
};
other_tags: layouts.into_bump_slice(),
});
let tag = Expr::Tag {
tag_layout: layout.clone(),
@ -5945,6 +5954,8 @@ fn from_can_pattern_help<'a>(
}
Wrapped(variant) => {
let (tag_id, argument_layouts) = variant.tag_name_to_id(tag_name);
let number_of_tags = variant.number_of_tags();
let mut ctors = std::vec::Vec::with_capacity(number_of_tags);
let arguments = {
let mut temp = arguments.clone();
@ -5971,7 +5982,6 @@ fn from_can_pattern_help<'a>(
} => {
debug_assert!(tags.len() > 1);
let mut ctors = std::vec::Vec::with_capacity(tags.len());
for (i, (tag_name, args)) in tags.iter().enumerate() {
ctors.push(Ctor {
tag_id: TagId(i as u8),
@ -6013,7 +6023,8 @@ fn from_can_pattern_help<'a>(
temp
};
let layout = Layout::Union(layouts.into_bump_slice());
let layout =
Layout::Union(UnionLayout::NonRecursive(layouts.into_bump_slice()));
Pattern::AppliedTag {
tag_name: tag_name.clone(),
@ -6029,7 +6040,6 @@ fn from_can_pattern_help<'a>(
} => {
debug_assert!(tags.len() > 1);
let mut ctors = std::vec::Vec::with_capacity(tags.len());
for (i, (tag_name, args)) in tags.iter().enumerate() {
ctors.push(Ctor {
tag_id: TagId(i as u8),
@ -6071,7 +6081,8 @@ fn from_can_pattern_help<'a>(
temp
};
let layout = Layout::RecursiveUnion(layouts.into_bump_slice());
let layout =
Layout::Union(UnionLayout::Recursive(layouts.into_bump_slice()));
Pattern::AppliedTag {
tag_name: tag_name.clone(),
@ -6089,8 +6100,6 @@ fn from_can_pattern_help<'a>(
} => {
debug_assert!(!tags.is_empty());
let mut ctors = std::vec::Vec::with_capacity(tags.len());
let mut i = 0;
for (tag_name, args) in tags.iter() {
if i == nullable_id as usize {
@ -6158,11 +6167,11 @@ fn from_can_pattern_help<'a>(
temp
};
let layout = Layout::NullableUnion {
let layout = Layout::Union(UnionLayout::NullableWrapped {
nullable_id,
nullable_layout: TAG_SIZE,
foo: layouts.into_bump_slice(),
};
other_tags: layouts.into_bump_slice(),
});
Pattern::AppliedTag {
tag_name: tag_name.clone(),

View file

@ -29,13 +29,7 @@ pub enum Layout<'a> {
/// this is important for closures that capture zero-sized values
PhantomEmptyStruct,
Struct(&'a [Layout<'a>]),
Union(&'a [&'a [Layout<'a>]]),
RecursiveUnion(&'a [&'a [Layout<'a>]]),
NullableUnion {
nullable_id: i64,
nullable_layout: Builtin<'a>,
foo: &'a [&'a [Layout<'a>]],
},
Union(UnionLayout<'a>),
RecursivePointer,
/// A function. The types of its arguments, then the type of its return value.
FunctionPointer(&'a [Layout<'a>], &'a Layout<'a>),
@ -43,6 +37,18 @@ pub enum Layout<'a> {
Pointer(&'a Layout<'a>),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum UnionLayout<'a> {
NonRecursive(&'a [&'a [Layout<'a>]]),
Recursive(&'a [&'a [Layout<'a>]]),
NullableWrapped {
nullable_id: i64,
nullable_layout: Builtin<'a>,
other_tags: &'a [&'a [Layout<'a>]],
},
// NullableUnwrapped,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ClosureLayout<'a> {
/// the layout that this specific closure captures
@ -104,7 +110,9 @@ impl<'a> ClosureLayout<'a> {
ClosureLayout {
captured: tags,
layout: arena.alloc(Layout::Union(tag_arguments.into_bump_slice())),
layout: arena.alloc(Layout::Union(UnionLayout::NonRecursive(
tag_arguments.into_bump_slice(),
))),
}
}
@ -273,7 +281,7 @@ impl<'a> ClosureLayout<'a> {
Ok(Expr::Struct(symbols))
}
Layout::Union(tags) => {
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
@ -284,7 +292,7 @@ impl<'a> ClosureLayout<'a> {
.unwrap() as _;
let expr = Expr::Tag {
tag_layout: Layout::Union(tags),
tag_layout: Layout::Union(UnionLayout::NonRecursive(tags)),
tag_name: TagName::Closure(original),
tag_id,
union_size: tags.len() as u8,
@ -459,17 +467,23 @@ impl<'a> Layout<'a> {
Struct(fields) => fields
.iter()
.all(|field_layout| field_layout.safe_to_memcpy()),
Union(tags) => tags
Union(variant) => {
use UnionLayout::*;
match variant {
NonRecursive(tags) => tags
.iter()
.all(|tag_layout| tag_layout.iter().all(|field| field.safe_to_memcpy())),
RecursiveUnion(_) => {
Recursive(_) => {
// a recursive union will always contain a pointer, and is thus not safe to memcpy
false
}
NullableUnion { .. } => {
NullableWrapped { .. } => {
// a nullable union will always contain a pointer, and is thus not safe to memcpy
false
}
}
}
FunctionPointer(_, _) => {
// Function pointers are immutable and can always be safely copied
true
@ -513,7 +527,11 @@ impl<'a> Layout<'a> {
sum
}
Union(fields) => fields
Union(variant) => {
use UnionLayout::*;
match variant {
NonRecursive(fields) => fields
.iter()
.map(|tag_layout| {
tag_layout
@ -523,7 +541,7 @@ impl<'a> Layout<'a> {
})
.max()
.unwrap_or_default(),
RecursiveUnion(fields) => fields
Recursive(fields) => fields
.iter()
.map(|tag_layout| {
tag_layout
@ -533,7 +551,9 @@ impl<'a> Layout<'a> {
})
.max()
.unwrap_or_default(),
NullableUnion { foo: fields, .. } => fields
NullableWrapped {
other_tags: fields, ..
} => fields
.iter()
.map(|tag_layout| {
tag_layout
@ -543,6 +563,8 @@ impl<'a> Layout<'a> {
})
.max()
.unwrap_or_default(),
}
}
Closure(_, closure_layout, _) => pointer_size + closure_layout.stack_size(pointer_size),
FunctionPointer(_, _) => pointer_size,
RecursivePointer => pointer_size,
@ -557,20 +579,30 @@ impl<'a> Layout<'a> {
.map(|x| x.alignment_bytes(pointer_size))
.max()
.unwrap_or(0),
Layout::Union(tags) => tags
Layout::Union(variant) => {
use UnionLayout::*;
match variant {
NonRecursive(tags) => tags
.iter()
.map(|x| x.iter())
.flatten()
.map(|x| x.alignment_bytes(pointer_size))
.max()
.unwrap_or(0),
Layout::RecursiveUnion(tags) | Layout::NullableUnion { foo: tags, .. } => tags
Recursive(tags)
| NullableWrapped {
other_tags: tags, ..
} => tags
.iter()
.map(|x| x.iter())
.flatten()
.map(|x| x.alignment_bytes(pointer_size))
.max()
.unwrap_or(pointer_size),
}
}
Layout::Builtin(builtin) => builtin.alignment_bytes(pointer_size),
Layout::PhantomEmptyStruct => 0,
Layout::RecursivePointer => pointer_size,
@ -583,7 +615,22 @@ impl<'a> Layout<'a> {
}
pub fn is_refcounted(&self) -> bool {
matches!(self, Layout::Builtin(Builtin::List(MemoryMode::Refcounted, _)) | Layout::Builtin(Builtin::Str) | Layout::RecursiveUnion(_) | Layout::RecursivePointer | Layout::NullableUnion { .. })
use self::Builtin::*;
use Layout::*;
match self {
Union(variant) => {
use UnionLayout::*;
matches!(variant, Recursive(_)| NullableWrapped { .. } )
}
RecursivePointer => true,
Builtin(List(MemoryMode::Refcounted, _)) | Builtin(Str) => true,
_ => false,
}
}
/// Even if a value (say, a record) is not itself reference counted,
@ -596,13 +643,19 @@ impl<'a> Layout<'a> {
Builtin(builtin) => builtin.is_refcounted(),
PhantomEmptyStruct => false,
Struct(fields) => fields.iter().any(|f| f.contains_refcounted()),
Union(fields) => fields
Union(variant) => {
use UnionLayout::*;
match variant {
NonRecursive(fields) => fields
.iter()
.map(|ls| ls.iter())
.flatten()
.any(|f| f.contains_refcounted()),
RecursiveUnion(_) => true,
NullableUnion { .. } => true,
Recursive(_) => true,
NullableWrapped { .. } => true,
}
}
Closure(_, closure_layout, _) => closure_layout.contains_refcounted(),
FunctionPointer(_, _) | RecursivePointer | Pointer(_) => false,
}
@ -1067,15 +1120,17 @@ fn layout_from_flat_type<'a>(
tag_layouts.push(tag_layout.into_bump_slice());
}
if let Some((tag_id, tag_id_layout)) = nullable {
Ok(Layout::NullableUnion {
let union_layout = if let Some((tag_id, tag_id_layout)) = nullable {
UnionLayout::NullableWrapped {
nullable_id: tag_id,
nullable_layout: tag_id_layout,
foo: tag_layouts.into_bump_slice(),
})
} else {
Ok(Layout::RecursiveUnion(tag_layouts.into_bump_slice()))
other_tags: tag_layouts.into_bump_slice(),
}
} else {
UnionLayout::Recursive(tag_layouts.into_bump_slice())
};
Ok(Layout::Union(union_layout))
}
EmptyTagUnion => {
panic!("TODO make Layout for empty Tag Union");
@ -1500,7 +1555,7 @@ pub fn layout_from_tag_union<'a>(
let variant = union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs);
match variant {
Never => Layout::Union(&[]),
Never => Layout::Union(UnionLayout::NonRecursive(&[])),
Unit | UnitWithArguments => Layout::Struct(&[]),
BoolUnion { .. } => Layout::Builtin(Builtin::Int1),
ByteUnion(_) => Layout::Builtin(Builtin::Int8),
@ -1521,7 +1576,7 @@ pub fn layout_from_tag_union<'a>(
let mut tag_layouts = Vec::with_capacity_in(tags.len(), arena);
tag_layouts.extend(tags.iter().map(|r| r.1));
Layout::Union(tag_layouts.into_bump_slice())
Layout::Union(UnionLayout::NonRecursive(tag_layouts.into_bump_slice()))
}
Recursive {
@ -1530,7 +1585,7 @@ pub fn layout_from_tag_union<'a>(
let mut tag_layouts = Vec::with_capacity_in(tags.len(), arena);
tag_layouts.extend(tags.iter().map(|r| r.1));
Layout::RecursiveUnion(tag_layouts.into_bump_slice())
Layout::Union(UnionLayout::Recursive(tag_layouts.into_bump_slice()))
}
NullableWrapped {
@ -1541,11 +1596,11 @@ pub fn layout_from_tag_union<'a>(
let mut tag_layouts = Vec::with_capacity_in(tags.len(), arena);
tag_layouts.extend(tags.iter().map(|r| r.1));
Layout::NullableUnion {
Layout::Union(UnionLayout::NullableWrapped {
nullable_id,
nullable_layout: TAG_SIZE,
foo: tag_layouts.into_bump_slice(),
}
other_tags: tag_layouts.into_bump_slice(),
})
}
NullableUnwrapped { .. } => todo!(),