Create symbols for struct fields before record update

This commit is contained in:
JRI98 2024-02-02 23:49:48 +00:00
parent 2347c3f667
commit ad6900514b
No known key found for this signature in database
GPG key ID: F83B29916FF13F24
4 changed files with 71 additions and 40 deletions

View file

@ -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);
}
}

View 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;

View file

@ -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 ():

View file

@ -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 }
"
)
}