mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-31 00:57:24 +00:00
Create symbols for struct fields before record update
This commit is contained in:
parent
2347c3f667
commit
ad6900514b
4 changed files with 71 additions and 40 deletions
|
@ -5156,6 +5156,21 @@ pub fn with_hole<'a>(
|
|||
Err(_) => return runtime_error(env, "Can't update record with improper layout"),
|
||||
};
|
||||
|
||||
let sorted_fields_filtered =
|
||||
sorted_fields
|
||||
.iter()
|
||||
.filter_map(|(label, _, opt_field_layout)| {
|
||||
match opt_field_layout {
|
||||
Ok(_) => Some(label),
|
||||
Err(_) => {
|
||||
debug_assert!(!updates.contains_key(label));
|
||||
// this was an optional field, and now does not exist!
|
||||
None
|
||||
}
|
||||
}
|
||||
});
|
||||
let sorted_fields = Vec::from_iter_in(sorted_fields_filtered, env.arena);
|
||||
|
||||
let single_field_struct = sorted_fields.len() == 1;
|
||||
|
||||
// The struct indexing generated by the current context
|
||||
|
@ -5164,44 +5179,38 @@ pub fn with_hole<'a>(
|
|||
let mut new_struct_symbols = Vec::with_capacity_in(sorted_fields.len(), env.arena);
|
||||
// Information about the fields that are being updated
|
||||
let mut fields = Vec::with_capacity_in(sorted_fields.len(), env.arena);
|
||||
let mut index = 0;
|
||||
for (label, _, opt_field_layout) in sorted_fields.iter() {
|
||||
let record_index = (structure, index);
|
||||
|
||||
match opt_field_layout {
|
||||
Err(_) => {
|
||||
debug_assert!(!updates.contains_key(label));
|
||||
// this was an optional field, and now does not exist!
|
||||
// do not increment `index`!
|
||||
}
|
||||
Ok(_field_layout) => {
|
||||
current_struct_indexing.push(record_index);
|
||||
// Create a symbol for each of the fields as they might be referenced later.
|
||||
// The struct with a single field is optimized in such a way that replacing later indexing will cause an incorrect IR.
|
||||
// Thus, only insert these struct_indices if there is more than one field in the struct.
|
||||
if !single_field_struct {
|
||||
for index in 0..sorted_fields.len() {
|
||||
let record_index = (structure, index as u64);
|
||||
|
||||
// The struct with a single field is optimized in such a way that replacing later indexing will cause an incorrect IR.
|
||||
// Thus, only insert these struct_indices if there is more than one field in the struct.
|
||||
if !single_field_struct {
|
||||
let original_struct_symbol = env.unique_symbol();
|
||||
env.struct_indexing
|
||||
.insert(record_index, original_struct_symbol);
|
||||
}
|
||||
if let Some(field) = updates.get(label) {
|
||||
let new_struct_symbol = possible_reuse_symbol_or_specialize(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
&field.loc_expr.value,
|
||||
field.var,
|
||||
);
|
||||
new_struct_symbols.push(new_struct_symbol);
|
||||
fields.push(UpdateExisting(field));
|
||||
} else {
|
||||
new_struct_symbols
|
||||
.push(*env.struct_indexing.get(record_index).unwrap());
|
||||
fields.push(CopyExisting);
|
||||
}
|
||||
current_struct_indexing.push(record_index);
|
||||
|
||||
index += 1;
|
||||
}
|
||||
let original_struct_symbol = env.unique_symbol();
|
||||
env.struct_indexing
|
||||
.insert(record_index, original_struct_symbol);
|
||||
}
|
||||
}
|
||||
|
||||
for (index, label) in sorted_fields.iter().enumerate() {
|
||||
let record_index = (structure, index as u64);
|
||||
|
||||
if let Some(field) = updates.get(label) {
|
||||
let new_struct_symbol = possible_reuse_symbol_or_specialize(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
&field.loc_expr.value,
|
||||
field.var,
|
||||
);
|
||||
new_struct_symbols.push(new_struct_symbol);
|
||||
fields.push(UpdateExisting(field));
|
||||
} else {
|
||||
new_struct_symbols.push(*env.struct_indexing.get(record_index).unwrap());
|
||||
fields.push(CopyExisting);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
11
crates/compiler/test_mono/generated/issue_5513.txt
Normal file
11
crates/compiler/test_mono/generated/issue_5513.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
procedure Test.1 (Test.2):
|
||||
let Test.7 : I64 = StructAtIndex 1 Test.2;
|
||||
let Test.5 : {I64, I64} = Struct {Test.7, Test.7};
|
||||
ret Test.5;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.8 : I64 = 0i64;
|
||||
let Test.9 : I64 = 0i64;
|
||||
let Test.4 : {I64, I64} = Struct {Test.8, Test.9};
|
||||
let Test.3 : {I64, I64} = CallByName Test.1 Test.4;
|
||||
ret Test.3;
|
|
@ -27,15 +27,15 @@ procedure Num.22 (#Attr.2, #Attr.3):
|
|||
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.6 : List U64 = StructAtIndex 0 Test.2;
|
||||
let Test.8 : List U64 = StructAtIndex 1 Test.2;
|
||||
let Test.10 : List U64 = StructAtIndex 2 Test.2;
|
||||
let Test.7 : List U64 = StructAtIndex 1 Test.2;
|
||||
let Test.8 : List U64 = StructAtIndex 2 Test.2;
|
||||
let Test.13 : U64 = 8i64;
|
||||
let Test.14 : U64 = 8i64;
|
||||
let Test.9 : List U64 = CallByName List.3 Test.8 Test.13 Test.14;
|
||||
let Test.10 : List U64 = CallByName List.3 Test.7 Test.13 Test.14;
|
||||
let Test.11 : U64 = 7i64;
|
||||
let Test.12 : U64 = 7i64;
|
||||
let Test.7 : List U64 = CallByName List.3 Test.6 Test.11 Test.12;
|
||||
let Test.5 : {List U64, List U64, List U64} = Struct {Test.7, Test.9, Test.10};
|
||||
let Test.9 : List U64 = CallByName List.3 Test.6 Test.11 Test.12;
|
||||
let Test.5 : {List U64, List U64, List U64} = Struct {Test.9, Test.10, Test.8};
|
||||
ret Test.5;
|
||||
|
||||
procedure Test.0 ():
|
||||
|
|
|
@ -3463,3 +3463,14 @@ fn issue_6196() {
|
|||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn issue_5513() {
|
||||
indoc!(
|
||||
r"
|
||||
f = \state ->
|
||||
{ state & a: state.b }
|
||||
f { a: 0, b: 0 }
|
||||
"
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue