Skip to content

Commit

Permalink
Feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
volsa committed Jul 4, 2024
1 parent 64b759a commit b60bc18
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 86 deletions.
4 changes: 2 additions & 2 deletions src/codegen/generators/statement_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,13 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> {
///
/// Note: Although somewhat similar to the [`generate_assignment_statement`] function, we can't
/// apply the code here because the left side of a `REF=` assignment is flagged as auto-deref.
/// For `REF=` assignments we don't want (and can't) deref without generating incorrect IR.:w
/// For `REF=` assignments we don't want (and can't) deref without generating incorrect IR.
pub fn generate_ref_assignment(&self, left: &AstNode, right: &AstNode) -> Result<(), Diagnostic> {
let exp = self.create_expr_generator();
let ref_builtin = self.index.get_builtin_function("REF").expect("REF must exist");

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

let left_ptr_val = {
Expand Down
54 changes: 53 additions & 1 deletion src/codegen/tests/statement_codegen_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ fn reference_to_assignment() {

// We want to assert that `a := 5` and `a^ := 5` yield identical IR
assert_eq!(auto_deref, manual_deref);
//

insta::assert_snapshot!(auto_deref, @r###"
; ModuleID = 'main'
source_filename = "main"
Expand All @@ -256,3 +256,55 @@ fn reference_to_assignment() {
}
"###);
}

#[test]
fn reference_to_string_assignment() {
let auto_deref = codegen(
r#"
FUNCTION main
VAR
a : REFERENCE TO STRING;
END_VAR
a := 'hello';
END_FUNCTION
"#,
);

let manual_deref = codegen(
r#"
FUNCTION main
VAR
a : REF_TO STRING;
END_VAR
a^ := 'hello';
END_FUNCTION
"#,
);

// We want to assert that `a := 'hello'` and `a^ := 'hello'` yield identical IR
assert_eq!(auto_deref, manual_deref);

insta::assert_snapshot!(auto_deref, @r###"
; ModuleID = 'main'
source_filename = "main"
@utf08_literal_0 = private unnamed_addr constant [6 x i8] c"hello\00"
define void @main() section "fn-$RUSTY$main:v" {
entry:
%a = alloca [81 x i8]*, align 8
store [81 x i8]* null, [81 x i8]** %a, align 8
%deref = load [81 x i8]*, [81 x i8]** %a, align 8
%0 = bitcast [81 x i8]* %deref to i8*
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)
ret void
}
; Function Attrs: argmemonly nofree nounwind willreturn
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #0
attributes #0 = { argmemonly nofree nounwind willreturn }
"###);
}
1 change: 1 addition & 0 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,7 @@ impl Index {
if segments.is_empty() {
return None;
}

//For the first element, if the context does not contain that element, it is possible that the element is also a global variable
let init = match context {
Some(context) => self
Expand Down
67 changes: 51 additions & 16 deletions src/validation/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ use plc_ast::{
use plc_diagnostics::diagnostics::Diagnostic;
use plc_source::source_location::SourceLocation;

use super::{array::validate_array_assignment, ValidationContext, Validator, Validators};
use crate::index::ImplementationType;
use crate::typesystem::VOID_TYPE;
use crate::validation::statement::helper::{get_datatype_name_or_slice, get_literal_int_or_const_expr_value};
use crate::{
builtins::{self, BuiltIn},
Expand All @@ -27,8 +29,6 @@ use crate::{
},
};

use super::{array::validate_array_assignment, ValidationContext, Validator, Validators};

macro_rules! visit_all_statements {
($validator:expr, $context:expr, $last:expr ) => {
visit_statement($validator, $last, $context);
Expand Down Expand Up @@ -777,24 +777,59 @@ fn validate_ref_assignment<T: AnnotationMap>(
assignment: &Assignment,
assignment_location: &SourceLocation,
) {
let mut assert_reference = |node: &AstNode| {
if !node.is_reference() {
validator.push_diagnostic(
Diagnostic::new("Invalid assignment, expected a reference")
.with_location(&node.location)
.with_error_code("E098"),
);
}
};

assert_reference(&assignment.left);
assert_reference(&assignment.right);

// Lastly, assert the type the lhs references matches with the rhs
let type_lhs = context.annotations.get_type_or_void(&assignment.left, context.index);
let type_rhs = context.annotations.get_type_or_void(&assignment.right, context.index);
let type_info_lhs = context.index.find_elementary_pointer_type(type_lhs.get_type_information());
let type_info_rhs = context.index.find_elementary_pointer_type(type_rhs.get_type_information());
let annotation_lhs = context.annotations.get(&assignment.left);

// Assert that the right-hand side is a reference
if !assignment.right.is_reference() {
validator.push_diagnostic(
Diagnostic::new("Invalid assignment, expected a reference")
.with_location(&assignment.right.location)
.with_error_code("E098"),
);
}

// Assert that the left-hand side is a valid pointer-reference
if !annotation_lhs.is_some_and(StatementAnnotation::is_reference_to) && !type_lhs.is_pointer() {
validator.push_diagnostic(
Diagnostic::new("Invalid assignment, expected a pointer reference")
.with_location(&assignment.left.location)
.with_error_code("E098"),
)
}

if type_info_lhs.is_array() && type_info_rhs.is_array() {
let mut messages = Vec::new();

let len_lhs = type_info_lhs.get_array_length(context.index).unwrap_or_default();
let len_rhs = type_info_rhs.get_array_length(context.index).unwrap_or_default();

if len_lhs < len_rhs {
messages.push(format!("Invalid assignment, array lengths {len_lhs} and {len_rhs} differ"));
}

let inner_ty_name_lhs = type_info_lhs.get_inner_array_type_name().unwrap_or(VOID_TYPE);
let inner_ty_name_rhs = type_info_rhs.get_inner_array_type_name().unwrap_or(VOID_TYPE);
let inner_ty_lhs = context.index.find_effective_type_by_name(inner_ty_name_lhs);
let inner_ty_rhs = context.index.find_effective_type_by_name(inner_ty_name_rhs);

if inner_ty_lhs != inner_ty_rhs {
messages.push(format!(
"Invalid assignment, array types {inner_ty_name_lhs} and {inner_ty_name_rhs} differ"
));
}

for message in messages {
validator.push_diagnostic(
Diagnostic::new(message).with_location(assignment_location).with_error_code("E098"),
)
}

return;
}

if type_info_lhs != type_info_rhs {
validator.push_diagnostic(
Expand Down
Loading

0 comments on commit b60bc18

Please sign in to comment.