diff --git a/compiler/gen/src/crane/convert.rs b/compiler/gen/src/crane/convert.rs index 5350de69b8..857cbdf8f9 100644 --- a/compiler/gen/src/crane/convert.rs +++ b/compiler/gen/src/crane/convert.rs @@ -10,7 +10,7 @@ pub fn type_from_layout(cfg: TargetFrontendConfig, layout: &Layout<'_>) -> Type use roc_mono::layout::Layout::*; match layout { - Pointer(_) | FunctionPointer(_, _) | Struct(_) => cfg.pointer_type(), + Pointer(_) | FunctionPointer(_, _) | Struct(_) | Tag(_) => cfg.pointer_type(), Builtin(builtin) => match builtin { Int64 => types::I64, Float64 => types::F64, diff --git a/compiler/gen/src/llvm/convert.rs b/compiler/gen/src/llvm/convert.rs index aa2e0b8143..a17c01933c 100644 --- a/compiler/gen/src/llvm/convert.rs +++ b/compiler/gen/src/llvm/convert.rs @@ -56,6 +56,9 @@ pub fn basic_type_from_layout<'ctx>( Struct(_fields) => { panic!("TODO layout_to_basic_type for Struct"); } + Tag(_fields) => { + panic!("TODO layout_to_basic_type for Tag"); + } Pointer(_layout) => { panic!("TODO layout_to_basic_type for Pointer"); } diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 53459bea27..d826a36254 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -10,6 +10,7 @@ use roc_types::subs::{Content, FlatType, Subs, Variable}; pub enum Layout<'a> { Builtin(Builtin<'a>), Struct(&'a [(Lowercase, Layout<'a>)]), + Tag(&'a [Layout<'a>]), Pointer(&'a Layout<'a>), /// A function. The types of its arguments, then the type of its return value. FunctionPointer(&'a [Layout<'a>], &'a Layout<'a>), @@ -92,6 +93,16 @@ impl<'a> Layout<'a> { sum } + Tag(fields) => { + // the symbol is a 64-bit value, so 8 bytes + let mut sum = 8; + + for field_layout in *fields { + sum += field_layout.stack_size(pointer_size); + } + + sum + } Pointer(_) | FunctionPointer(_, _) => pointer_size, } } @@ -264,7 +275,9 @@ fn layout_from_flat_type<'a>( 0 => { panic!("TODO gracefully handle trying to instantiate Never"); } - 1 => { + // We can only unwrap a wrapper if it never becomes part of a bigger union + // therefore, the ext_var must be the literal empty tag union + 1 if ext_var == Variable::EMPTY_TAG_UNION => { // This is a wrapper. Unwrap it! let (tag, args) = tags.into_iter().next().unwrap(); @@ -294,6 +307,7 @@ fn layout_from_flat_type<'a>( // But when one-tag tag unions are optimized away, we can also use an enum for // // [ Foo [ Unit ], Bar [ Unit ] ] + let arguments_have_size_0 = || { tags.iter().all(|(_, args)| { args.iter().all(|var| { @@ -327,7 +341,8 @@ fn layout_from_flat_type<'a>( Ok(Layout::Builtin(Builtin::Byte(tag_to_u8))) } } else { - panic!("TODO handle a tag union with mutliple tags: {:?}", tags); + // panic!("TODO handle a tag union with mutliple tags: {:?}", tags); + Ok(Layout::Tag(&[])) } } } @@ -350,12 +365,7 @@ fn ext_var_is_empty_tag_union(subs: &Subs, ext_var: Variable) -> bool { // the ext_var is empty let mut ext_fields = std::vec::Vec::new(); match roc_types::pretty_print::chase_ext_tag_union(subs, ext_var, &mut ext_fields) { - Ok(()) | Err((_, Content::FlexVar(_))) => { - if !ext_fields.is_empty() { - println!("ext_tags: {:?}", ext_fields); - } - ext_fields.is_empty() - } + Ok(()) | Err((_, Content::FlexVar(_))) => ext_fields.is_empty(), Err(content) => panic!("invalid content in ext_var: {:?}", content), } } @@ -364,13 +374,7 @@ fn ext_var_is_empty_record(subs: &Subs, ext_var: Variable) -> bool { // the ext_var is empty let mut ext_fields = MutMap::default(); match roc_types::pretty_print::chase_ext_record(subs, ext_var, &mut ext_fields) { - Ok(()) | Err((_, Content::FlexVar(_))) => { - if !ext_fields.is_empty() { - println!("ext_fields: {:?}", ext_fields); - } - - ext_fields.is_empty() - } + Ok(()) | Err((_, Content::FlexVar(_))) => ext_fields.is_empty(), Err((_, content)) => panic!("invalid content in ext_var: {:?}", content), } }