Skip to content

Commit 3150be6

Browse files
authored
Merge pull request #663 from PLC-lang/659-array-of-struct-initialization-problem
#659 array of struct initialization
2 parents 3dc10fb + 79e09c7 commit 3150be6

6 files changed

+184
-2
lines changed

src/codegen/generators/expression_generator.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -2224,7 +2224,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
22242224
initializer: &AstStatement,
22252225
) -> Result<BasicValueEnum<'ink>, Diagnostic> {
22262226
let array_value = self.generate_literal_array_value(
2227-
flatten_expression_list(initializer),
2227+
initializer,
22282228
self.get_type_hint_info_for(initializer)?,
22292229
&initializer.get_location(),
22302230
)?;
@@ -2238,7 +2238,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
22382238
/// i16-array-value
22392239
fn generate_literal_array_value(
22402240
&self,
2241-
elements: Vec<&AstStatement>,
2241+
elements: &AstStatement,
22422242
data_type: &DataTypeInformation,
22432243
location: &SourceRange,
22442244
) -> Result<BasicValueEnum<'ink>, Diagnostic> {
@@ -2266,6 +2266,23 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
22662266
))
22672267
}?;
22682268

2269+
// for arrays of struct we cannot flatten the expression list
2270+
// to generate the passed structs we need an expression list of assignments
2271+
// flatten_expression_list will will return a vec of only assignments
2272+
let elements = if self
2273+
.index
2274+
.get_effective_type_or_void_by_name(inner_type.get_name())
2275+
.information
2276+
.is_struct()
2277+
{
2278+
match elements {
2279+
AstStatement::ExpressionList { expressions, .. } => expressions.iter().collect(),
2280+
_ => unreachable!("This should always be an expression list"),
2281+
}
2282+
} else {
2283+
flatten_expression_list(elements)
2284+
};
2285+
22692286
let llvm_type = self.llvm_index.get_associated_type(inner_type.get_name())?;
22702287
let mut v = Vec::new();
22712288
for e in elements {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
source: src/codegen/tests/initialization_test/type_initializers.rs
3+
expression: result
4+
---
5+
; ModuleID = 'main'
6+
source_filename = "main"
7+
8+
%myStruct = type { i32, i32 }
9+
%main = type { [2 x %myStruct], [2 x %myStruct] }
10+
11+
@str = unnamed_addr constant %myStruct { i32 40, i32 50 }
12+
@alias_str = unnamed_addr constant %myStruct { i32 40, i32 50 }
13+
@main_instance = global %main { [2 x %myStruct] [%myStruct { i32 20, i32 30 }, %myStruct { i32 40, i32 50 }], [2 x %myStruct] [%myStruct { i32 20, i32 30 }, %myStruct { i32 40, i32 50 }] }
14+
@__myStruct__init = unnamed_addr constant %myStruct zeroinitializer
15+
@__main.arr__init = unnamed_addr constant [2 x %myStruct] [%myStruct { i32 20, i32 30 }, %myStruct { i32 40, i32 50 }]
16+
@__main.alias_arr__init = unnamed_addr constant [2 x %myStruct] [%myStruct { i32 20, i32 30 }, %myStruct { i32 40, i32 50 }]
17+
18+
define void @main(%main* %0) {
19+
entry:
20+
%arr = getelementptr inbounds %main, %main* %0, i32 0, i32 0
21+
%alias_arr = getelementptr inbounds %main, %main* %0, i32 0, i32 1
22+
ret void
23+
}
24+

src/codegen/tests/initialization_test/type_initializers.rs

+28
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,34 @@ fn struct_initializer_uses_fallback_to_field_default() {
517517
assert!(diagnostics.is_empty());
518518
}
519519

520+
#[test]
521+
fn array_of_struct_initialization() {
522+
let source = "
523+
TYPE myStruct : STRUCT
524+
a,b : DINT;
525+
END_STRUCT
526+
END_TYPE
527+
528+
TYPE AliasMyStruct : myStruct; END_TYPE
529+
530+
VAR_GLOBAL CONSTANT
531+
str : myStruct := (a := 40, b := 50);
532+
alias_str : AliasMyStruct := (a := 40, b := 50);
533+
END_VAR
534+
535+
PROGRAM main
536+
VAR
537+
arr : ARRAY[0..1] OF myStruct := ((a := 20, b := 30), str);
538+
alias_arr : ARRAY[0..1] OF AliasMyStruct := ((a := 20, b := 30), alias_str);
539+
END_VAR
540+
END_PROGRAM
541+
";
542+
let (result, diagnostics) = codegen(source);
543+
544+
insta::assert_snapshot!(result);
545+
assert!(diagnostics.is_empty());
546+
}
547+
520548
#[test]
521549
fn type_defaults_are_used_for_uninitialized_constants() {
522550
let result = codegen_without_unwrap(

src/resolver.rs

+23
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,29 @@ impl<'i> TypeAnnotator<'i> {
811811
StatementAnnotation::value(expected_type.get_name()),
812812
);
813813
self.update_expected_types(expected_type, initializer);
814+
815+
// handle annotation for array of struct
816+
if let DataTypeInformation::Array {
817+
inner_type_name, ..
818+
} = expected_type.get_type_information()
819+
{
820+
let struct_type = self
821+
.index
822+
.get_effective_type_or_void_by_name(inner_type_name);
823+
if struct_type.get_type_information().is_struct() {
824+
if let AstStatement::ExpressionList { expressions, .. } = initializer {
825+
for e in expressions {
826+
// annotate with the arrays inner_type
827+
self.annotation_map.annotate_type_hint(
828+
e,
829+
StatementAnnotation::Value {
830+
resulting_type: struct_type.get_name().to_string(),
831+
},
832+
)
833+
}
834+
}
835+
}
836+
}
814837
}
815838
}
816839
}

src/resolver/tests/resolve_expressions_tests.rs

+47
Original file line numberDiff line numberDiff line change
@@ -3774,3 +3774,50 @@ fn multiple_negative_annotates_correctly() {
37743774
}
37753775
}
37763776
}
3777+
3778+
#[test]
3779+
fn array_of_struct_with_inital_values_annotated_correctly() {
3780+
let id_provider = IdProvider::default();
3781+
// GIVEN
3782+
let (unit, mut index) = index_with_ids(
3783+
"
3784+
TYPE myStruct : STRUCT
3785+
a,b : DINT;
3786+
END_STRUCT
3787+
END_TYPE
3788+
3789+
PROGRAM main
3790+
VAR
3791+
arr : ARRAY[0..1] OF myStruct := ((a:= 10, b:= 20), (a:= 30, b:= 40));
3792+
END_VAR
3793+
END_PROGRAM",
3794+
id_provider.clone(),
3795+
);
3796+
3797+
let mut annotations = annotate_with_ids(&unit, &mut index, id_provider);
3798+
index.import(std::mem::take(&mut annotations.new_index));
3799+
3800+
let container_name = &unit.implementations[0].name; // main
3801+
let members = index.get_container_members(container_name);
3802+
// there is only one member => arr
3803+
assert_eq!(1, members.len());
3804+
3805+
if let Some(AstStatement::ExpressionList { expressions, .. }) = index
3806+
.get_const_expressions()
3807+
.maybe_get_constant_statement(&members[0].initial_value)
3808+
{
3809+
// we initialized the array with 2 structs
3810+
assert_eq!(2, expressions.len());
3811+
let target_type = index
3812+
.find_effective_type_by_name("myStruct")
3813+
.expect("at this point we should have the type");
3814+
for e in expressions {
3815+
let type_hint = annotations
3816+
.get_type_hint(e, &index)
3817+
.expect("we should have a type hint");
3818+
assert_eq!(target_type, type_hint);
3819+
}
3820+
} else {
3821+
panic!("No initial value, initial value should be an expression list")
3822+
}
3823+
}

tests/correctness/initial_values.rs

+43
Original file line numberDiff line numberDiff line change
@@ -1413,3 +1413,46 @@ fn initial_value_of_function_return_struct() {
14131413
let _: i32 = compile_and_run(function.to_string(), &mut maintype);
14141414
assert_eq!([11, 22, 33], [maintype.a, maintype.b, maintype.c]);
14151415
}
1416+
1417+
#[test]
1418+
fn initial_value_in_array_of_struct() {
1419+
let function = "
1420+
TYPE myStruct : STRUCT
1421+
a,b : DINT;
1422+
END_STRUCT
1423+
END_TYPE
1424+
1425+
VAR_GLOBAL CONSTANT
1426+
str : myStruct := (a := 30, b := 40);
1427+
END_VAR
1428+
1429+
PROGRAM main
1430+
VAR_TEMP
1431+
arr : ARRAY[0..1] OF myStruct := ((a:= 10, b:= 20), str);
1432+
END_VAR
1433+
VAR
1434+
a,b,c,d: DINT;
1435+
END_VAR
1436+
a := arr[0].a;
1437+
b := arr[0].b;
1438+
c := arr[1].a;
1439+
d := arr[1].b;
1440+
END_PROGRAM
1441+
";
1442+
1443+
#[allow(dead_code)]
1444+
#[derive(Default)]
1445+
struct MainType {
1446+
a: i32,
1447+
b: i32,
1448+
c: i32,
1449+
d: i32,
1450+
}
1451+
let mut maintype = MainType::default();
1452+
1453+
let _: i32 = compile_and_run(function.to_string(), &mut maintype);
1454+
assert_eq!(
1455+
[10, 20, 30, 40],
1456+
[maintype.a, maintype.b, maintype.c, maintype.d]
1457+
);
1458+
}

0 commit comments

Comments
 (0)