Skip to content

Commit c5680bd

Browse files
committed
Feedback
1 parent 64b759a commit c5680bd

File tree

8 files changed

+314
-86
lines changed

8 files changed

+314
-86
lines changed

src/codegen/generators/statement_generator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,13 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> {
242242
///
243243
/// Note: Although somewhat similar to the [`generate_assignment_statement`] function, we can't
244244
/// apply the code here because the left side of a `REF=` assignment is flagged as auto-deref.
245-
/// For `REF=` assignments we don't want (and can't) deref without generating incorrect IR.:w
245+
/// For `REF=` assignments we don't want (and can't) deref without generating incorrect IR.
246246
pub fn generate_ref_assignment(&self, left: &AstNode, right: &AstNode) -> Result<(), Diagnostic> {
247247
let exp = self.create_expr_generator();
248248
let ref_builtin = self.index.get_builtin_function("REF").expect("REF must exist");
249249

250250
let AstStatement::ReferenceExpr(data) = &left.stmt else {
251-
unreachable!("should be covered by a validation? The left-hand side must be a reference")
251+
unreachable!("should be covered by a validation")
252252
};
253253

254254
let left_ptr_val = {

src/codegen/tests/statement_codegen_test.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ fn reference_to_assignment() {
241241

242242
// We want to assert that `a := 5` and `a^ := 5` yield identical IR
243243
assert_eq!(auto_deref, manual_deref);
244-
//
244+
245245
insta::assert_snapshot!(auto_deref, @r###"
246246
; ModuleID = 'main'
247247
source_filename = "main"
@@ -256,3 +256,55 @@ fn reference_to_assignment() {
256256
}
257257
"###);
258258
}
259+
260+
#[test]
261+
fn reference_to_string_assignment() {
262+
let auto_deref = codegen(
263+
r#"
264+
FUNCTION main
265+
VAR
266+
a : REFERENCE TO STRING;
267+
END_VAR
268+
269+
a := 'hello';
270+
END_FUNCTION
271+
"#,
272+
);
273+
274+
let manual_deref = codegen(
275+
r#"
276+
FUNCTION main
277+
VAR
278+
a : REF_TO STRING;
279+
END_VAR
280+
281+
a^ := 'hello';
282+
END_FUNCTION
283+
"#,
284+
);
285+
286+
// We want to assert that `a := 'hello'` and `a^ := 'hello'` yield identical IR
287+
assert_eq!(auto_deref, manual_deref);
288+
289+
insta::assert_snapshot!(auto_deref, @r###"
290+
; ModuleID = 'main'
291+
source_filename = "main"
292+
293+
@utf08_literal_0 = private unnamed_addr constant [6 x i8] c"hello\00"
294+
295+
define void @main() section "fn-$RUSTY$main:v" {
296+
entry:
297+
%a = alloca [81 x i8]*, align 8
298+
store [81 x i8]* null, [81 x i8]** %a, align 8
299+
%deref = load [81 x i8]*, [81 x i8]** %a, align 8
300+
%0 = bitcast [81 x i8]* %deref to i8*
301+
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %0, i8* align 1 getelementptr inbounds ([6 x i8], [6 x i8]* @utf08_literal_0, i32 0, i32 0), i32 6, i1 false)
302+
ret void
303+
}
304+
305+
; Function Attrs: argmemonly nofree nounwind willreturn
306+
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #0
307+
308+
attributes #0 = { argmemonly nofree nounwind willreturn }
309+
"###);
310+
}

src/index.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,7 @@ impl Index {
11301130
if segments.is_empty() {
11311131
return None;
11321132
}
1133+
11331134
//For the first element, if the context does not contain that element, it is possible that the element is also a global variable
11341135
let init = match context {
11351136
Some(context) => self

src/validation/statement.rs

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use plc_ast::{
1414
use plc_diagnostics::diagnostics::Diagnostic;
1515
use plc_source::source_location::SourceLocation;
1616

17+
use super::{array::validate_array_assignment, ValidationContext, Validator, Validators};
1718
use crate::index::ImplementationType;
19+
use crate::typesystem::VOID_TYPE;
1820
use crate::validation::statement::helper::{get_datatype_name_or_slice, get_literal_int_or_const_expr_value};
1921
use crate::{
2022
builtins::{self, BuiltIn},
@@ -27,8 +29,6 @@ use crate::{
2729
},
2830
};
2931

30-
use super::{array::validate_array_assignment, ValidationContext, Validator, Validators};
31-
3232
macro_rules! visit_all_statements {
3333
($validator:expr, $context:expr, $last:expr ) => {
3434
visit_statement($validator, $last, $context);
@@ -777,24 +777,59 @@ fn validate_ref_assignment<T: AnnotationMap>(
777777
assignment: &Assignment,
778778
assignment_location: &SourceLocation,
779779
) {
780-
let mut assert_reference = |node: &AstNode| {
781-
if !node.is_reference() {
782-
validator.push_diagnostic(
783-
Diagnostic::new("Invalid assignment, expected a reference")
784-
.with_location(&node.location)
785-
.with_error_code("E098"),
786-
);
787-
}
788-
};
789-
790-
assert_reference(&assignment.left);
791-
assert_reference(&assignment.right);
792-
793-
// Lastly, assert the type the lhs references matches with the rhs
794780
let type_lhs = context.annotations.get_type_or_void(&assignment.left, context.index);
795781
let type_rhs = context.annotations.get_type_or_void(&assignment.right, context.index);
796782
let type_info_lhs = context.index.find_elementary_pointer_type(type_lhs.get_type_information());
797783
let type_info_rhs = context.index.find_elementary_pointer_type(type_rhs.get_type_information());
784+
let annotation_lhs = context.annotations.get(&assignment.left);
785+
786+
// Assert that the right-hand side is a reference
787+
if !assignment.right.is_reference() {
788+
validator.push_diagnostic(
789+
Diagnostic::new("Invalid assignment, expected a reference")
790+
.with_location(&assignment.right.location)
791+
.with_error_code("E098"),
792+
);
793+
}
794+
795+
// Assert that the left-hand side is a valid pointer-reference
796+
if !annotation_lhs.is_some_and(StatementAnnotation::is_reference_to) && !type_lhs.is_pointer() {
797+
validator.push_diagnostic(
798+
Diagnostic::new("Invalid assignment, expected a pointer reference")
799+
.with_location(&assignment.left.location)
800+
.with_error_code("E098"),
801+
)
802+
}
803+
804+
if type_info_lhs.is_array() && type_info_rhs.is_array() {
805+
let mut messages = Vec::new();
806+
807+
let len_lhs = type_info_lhs.get_array_length(context.index).unwrap_or_default();
808+
let len_rhs = type_info_rhs.get_array_length(context.index).unwrap_or_default();
809+
810+
if len_lhs < len_rhs {
811+
messages.push(format!("Invalid assignment, array lengths {len_lhs} and {len_rhs} differ"));
812+
}
813+
814+
let inner_ty_name_lhs = type_info_lhs.get_inner_array_type_name().unwrap_or(VOID_TYPE);
815+
let inner_ty_name_rhs = type_info_rhs.get_inner_array_type_name().unwrap_or(VOID_TYPE);
816+
let inner_ty_lhs = context.index.find_effective_type_by_name(inner_ty_name_lhs);
817+
let inner_ty_rhs = context.index.find_effective_type_by_name(inner_ty_name_rhs);
818+
819+
if inner_ty_lhs != inner_ty_rhs {
820+
messages.push(format!(
821+
"Invalid assignment, array types {inner_ty_name_lhs} and {inner_ty_name_rhs} differ"
822+
));
823+
}
824+
825+
for message in messages {
826+
validator.push_diagnostic(
827+
Diagnostic::new(message).with_location(assignment_location).with_error_code("E098"),
828+
)
829+
}
830+
831+
return;
832+
}
798833

799834
if type_info_lhs != type_info_rhs {
800835
validator.push_diagnostic(

0 commit comments

Comments
 (0)