diff --git a/compiler/alias_analysis/src/lib.rs b/compiler/alias_analysis/src/lib.rs index d492f3a12a..572a438847 100644 --- a/compiler/alias_analysis/src/lib.rs +++ b/compiler/alias_analysis/src/lib.rs @@ -279,7 +279,8 @@ fn build_entry_point( let block = builder.add_block(); // to the modelling language, the arguments appear out of thin air - let argument_type = build_tuple_type(&mut builder, layout.arguments)?; + let argument_type = + build_tuple_type(&mut builder, layout.arguments, &WhenRecursive::Unreachable)?; // does not make any assumptions about the input // let argument = builder.add_unknown_with(block, &[], argument_type)?; @@ -308,7 +309,11 @@ fn build_entry_point( let block = builder.add_block(); - let type_id = layout_spec(&mut builder, &Layout::struct_no_name_order(layouts))?; + let type_id = layout_spec( + &mut builder, + &Layout::struct_no_name_order(layouts), + &WhenRecursive::Unreachable, + )?; let argument = builder.add_unknown_with(block, &[], type_id)?; @@ -352,8 +357,9 @@ fn proc_spec<'a>(proc: &Proc<'a>) -> Result<(FuncDef, MutSet>)> let arg_type_id = layout_spec( &mut builder, &Layout::struct_no_name_order(&argument_layouts), + &WhenRecursive::Unreachable, )?; - let ret_type_id = layout_spec(&mut builder, &proc.ret_layout)?; + let ret_type_id = layout_spec(&mut builder, &proc.ret_layout, &WhenRecursive::Unreachable)?; let spec = builder.build(arg_type_id, ret_type_id, root)?; @@ -457,10 +463,14 @@ fn stmt_spec<'a>( let mut type_ids = Vec::new(); for p in parameters.iter() { - type_ids.push(layout_spec(builder, &p.layout)?); + type_ids.push(layout_spec( + builder, + &p.layout, + &WhenRecursive::Unreachable, + )?); } - let ret_type_id = layout_spec(builder, layout)?; + let ret_type_id = layout_spec(builder, layout, &WhenRecursive::Unreachable)?; let jp_arg_type_id = builder.add_tuple_type(&type_ids)?; @@ -500,14 +510,14 @@ fn stmt_spec<'a>( builder.add_sub_block(block, BlockExpr(cont_block, cont_value_id)) } Jump(id, symbols) => { - let ret_type_id = layout_spec(builder, layout)?; + let ret_type_id = layout_spec(builder, layout, &WhenRecursive::Unreachable)?; let argument = build_tuple_value(builder, env, block, symbols)?; let jpid = env.join_points[id]; builder.add_jump(block, jpid, argument, ret_type_id) } RuntimeError(_) => { - let type_id = layout_spec(builder, layout)?; + let type_id = layout_spec(builder, layout, &WhenRecursive::Unreachable)?; builder.add_terminate(block, type_id) } @@ -556,11 +566,15 @@ fn build_recursive_tuple_type( builder.add_tuple_type(&field_types) } -fn build_tuple_type(builder: &mut impl TypeContext, layouts: &[Layout]) -> Result { +fn build_tuple_type( + builder: &mut impl TypeContext, + layouts: &[Layout], + when_recursive: &WhenRecursive, +) -> Result { let mut field_types = Vec::new(); for field in layouts.iter() { - field_types.push(layout_spec(builder, field)?); + field_types.push(layout_spec(builder, field, when_recursive)?); } builder.add_tuple_type(&field_types) @@ -691,7 +705,7 @@ fn call_spec( .map(|symbol| env.symbols[symbol]) .collect(); - let result_type = layout_spec(builder, ret_layout)?; + let result_type = layout_spec(builder, ret_layout, &WhenRecursive::Unreachable)?; builder.add_unknown_with(block, &arguments, result_type) } @@ -761,7 +775,8 @@ fn call_spec( }; let state_layout = argument_layouts[0]; - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = state; add_loop(builder, block, state_type, init_state, loop_body) @@ -782,7 +797,8 @@ fn call_spec( }; let state_layout = argument_layouts[0]; - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = state; add_loop(builder, block, state_type, init_state, loop_body) @@ -806,7 +822,8 @@ fn call_spec( }; let state_layout = argument_layouts[0]; - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = state; add_loop(builder, block, state_type, init_state, loop_body) @@ -828,10 +845,12 @@ fn call_spec( list_append(builder, block, update_mode_var, state, new_element) }; - let output_element_type = layout_spec(builder, return_layout)?; + let output_element_type = + layout_spec(builder, return_layout, &WhenRecursive::Unreachable)?; let state_layout = Layout::Builtin(Builtin::List(return_layout)); - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = new_list(builder, block, output_element_type)?; @@ -851,10 +870,12 @@ fn call_spec( list_append(builder, block, update_mode_var, state, new_element) }; - let output_element_type = layout_spec(builder, return_layout)?; + let output_element_type = + layout_spec(builder, return_layout, &WhenRecursive::Unreachable)?; let state_layout = Layout::Builtin(Builtin::List(return_layout)); - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = new_list(builder, block, output_element_type)?; @@ -879,7 +900,8 @@ fn call_spec( }; let state_layout = Layout::Builtin(Builtin::List(&argument_layouts[0])); - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = list; add_loop(builder, block, state_type, init_state, loop_body) @@ -903,10 +925,12 @@ fn call_spec( list_append(builder, block, update_mode_var, state, new_element) }; - let output_element_type = layout_spec(builder, return_layout)?; + let output_element_type = + layout_spec(builder, return_layout, &WhenRecursive::Unreachable)?; let state_layout = Layout::Builtin(Builtin::List(return_layout)); - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = new_list(builder, block, output_element_type)?; @@ -936,10 +960,12 @@ fn call_spec( list_append(builder, block, update_mode_var, state, new_element) }; - let output_element_type = layout_spec(builder, return_layout)?; + let output_element_type = + layout_spec(builder, return_layout, &WhenRecursive::Unreachable)?; let state_layout = Layout::Builtin(Builtin::List(return_layout)); - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = new_list(builder, block, output_element_type)?; @@ -975,10 +1001,12 @@ fn call_spec( list_append(builder, block, update_mode_var, state, new_element) }; - let output_element_type = layout_spec(builder, return_layout)?; + let output_element_type = + layout_spec(builder, return_layout, &WhenRecursive::Unreachable)?; let state_layout = Layout::Builtin(Builtin::List(return_layout)); - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = new_list(builder, block, output_element_type)?; @@ -1010,7 +1038,8 @@ fn call_spec( }; let state_layout = Layout::Builtin(Builtin::List(&argument_layouts[0])); - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = list; add_loop(builder, block, state_type, init_state, loop_body) @@ -1087,11 +1116,13 @@ fn call_spec( ) }; - let output_element_type = layout_spec(builder, &output_element_layout)?; + let output_element_type = + layout_spec(builder, &output_element_layout, &WhenRecursive::Unreachable)?; let init_state = new_list(builder, block, output_element_type)?; let state_layout = Layout::Builtin(Builtin::List(&output_element_layout)); - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; add_loop(builder, block, state_type, init_state, loop_body) } @@ -1108,7 +1139,8 @@ fn call_spec( }; let state_layout = Layout::Builtin(Builtin::Bool); - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = new_num(builder, block)?; @@ -1127,7 +1159,8 @@ fn call_spec( }; let state_layout = Layout::Builtin(Builtin::Bool); - let state_type = layout_spec(builder, &state_layout)?; + let state_type = + layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?; let init_state = new_num(builder, block)?; @@ -1139,7 +1172,8 @@ fn call_spec( // ListFindUnsafe returns { value: v, found: Bool=Int1 } let output_layouts = vec![argument_layouts[0], Layout::Builtin(Builtin::Bool)]; let output_layout = Layout::struct_no_name_order(&output_layouts); - let output_type = layout_spec(builder, &output_layout)?; + let output_type = + layout_spec(builder, &output_layout, &WhenRecursive::Unreachable)?; let loop_body = |builder: &mut FuncDefBuilder, block, output| { let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?; @@ -1201,7 +1235,7 @@ fn lowlevel_spec( ) -> Result { use LowLevel::*; - let type_id = layout_spec(builder, layout)?; + let type_id = layout_spec(builder, layout, &WhenRecursive::Unreachable)?; let mode = update_mode.to_bytes(); let update_mode_var = UpdateModeVar(&mode); @@ -1323,8 +1357,8 @@ fn lowlevel_spec( } DictEmpty => match layout { Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => { - let key_id = layout_spec(builder, key_layout)?; - let value_id = layout_spec(builder, value_layout)?; + let key_id = layout_spec(builder, key_layout, &WhenRecursive::Unreachable)?; + let value_id = layout_spec(builder, value_layout, &WhenRecursive::Unreachable)?; new_dict(builder, block, key_id, value_id) } _ => unreachable!("empty array does not have a list layout"), @@ -1367,7 +1401,7 @@ fn lowlevel_spec( // TODO overly pessimstic let arguments: Vec<_> = arguments.iter().map(|symbol| env.symbols[symbol]).collect(); - let result_type = layout_spec(builder, layout)?; + let result_type = layout_spec(builder, layout, &WhenRecursive::Unreachable)?; builder.add_unknown_with(block, &arguments, result_type) } @@ -1478,7 +1512,8 @@ fn expr_spec<'a>( let value_id = match tag_layout { UnionLayout::NonRecursive(tags) => { - let variant_types = non_recursive_variant_types(builder, tags)?; + let variant_types = + non_recursive_variant_types(builder, tags, &WhenRecursive::Unreachable)?; let value_id = build_tuple_value(builder, env, block, arguments)?; return builder.add_make_union(block, &variant_types, *tag_id as u32, value_id); } @@ -1592,7 +1627,7 @@ fn expr_spec<'a>( builder.add_get_tuple_field(block, value_id, *index as u32) } Array { elem_layout, elems } => { - let type_id = layout_spec(builder, elem_layout)?; + let type_id = layout_spec(builder, elem_layout, &WhenRecursive::Unreachable)?; let list = new_list(builder, block, type_id)?; @@ -1619,19 +1654,19 @@ fn expr_spec<'a>( EmptyArray => match layout { Layout::Builtin(Builtin::List(element_layout)) => { - let type_id = layout_spec(builder, element_layout)?; + let type_id = layout_spec(builder, element_layout, &WhenRecursive::Unreachable)?; new_list(builder, block, type_id) } _ => unreachable!("empty array does not have a list layout"), }, Reset { symbol, .. } => { - let type_id = layout_spec(builder, layout)?; + let type_id = layout_spec(builder, layout, &WhenRecursive::Unreachable)?; let value_id = env.symbols[symbol]; builder.add_unknown_with(block, &[value_id], type_id) } RuntimeErrorFunction(_) => { - let type_id = layout_spec(builder, layout)?; + let type_id = layout_spec(builder, layout, &WhenRecursive::Unreachable)?; builder.add_terminate(block, type_id) } @@ -1658,18 +1693,24 @@ fn literal_spec( } } -fn layout_spec(builder: &mut impl TypeContext, layout: &Layout) -> Result { - layout_spec_help(builder, layout, &WhenRecursive::Unreachable) +fn layout_spec( + builder: &mut impl TypeContext, + layout: &Layout, + when_recursive: &WhenRecursive, +) -> Result { + layout_spec_help(builder, layout, when_recursive) } fn non_recursive_variant_types( builder: &mut impl TypeContext, tags: &[&[Layout]], + // If there is a recursive pointer latent within this layout, coming from a containing layout. + when_recursive: &WhenRecursive, ) -> Result> { let mut result = Vec::with_capacity(tags.len()); for tag in tags.iter() { - result.push(build_tuple_type(builder, tag)?); + result.push(build_tuple_type(builder, tag, when_recursive)?); } Ok(result) @@ -1701,7 +1742,7 @@ fn layout_spec_help( builder.add_tuple_type(&[]) } UnionLayout::NonRecursive(tags) => { - let variant_types = non_recursive_variant_types(builder, tags)?; + let variant_types = non_recursive_variant_types(builder, tags, when_recursive)?; builder.add_union_type(&variant_types) } UnionLayout::Recursive(_) diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index ce79180f75..504d59b96a 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -1809,7 +1809,39 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( for (i, field_layout) in field_layouts.iter().enumerate() { if let Layout::RecursivePointer = field_layout { - panic!("non-recursive tag unions cannot contain naked recursion pointers!"); + let recursive_union_layout = match when_recursive { + WhenRecursive::Unreachable => { + panic!("non-recursive tag unions cannot contain naked recursion pointers!"); + } + WhenRecursive::Loop(recursive_union_layout) => recursive_union_layout, + }; + + // This field is a pointer to the recursive pointer. + let field_ptr = env + .builder + .build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field") + .unwrap(); + + // This is the actual pointer to the recursive data. + let field_value = env.builder.build_load(field_ptr, "load_recursive_pointer"); + + debug_assert!(field_value.is_pointer_value()); + + // therefore we must cast it to our desired type + let union_type = + basic_type_from_layout(env, &Layout::Union(*recursive_union_layout)); + let recursive_ptr_field_value = + cast_basic_basic(env.builder, field_value, union_type); + + modify_refcount_layout_help( + env, + parent, + layout_ids, + mode.to_call_mode(fn_val), + when_recursive, + recursive_ptr_field_value, + &Layout::RecursivePointer, + ) } else if field_layout.contains_refcounted() { let field_ptr = env .builder diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index eef312cab3..e21d054ed0 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -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 { 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, 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, - 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 { diff --git a/compiler/test_mono/generated/issue_2810.txt b/compiler/test_mono/generated/issue_2810.txt new file mode 100644 index 0000000000..d5b11bcac2 --- /dev/null +++ b/compiler/test_mono/generated/issue_2810.txt @@ -0,0 +1,6 @@ +procedure Test.0 (): + let Test.16 : [C TODO, C ] = SystemTool ; + let Test.14 : TODO = Job Test.16; + let Test.13 : [C TODO, C ] = FromJob Test.14; + let Test.4 : TODO = Job Test.13; + ret Test.4; diff --git a/compiler/test_mono/src/tests.rs b/compiler/test_mono/src/tests.rs index 86e93346f1..115b5a8ca3 100644 --- a/compiler/test_mono/src/tests.rs +++ b/compiler/test_mono/src/tests.rs @@ -1283,6 +1283,23 @@ fn issue_2583_specialize_errors_behind_unified_branches() { ) } +#[mono_test] +fn issue_2810() { + indoc!( + r#" + Command : [ Command Tool ] + + Job : [ Job Command ] + + Tool : [ SystemTool, FromJob Job ] + + a : Job + a = Job (Command (FromJob (Job (Command SystemTool)))) + a + "# + ) +} + #[mono_test] fn issue_2811() { indoc!( diff --git a/repl_test/src/tests.rs b/repl_test/src/tests.rs index 53b692266c..fe2b90d2ea 100644 --- a/repl_test/src/tests.rs +++ b/repl_test/src/tests.rs @@ -1138,3 +1138,23 @@ fn issue_2818() { r" : {} -> List Str", ) } + +#[test] +fn issue_2810_recursive_layout_inside_nonrecursive() { + expect_success( + indoc!( + r#" + Command : [ Command Tool ] + + Job : [ Job Command ] + + Tool : [ SystemTool, FromJob Job ] + + a : Job + a = Job (Command (FromJob (Job (Command SystemTool)))) + a + "# + ), + "Job (Command (FromJob (Job (Command SystemTool)))) : Job", + ) +}