mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 22:09:09 +00:00
Hash record field name order in generated layouts
Closes #2535 See the referenced issue for longer discussion - here's the synopsis. Consider this program ``` app "test" provides [ nums ] to "./platform" alpha = { a: 1, b: 2 } nums : List U8 nums = [ alpha.a, alpha.b, ] ``` Here's its IR: ``` procedure : `#UserApp.alpha` {I64, U8} procedure = `#UserApp.alpha` (): let `#UserApp.5` : Builtin(Int(I64)) = 1i64; let `#UserApp.6` : Builtin(Int(U8)) = 2i64; let `#UserApp.4` : Struct([Builtin(Int(I64)), Builtin(Int(U8))]) = Struct {`#UserApp.5`, `#UserApp.6`}; ret `#UserApp.4`; procedure : `#UserApp.nums` List U8 procedure = `#UserApp.nums` (): let `#UserApp.7` : Struct([Builtin(Int(I64)), Builtin(Int(U8))]) = CallByName `#UserApp.alpha`; let `#UserApp.1` : Builtin(Int(U8)) = StructAtIndex 1 `#UserApp.7`; let `#UserApp.3` : Struct([Builtin(Int(I64)), Builtin(Int(U8))]) = CallByName `#UserApp.alpha`; let `#UserApp.2` : Builtin(Int(U8)) = StructAtIndex 1 `#UserApp.3`; let `#UserApp.0` : Builtin(List(Builtin(Int(U8)))) = Array [`#UserApp.1`, `#UserApp.2`]; ret `#UserApp.0`; ``` What's happening is that we need to specialize `alpha` twice - once for the type of a narrowed to a U8, another time for the type of b narrowed to a U8. We do the specialization for alpha.b first - record fields are sorted by layout, so we generate a record of type {i64, u8}. But then we go to specialize alpha.a, but this has the same layout - {i64, u8} - so we reuse the existing one! So (at least for records), we need to include record field order associated with the sorted layout fields, so that we don't reuse monomorphizations like this incorrectly!
This commit is contained in:
parent
74daec84df
commit
e52d427ac8
22 changed files with 225 additions and 105 deletions
|
@ -714,8 +714,7 @@ fn promote_to_main_function<'a, 'ctx, 'env>(
|
|||
);
|
||||
|
||||
// NOTE fake layout; it is only used for debug prints
|
||||
let roc_main_fn =
|
||||
function_value_by_func_spec(env, *func_spec, symbol, &[], &Layout::Struct(&[]));
|
||||
let roc_main_fn = function_value_by_func_spec(env, *func_spec, symbol, &[], &Layout::UNIT);
|
||||
|
||||
let main_fn_name = "$Test.main";
|
||||
|
||||
|
@ -1188,8 +1187,8 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
|
||||
// extract field from a record
|
||||
match (value, layout) {
|
||||
(StructValue(argument), Layout::Struct(fields)) => {
|
||||
debug_assert!(!fields.is_empty());
|
||||
(StructValue(argument), Layout::Struct { field_layouts, .. }) => {
|
||||
debug_assert!(!field_layouts.is_empty());
|
||||
|
||||
let field_value = env
|
||||
.builder
|
||||
|
@ -1201,14 +1200,14 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let field_layout = fields[*index as usize];
|
||||
let field_layout = field_layouts[*index as usize];
|
||||
use_roc_value(env, field_layout, field_value, "struct_field_tag")
|
||||
}
|
||||
(
|
||||
PointerValue(argument),
|
||||
Layout::Union(UnionLayout::NonNullableUnwrapped(fields)),
|
||||
) => {
|
||||
let struct_layout = Layout::Struct(fields);
|
||||
let struct_layout = Layout::struct_no_name_order(fields);
|
||||
let struct_type = basic_type_from_layout(env, &struct_layout);
|
||||
|
||||
let cast_argument = env
|
||||
|
@ -1292,7 +1291,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
UnionLayout::NonNullableUnwrapped(field_layouts) => {
|
||||
let struct_layout = Layout::Struct(field_layouts);
|
||||
let struct_layout = Layout::struct_no_name_order(field_layouts);
|
||||
|
||||
let struct_type = basic_type_from_layout(env, &struct_layout);
|
||||
|
||||
|
@ -1341,7 +1340,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
debug_assert_ne!(*tag_id != 0, *nullable_id);
|
||||
|
||||
let field_layouts = other_fields;
|
||||
let struct_layout = Layout::Struct(field_layouts);
|
||||
let struct_layout = Layout::struct_no_name_order(field_layouts);
|
||||
|
||||
let struct_type = basic_type_from_layout(env, &struct_layout);
|
||||
|
||||
|
@ -2024,7 +2023,7 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
|
|||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let struct_layout = Layout::Struct(field_layouts);
|
||||
let struct_layout = Layout::struct_no_name_order(field_layouts);
|
||||
let struct_type = basic_type_from_layout(env, &struct_layout);
|
||||
|
||||
let wrapper_type = env
|
||||
|
@ -3522,7 +3521,7 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
|
|||
call_roc_function(
|
||||
env,
|
||||
roc_wrapper_function,
|
||||
&Layout::Struct(&[Layout::u64(), return_layout]),
|
||||
&Layout::struct_no_name_order(&[Layout::u64(), return_layout]),
|
||||
arguments_for_call,
|
||||
)
|
||||
};
|
||||
|
@ -3903,7 +3902,7 @@ fn roc_result_layout<'a>(
|
|||
) -> Layout<'a> {
|
||||
let elements = [Layout::u64(), Layout::usize(target_info), return_layout];
|
||||
|
||||
Layout::Struct(arena.alloc(elements))
|
||||
Layout::struct_no_name_order(arena.alloc(elements))
|
||||
}
|
||||
|
||||
fn roc_result_type<'a, 'ctx, 'env>(
|
||||
|
@ -5363,7 +5362,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
let (string, _string_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
|
||||
let number_layout = match layout {
|
||||
Layout::Struct(fields) => fields[0], // TODO: why is it sometimes a struct?
|
||||
Layout::Struct { field_layouts, .. } => field_layouts[0], // TODO: why is it sometimes a struct?
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue