Skip to content

Commit a991a8c

Browse files
committed
polish
1 parent 1cccae8 commit a991a8c

File tree

9 files changed

+60
-65
lines changed

9 files changed

+60
-65
lines changed
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
# Invalid REF= assignment
22

3-
For `REF=` to be valid, the left-hand side of the assignment must be a variable declared
4-
with the `REFERENCE TO` keyword and the right hand side must be a variable of the type
5-
that is being referenced.
3+
`REF=` assignments are considered valid if the left-hand side of the assignment is a variable declared
4+
with `REFERENCE TO` and the right-hand side is a variable of the type that is being referenced.
65

76
For example assignments such as the following are invalid
87

98
```smalltalk
109
VAR
1110
foo : DINT;
1211
bar : DINT;
12+
qux : SINT;
1313
refFoo : REFERENCE TO DINT;
1414
END_VAR
1515
1616
refFoo REF= 5; // `5` is not a variable
1717
foo REF= bar; // `foo` is not declared with `REFERENCE TO`
18+
refFoo REF= qux; // `refFoo` and `qux` have different types, DINT vs SINT
1819
refFoo REF= refFoo; // pointing to oneself doesn't make sense
1920
```
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
# Invalid `REFERENCE TO` declaration
1+
# Invalid `REFERENCE TO` declaration
2+
3+
`REFERENCE TO` variable declarations are considered valid if the referenced type is not a
4+
* array, e.g. `foo : REFERENCE TO ARRAY[1..5] OF DINT`
5+
* pointer, e.g. `foo : REFERENCE TO REF_TO DINT`
6+
* reference, e.g. `foo : REFERENCE TO bar`
7+
8+
and furthermore are not initialized in their declaration, e.g. `foo : REFERENCE TO DINT := bar`.

src/codegen/generators/statement_generator.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,12 +236,13 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> {
236236
}
237237
}
238238

239-
/// Generates IR for a `REF=` assignment, which is syntactic sugar for a `REF(...)` call on the
240-
/// right side of an assignment. Specifically `foo REF= bar` and `foo := REF(bar)` are the same.
239+
/// Generates IR for a `REF=` assignment, which is syntactic sugar for an assignment where the
240+
/// right-hand side is wrapped in a `REF(...)` call. Specifically `foo REF= bar` and
241+
/// `foo := REF(bar)` are the same.
241242
///
242-
/// Note: Though somewhat similar to the [`generate_assignment_statement`] function, we can't
243-
/// directly call it here because the left side of a `REF=` assignment is flagged as auto-deref
244-
/// but for `REF=` assignment we don't want (and can't) deref without generating incorrect IR.:w
243+
/// Note: Although somewhat similar to the [`generate_assignment_statement`] function, we can't
244+
/// 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
245246
pub fn generate_ref_assignment(&self, left: &AstNode, right: &AstNode) -> Result<(), Diagnostic> {
246247
let exp = self.create_expr_generator();
247248
let ref_builtin = self.index.get_builtin_function("REF").expect("REF must exist");

src/codegen/tests/statement_codegen_test.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -217,33 +217,41 @@ fn ref_assignment() {
217217

218218
#[test]
219219
fn reference_to_assignment() {
220-
let result = codegen(
220+
let auto_deref = codegen(
221221
r#"
222222
FUNCTION main
223223
VAR
224224
a : REFERENCE TO DINT;
225-
b : REF_TO DINT;
226225
END_VAR
227226
a := 5;
228-
b^ := 5;
229227
END_FUNCTION
230228
"#,
231229
);
232230

233-
insta::assert_snapshot!(result, @r###"
231+
let manual_deref = codegen(
232+
r#"
233+
FUNCTION main
234+
VAR
235+
a : REF_TO DINT;
236+
END_VAR
237+
a^ := 5;
238+
END_FUNCTION
239+
"#,
240+
);
241+
242+
// We want to assert that `a := 5` and `a^ := 5` yield identical IR
243+
assert_eq!(auto_deref, manual_deref);
244+
//
245+
insta::assert_snapshot!(auto_deref, @r###"
234246
; ModuleID = 'main'
235247
source_filename = "main"
236248
237249
define void @main() section "fn-$RUSTY$main:v" {
238250
entry:
239251
%a = alloca i32*, align 8
240-
%b = alloca i32*, align 8
241252
store i32* null, i32** %a, align 8
242-
store i32* null, i32** %b, align 8
243253
%deref = load i32*, i32** %a, align 8
244254
store i32 5, i32* %deref, align 4
245-
%deref1 = load i32*, i32** %b, align 8
246-
store i32 5, i32* %deref1, align 4
247255
ret void
248256
}
249257
"###);

src/typesystem.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ mod tests;
9696
#[derive(Debug, Clone)]
9797
pub struct DataType {
9898
pub name: String,
99-
/// the initial value defined on the TYPE-declration
99+
/// the initial value defined on the TYPE-declaration
100100
pub initial_value: Option<ConstId>,
101101
pub information: DataTypeInformation,
102102
pub nature: TypeNature,

src/validation/statement.rs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,6 @@ fn validate_call_by_ref(validator: &mut Validator, param: &VariableIndexEntry, a
769769
}
770770
}
771771

772-
// TODO: Improve error messages?
773772
/// Checks if `REF=` assignments are correct, specifically if the left-hand side is a reference declared
774773
/// as `REFERENCE TO` and the right hand side is a lvalue of the same type that is being referenced.
775774
fn validate_ref_assignment<T: AnnotationMap>(
@@ -778,24 +777,6 @@ fn validate_ref_assignment<T: AnnotationMap>(
778777
assignment: &Assignment,
779778
assignment_location: &SourceLocation,
780779
) {
781-
// // Assert that the lhs is a variable declared with `REFERENCE TO`
782-
// if !context.annotations.get(&assignment.left).is_some_and(StatementAnnotation::is_reference_to) {
783-
// validator.push_diagnostic(
784-
// Diagnostic::new("Invalid assignment, expected a variable declared with `REFERENCE TO`")
785-
// .with_location(&assignment.left.location)
786-
// .with_error_code("E098"),
787-
// );
788-
// }
789-
790-
// // Assert that the rhs is NOT a variable declared with `REFERENCE TO`
791-
// if context.annotations.get(&assignment.right).is_some_and(StatementAnnotation::is_reference_to) {
792-
// validator.push_diagnostic(
793-
// Diagnostic::new("Invalid assignment, variable must not be declared with `REFERENCE TO`")
794-
// .with_location(&assignment.right.location)
795-
// .with_error_code("E098"),
796-
// );
797-
// }
798-
799780
// Assert that the rhs is a variable that can be referenced
800781
if !assignment.right.is_reference() {
801782
validator.push_diagnostic(
@@ -812,7 +793,7 @@ fn validate_ref_assignment<T: AnnotationMap>(
812793
if type_lhs != type_rhs {
813794
validator.push_diagnostic(
814795
Diagnostic::new(format!(
815-
"Invalid assignment, types differ (got {} and {})",
796+
"Invalid assignment, types {} and {} differ",
816797
get_datatype_name_or_slice(validator.context, type_lhs),
817798
get_datatype_name_or_slice(validator.context, type_rhs),
818799
))

src/validation/tests/assignment_validation_tests.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,9 +1218,8 @@ fn void_assignment_validation() {
12181218
"###)
12191219
}
12201220

1221-
// TODO: Think of an edge-case here, some variable that has the auto-deref trait on which
12221221
#[test]
1223-
fn ref_assignment() {
1222+
fn reference_to_variables_and_ref_assignments() {
12241223
let diagnostics = parse_and_validate_buffered(
12251224
"
12261225
TYPE
@@ -1259,46 +1258,46 @@ fn ref_assignment() {
12591258
);
12601259

12611260
assert_snapshot!(diagnostics, @r###"
1262-
error[E099]: Invalid type, reference
1261+
error[E099]: REFERENCE TO variables can not reference other variables
12631262
┌─ <internal>:18:55
12641263
12651264
18 │ referenceToFooInitializedVariable : REFERENCE TO foo;
1266-
│ ^^^^^^^^^^^^^^^^ Invalid type, reference
1265+
│ ^^^^^^^^^^^^^^^^ REFERENCE TO variables can not reference other variables
12671266
1268-
error[E099]: Invalid type, reference
1267+
error[E099]: REFERENCE TO variables can not reference other variables
12691268
┌─ <internal>:19:55
12701269
12711270
19 │ referenceToFooGlobalVariable : REFERENCE TO fooGlobal;
1272-
│ ^^^^^^^^^^^^^^^^^^^^^^ Invalid type, reference
1271+
│ ^^^^^^^^^^^^^^^^^^^^^^ REFERENCE TO variables can not reference other variables
12731272
1274-
error[E099]: Invalid type: array, pointer or bit
1273+
error[E099]: REFERENCE TO variables can not reference arrays, pointers or bits
12751274
┌─ <internal>:21:17
12761275
12771276
4 │ AliasedArray : ARRAY[1..5] OF DINT;
12781277
│ ------------ see also
12791278
·
12801279
21 │ referenceToFooAliasedArrayType : REFERENCE TO AliasedArray;
1281-
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Invalid type: array, pointer or bit
1280+
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ REFERENCE TO variables can not reference arrays, pointers or bits
12821281
1283-
error[E099]: REFERENCE TO variables can not be initialized in their declaration
1282+
error[E099]: Initializations of REFERENCE TO variables are disallowed
12841283
┌─ <internal>:22:76
12851284
12861285
22 │ referenceToFooInitializedLiteral : REFERENCE TO DINT := 5;
1287-
│ ^ REFERENCE TO variables can not be initialized in their declaration
1286+
│ ^ Initializations of REFERENCE TO variables are disallowed
12881287
1289-
error[E099]: Invalid type: array, pointer or bit
1288+
error[E099]: REFERENCE TO variables can not reference arrays, pointers or bits
12901289
┌─ <internal>:23:17
12911290
12921291
23 │ referenceToFooInitializedArray : REFERENCE TO ARRAY[1..5] OF DINT;
12931292
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -------------------------------- see also
12941293
│ │
1295-
Invalid type: array, pointer or bit
1294+
REFERENCE TO variables can not reference arrays, pointers or bits
12961295
1297-
error[E098]: Invalid assignment, types differ (got REF_TO DINT and DINT)
1296+
error[E098]: Invalid assignment, types REF_TO DINT and DINT differ
12981297
┌─ <internal>:30:13
12991298
13001299
30 │ refToFoo REF= foo;
1301-
│ ^^^^^^^^^^^^^^^^^ Invalid assignment, types differ (got REF_TO DINT and DINT)
1300+
│ ^^^^^^^^^^^^^^^^^ Invalid assignment, types REF_TO DINT and DINT differ
13021301
13031302
error[E098]: Invalid assignment, expected a reference
13041303
┌─ <internal>:31:33

src/validation/tests/snapshots/rusty__validation__tests__variable_validation_tests__constant_fb_instances_are_illegal.snap

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@
22
source: src/validation/tests/variable_validation_tests.rs
33
expression: "&diagnostics"
44
---
5-
error[E035]: Invalid constant y - Functionblock- and Class-instances cannot be delcared constant
5+
error[E035]: Invalid constant y, FUNCTION_BLOCK- and CLASS-instances cannot be declared constant
66
┌─ <internal>:15:13
77
88
15 │ y : MyFb;
9-
│ ^ Invalid constant y - Functionblock- and Class-instances cannot be delcared constant
9+
│ ^ Invalid constant y, FUNCTION_BLOCK- and CLASS-instances cannot be declared constant
1010

11-
error[E035]: Invalid constant z - Functionblock- and Class-instances cannot be delcared constant
11+
error[E035]: Invalid constant z, FUNCTION_BLOCK- and CLASS-instances cannot be declared constant
1212
┌─ <internal>:16:13
1313
1414
16 │ z : cls;
15-
│ ^ Invalid constant z - Functionblock- and Class-instances cannot be delcared constant
16-
17-
15+
│ ^ Invalid constant z, FUNCTION_BLOCK- and CLASS-instances cannot be declared constant

src/validation/variable.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ fn validate_variable<T: AnnotationMap>(
200200
{
201201
validator.push_diagnostic(
202202
Diagnostic::new(format!(
203-
"Invalid constant {} - Functionblock- and Class-instances cannot be delcared constant",
203+
"Invalid constant {}, FUNCTION_BLOCK- and CLASS-instances cannot be declared constant",
204204
v_entry.get_name()
205205
))
206206
.with_error_code("E035")
@@ -228,7 +228,7 @@ fn validate_reference_to_declaration<T: AnnotationMap>(
228228
if let Some(ref initializer) = variable.initializer {
229229
if variable_type.get_type_information().is_reference_to() {
230230
validator.push_diagnostic(
231-
Diagnostic::new("REFERENCE TO variables can not be initialized in their declaration")
231+
Diagnostic::new("Initializations of REFERENCE TO variables are disallowed")
232232
.with_location(&initializer.location)
233233
.with_error_code("E099"),
234234
);
@@ -237,12 +237,12 @@ fn validate_reference_to_declaration<T: AnnotationMap>(
237237

238238
// Assert that the referenced type is no variable reference
239239
let qualifier = context.qualifier.unwrap_or_default();
240-
let var_local = context.index.find_member(qualifier, inner_type_name).is_some();
241-
let var_global = context.index.find_global_variable(inner_type_name).is_some();
240+
let inner_ty_is_local_var = context.index.find_member(qualifier, inner_type_name).is_some();
241+
let inner_ty_is_global_var = context.index.find_global_variable(inner_type_name).is_some();
242242

243-
if var_local || var_global {
243+
if inner_ty_is_local_var || inner_ty_is_global_var {
244244
validator.push_diagnostic(
245-
Diagnostic::new("Invalid type, reference")
245+
Diagnostic::new("REFERENCE TO variables can not reference other variables")
246246
.with_location(&variable_type.location)
247247
.with_error_code("E099"),
248248
);
@@ -253,7 +253,7 @@ fn validate_reference_to_declaration<T: AnnotationMap>(
253253
if let Some(ty) = inner_type {
254254
if ty.is_array() || ty.is_pointer() || ty.is_bit() {
255255
validator.push_diagnostic(
256-
Diagnostic::new("Invalid type: array, pointer or bit ")
256+
Diagnostic::new("REFERENCE TO variables can not reference arrays, pointers or bits")
257257
.with_location(&variable.location)
258258
.with_secondary_location(&ty.location)
259259
.with_error_code("E099"),

0 commit comments

Comments
 (0)