Skip to content

Commit 9a06f03

Browse files
authored
feat: Validate types in math operations (#1300)
Adds a validation to check if a math operation has incompatible types. For example the following code previously had no validation and as a consequence would panic during codegen. ``` FUNCTION main : DINT VAR x1 : ARRAY[0..2] OF TOD; x2 : STRING; END_VAR x1 + x2; ADD(x1, x1); DIV(x1, x2); SUB(x2, x2); END_FUNCTION ```
1 parent 05e623d commit 9a06f03

File tree

6 files changed

+294
-89
lines changed

6 files changed

+294
-89
lines changed

compiler/plc_diagnostics/src/diagnostics/diagnostics_registry.rs

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -102,30 +102,30 @@ impl From<&DiagnosticsRegistry> for DiagnosticsConfiguration {
102102
#[rustfmt::skip]
103103
lazy_static! {
104104
pub static ref DIAGNOSTICS: FxHashMap<&'static str, DiagnosticEntry> = add_diagnostic!(
105-
E001, Error, include_str!("./error_codes/E001.md"), //General Error
106-
E002, Error, include_str!("./error_codes/E002.md"), //General IO Error
107-
E003, Error, include_str!("./error_codes/E003.md"), //Parameter Error
108-
E004, Error, include_str!("./error_codes/E004.md"), //Duplicate Symbol
109-
E005, Error, include_str!("./error_codes/E005.md"), //Generic LLVM Error
110-
E006, Error, include_str!("./error_codes/E006.md"), //Missing Token
111-
E007, Error, include_str!("./error_codes/E007.md"), //Unexpected Token
112-
E008, Error, include_str!("./error_codes/E008.md"), //Invalid Range
113-
E009, Error, include_str!("./error_codes/E009.md"), //Mismatched Parantheses
114-
E010, Error, include_str!("./error_codes/E010.md"), //Invalid Time Literal
115-
E011, Error, include_str!("./error_codes/E011.md"), //Invalid Number
116-
E012, Error, include_str!("./error_codes/E012.md"), //Missing Case Condition
117-
E013, Warning, include_str!("./error_codes/E013.md"), //Keywords shoud contain underscores
118-
E014, Warning, include_str!("./error_codes/E014.md"), //Wrong parantheses type
119-
E015, Warning, include_str!("./error_codes/E015.md"), //Pointer is not standard
120-
E016, Warning, include_str!("./error_codes/E016.md"), //Return types cannot have a default value
121-
E017, Error, include_str!("./error_codes/E017.md"), //Classes cannot contain implementations
122-
E018, Error, include_str!("./error_codes/E018.md"), //Duplicate Label
123-
E019, Error, include_str!("./error_codes/E019.md"), //Classes cannot contain IN_OUT variables
124-
E020, Error, include_str!("./error_codes/E020.md"), //Classes cannot contain a return type
125-
E021, Error, include_str!("./error_codes/E021.md"), //POUs cannot be extended
126-
E022, Warning, include_str!("./error_codes/E022.md"), //Missing action container
127-
E023, Warning, include_str!("./error_codes/E023.md"), //Statement with no effect
128-
E024, Warning, include_str!("./error_codes/E024.md"), //Invalid pragma location
105+
E001, Error, include_str!("./error_codes/E001.md"), // General Error
106+
E002, Error, include_str!("./error_codes/E002.md"), // General IO Error
107+
E003, Error, include_str!("./error_codes/E003.md"), // Parameter Error
108+
E004, Error, include_str!("./error_codes/E004.md"), // Duplicate Symbol
109+
E005, Error, include_str!("./error_codes/E005.md"), // Generic LLVM Error
110+
E006, Error, include_str!("./error_codes/E006.md"), // Missing Token
111+
E007, Error, include_str!("./error_codes/E007.md"), // Unexpected Token
112+
E008, Error, include_str!("./error_codes/E008.md"), // Invalid Range
113+
E009, Error, include_str!("./error_codes/E009.md"), // Mismatched Parantheses
114+
E010, Error, include_str!("./error_codes/E010.md"), // Invalid Time Literal
115+
E011, Error, include_str!("./error_codes/E011.md"), // Invalid Number
116+
E012, Error, include_str!("./error_codes/E012.md"), // Missing Case Condition
117+
E013, Warning, include_str!("./error_codes/E013.md"), // Keywords shoud contain underscores
118+
E014, Warning, include_str!("./error_codes/E014.md"), // Wrong parantheses type
119+
E015, Warning, include_str!("./error_codes/E015.md"), // Pointer is not standard
120+
E016, Warning, include_str!("./error_codes/E016.md"), // Return types cannot have a default value
121+
E017, Error, include_str!("./error_codes/E017.md"), // Classes cannot contain implementations
122+
E018, Error, include_str!("./error_codes/E018.md"), // Duplicate Label
123+
E019, Error, include_str!("./error_codes/E019.md"), // Classes cannot contain IN_OUT variables
124+
E020, Error, include_str!("./error_codes/E020.md"), // Classes cannot contain a return type
125+
E021, Error, include_str!("./error_codes/E021.md"), // POUs cannot be extended
126+
E022, Warning, include_str!("./error_codes/E022.md"), // Missing action container
127+
E023, Warning, include_str!("./error_codes/E023.md"), // Statement with no effect
128+
E024, Warning, include_str!("./error_codes/E024.md"), // Invalid pragma location
129129
E025, Error, include_str!("./error_codes/E025.md"), // Missing return type
130130
E026, Error, include_str!("./error_codes/E026.md"),
131131
E027, Error, include_str!("./error_codes/E027.md"),
@@ -139,16 +139,16 @@ lazy_static! {
139139
E035, Error, include_str!("./error_codes/E035.md"),
140140
E036, Error, include_str!("./error_codes/E036.md"),
141141
E037, Error, include_str!("./error_codes/E037.md"),
142-
E038, Error, include_str!("./error_codes/E038.md"), //Missing type
142+
E038, Error, include_str!("./error_codes/E038.md"), // Missing type
143143
E039, Warning, include_str!("./error_codes/E039.md"),
144144
E040, Error, include_str!("./error_codes/E040.md"),
145145
E041, Error, include_str!("./error_codes/E041.md"),
146-
E042, Warning, include_str!("./error_codes/E042.md"), //Assignment to reference
146+
E042, Warning, include_str!("./error_codes/E042.md"), // Assignment to reference
147147
E043, Error, include_str!("./error_codes/E043.md"),
148148
E044, Error, include_str!("./error_codes/E044.md"),
149149
E045, Error, include_str!("./error_codes/E045.md"),
150150
E046, Error, include_str!("./error_codes/E046.md"),
151-
E047, Warning, include_str!("./error_codes/E047.md"), //VLAs are always by reference
151+
E047, Warning, include_str!("./error_codes/E047.md"), // VLAs are always by reference
152152
E048, Error, include_str!("./error_codes/E048.md"),
153153
E049, Error, include_str!("./error_codes/E049.md"),
154154
E050, Error, include_str!("./error_codes/E050.md"),
@@ -161,14 +161,14 @@ lazy_static! {
161161
E057, Error, include_str!("./error_codes/E057.md"),
162162
E058, Error, include_str!("./error_codes/E058.md"),
163163
E059, Error, include_str!("./error_codes/E059.md"),
164-
E060, Info, include_str!("./error_codes/E060.md"), //Variable direct access with %
164+
E060, Info, include_str!("./error_codes/E060.md"), // Variable direct access with %
165165
E061, Error, include_str!("./error_codes/E061.md"),
166166
E062, Error, include_str!("./error_codes/E062.md"),
167167
E063, Error, include_str!("./error_codes/E063.md"),
168168
E064, Error, include_str!("./error_codes/E064.md"),
169169
E065, Error, include_str!("./error_codes/E065.md"),
170170
E066, Error, include_str!("./error_codes/E066.md"),
171-
E067, Warning, include_str!("./error_codes/E067.md"), //Implicit typecast
171+
E067, Warning, include_str!("./error_codes/E067.md"), // Implicit typecast
172172
E068, Error, include_str!("./error_codes/E068.md"),
173173
E069, Error, include_str!("./error_codes/E069.md"),
174174
E070, Error, include_str!("./error_codes/E070.md"),
@@ -191,17 +191,17 @@ lazy_static! {
191191
E087, Error, include_str!("./error_codes/E087.md"),
192192
E088, Error, include_str!("./error_codes/E088.md"),
193193
E089, Error, include_str!("./error_codes/E089.md"),
194-
E090, Warning, include_str!("./error_codes/E090.md"), //Incompatible reference Assignment
194+
E090, Warning, include_str!("./error_codes/E090.md"), // Incompatible reference Assignment
195195
E091, Warning, include_str!("./error_codes/E091.md"),
196196
E092, Info, include_str!("./error_codes/E092.md"),
197197
E093, Warning, include_str!("./error_codes/E093.md"),
198198
E094, Error, include_str!("./error_codes/E094.md"),
199-
E095, Error, include_str!("./error_codes/E095.md"), // Action call without `()`
200-
E096, Warning, include_str!("./error_codes/E096.md"), // Integer Condition
201-
E097, Error, include_str!("./error_codes/E097.md"), // Invalid Array Range
202-
E098, Error, include_str!("./error_codes/E098.md"), // Invalid `REF=` assignment
203-
E099, Error, include_str!("./error_codes/E099.md"), // Invalid `REFERENCE TO` declaration
204-
E100, Error, include_str!("./error_codes/E100.md"), // Immutable variable address
199+
E095, Error, include_str!("./error_codes/E095.md"), // Action call without `()`
200+
E096, Warning, include_str!("./error_codes/E096.md"), // Integer Condition
201+
E097, Error, include_str!("./error_codes/E097.md"), // Invalid Array Range
202+
E098, Error, include_str!("./error_codes/E098.md"), // Invalid `REF=` assignment
203+
E099, Error, include_str!("./error_codes/E099.md"), // Invalid `REFERENCE TO` declaration
204+
E100, Error, include_str!("./error_codes/E100.md"), // Immutable variable address
205205
);
206206
}
207207

src/builtins.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::{
2626
AnnotationMap, StatementAnnotation, TypeAnnotator, VisitorContext,
2727
},
2828
typesystem::{self, get_bigger_type, get_literal_actual_signed_type_name, DataTypeInformationProvider},
29-
validation::{Validator, Validators},
29+
validation::{statement::validate_type_compatibility, Validator, Validators},
3030
};
3131

3232
// Defines a set of functions that are always included in a compiled application
@@ -332,8 +332,9 @@ lazy_static! {
332332

333333
annotate_arithmetic_function(annotator, statement, operator, params, ctx, Operator::Plus)
334334
}),
335-
validation:Some(|validator, operator, parameters, _, _| {
336-
validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Plus)
335+
validation:Some(|validator, operator, parameters, annotations, index| {
336+
validate_types(validator, &parameters, annotations, index);
337+
validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Plus);
337338
}),
338339
generic_name_resolver,
339340
code: |_, _, _| {
@@ -357,7 +358,8 @@ lazy_static! {
357358

358359
annotate_arithmetic_function(annotator, statement, operator, params, ctx, Operator::Multiplication)
359360
}),
360-
validation: Some(|validator, operator, parameters, _, _| {
361+
validation: Some(|validator, operator, parameters, annotations, index| {
362+
validate_types(validator, &parameters, annotations, index);
361363
validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Multiplication)
362364
}),
363365
generic_name_resolver,
@@ -382,7 +384,8 @@ lazy_static! {
382384
};
383385
annotate_arithmetic_function(annotator, statement, operator, params, ctx, Operator::Minus)
384386
}),
385-
validation:Some(|validator, operator, parameters, _, _| {
387+
validation:Some(|validator, operator, parameters, annotations, index| {
388+
validate_types(validator, &parameters, annotations, index);
386389
validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Minus)
387390
}),
388391
generic_name_resolver,
@@ -407,7 +410,8 @@ lazy_static! {
407410
};
408411
annotate_arithmetic_function(annotator, statement, operator, params, ctx, Operator::Division)
409412
}),
410-
validation:Some(|validator, operator, parameters, _, _| {
413+
validation:Some(|validator, operator, parameters, annotations, index| {
414+
validate_types(validator, &parameters, annotations, index);
411415
validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Division)
412416
}),
413417
generic_name_resolver,
@@ -565,6 +569,24 @@ lazy_static! {
565569
]);
566570
}
567571

572+
fn validate_types(
573+
validator: &mut Validator,
574+
parameters: &Option<&AstNode>,
575+
annotations: &dyn AnnotationMap,
576+
index: &Index,
577+
) {
578+
let Some(params) = parameters else { return };
579+
580+
let types = flatten_expression_list(params);
581+
let mut types = types.iter().peekable();
582+
583+
while let Some(left) = types.next() {
584+
if let Some(right) = types.peek() {
585+
validate_type_compatibility(validator, annotations, index, left, right);
586+
}
587+
}
588+
}
589+
568590
fn validate_builtin_symbol_parameter_count(
569591
validator: &mut Validator,
570592
operator: &AstNode,

src/validation.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
Index, PouIndexEntry,
1010
},
1111
resolver::AnnotationMap,
12+
typesystem::DataType,
1213
};
1314

1415
use self::{
@@ -23,7 +24,7 @@ mod array;
2324
mod global;
2425
mod pou;
2526
mod recursive;
26-
mod statement;
27+
pub(crate) mod statement;
2728
mod types;
2829
mod variable;
2930

@@ -129,6 +130,14 @@ impl<'a> Validator<'a> {
129130
}
130131
}
131132

133+
pub fn get_type_name_or_slice(&self, dt: &DataType) -> String {
134+
if dt.is_internal() {
135+
return dt.get_type_information().get_inner_name().to_string();
136+
}
137+
138+
self.context.slice(&dt.location)
139+
}
140+
132141
pub fn diagnostics(&mut self) -> Vec<Diagnostic> {
133142
let mut all_diagnostics = Vec::new();
134143
all_diagnostics.append(&mut self.take_diagnostics());

0 commit comments

Comments
 (0)