-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add additional pointer and type validations #1341
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
# Unknown type | ||
|
||
Use of undeclared type-identifier. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -746,6 +746,7 @@ fn parse_pointer_definition( | |
( | ||
DataTypeDeclaration::DataTypeDefinition { | ||
data_type: DataType::PointerType { name, referenced_type: Box::new(decl), auto_deref }, | ||
// FIXME: this currently includes the initializer in the sourcelocation, resulting in 'REF_TO A := B' when creating a slice | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we track this on GitHub instead in the code itself? I feel like these FIXMEs are easily forgotten There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, I've already set up a draft for this issue - just need to add a reproducible example. |
||
location: lexer.source_range_factory.create_range(start_pos..lexer.last_range.end), | ||
scope: lexer.scope.clone(), | ||
}, | ||
|
@@ -772,14 +773,15 @@ fn parse_type_reference_type_definition( | |
None | ||
}; | ||
|
||
let initial_value = | ||
let end = lexer.last_range.end; | ||
|
||
let initial_value: Option<AstNode> = | ||
if lexer.try_consume(&KeywordAssignment) || lexer.try_consume(&KeywordReferenceAssignment) { | ||
Some(parse_expression(lexer)) | ||
} else { | ||
None | ||
}; | ||
|
||
let end = lexer.last_range.end; | ||
if name.is_some() || bounds.is_some() { | ||
let data_type = match bounds { | ||
Some(AstNode { stmt: AstStatement::ExpressionList(expressions), id, location }) => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -719,6 +719,117 @@ fn unresolved_references_to_const_builtins_in_initializer_are_reported() { | |
"###); | ||
} | ||
|
||
#[test] | ||
fn unknown_types_are_reported() { | ||
let diagnostics = parse_and_validate_buffered( | ||
r#" | ||
VAR_GLOBAL | ||
a: undefined; | ||
END_VAR | ||
"#, | ||
); | ||
|
||
assert_snapshot!(diagnostics, @r###" | ||
error[E052]: Unknown type: undefined | ||
┌─ <internal>:3:16 | ||
│ | ||
3 │ a: undefined; | ||
│ ^^^^^^^^^ Unknown type: undefined | ||
|
||
"###); | ||
} | ||
|
||
#[test] | ||
fn aliases_are_not_reported_as_unknown_types() { | ||
let diagnostics = parse_and_validate_buffered( | ||
r#" | ||
TYPE myDeclaredType : DINT; END_TYPE | ||
VAR_GLOBAL | ||
a: myDeclaredType; | ||
END_VAR | ||
"#, | ||
); | ||
|
||
assert!(diagnostics.is_empty()) | ||
} | ||
|
||
#[test] | ||
fn aliasing_to_undeclared_type_is_an_error() { | ||
let diagnostics = parse_and_validate_buffered( | ||
r#" | ||
TYPE myDeclaredType : undeclaredType; END_TYPE | ||
VAR_GLOBAL | ||
a: myDeclaredType; | ||
END_VAR | ||
"#, | ||
); | ||
|
||
assert_snapshot!(diagnostics, @r###" | ||
error[E052]: Unknown type: myDeclaredType | ||
┌─ <internal>:4:16 | ||
│ | ||
4 │ a: myDeclaredType; | ||
│ ^^^^^^^^^^^^^^ Unknown type: myDeclaredType | ||
Comment on lines
+771
to
+772
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already talked about this yesterday offline, but the UX isn't good here; maybe we should also track this in a issue seperately and see if there's a solution to this (minor however) |
||
|
||
"###); | ||
} | ||
|
||
#[test] | ||
fn trying_to_initialize_a_pointer_of_unknown_type_is_reported() { | ||
let diagnostics = parse_and_validate_buffered( | ||
r#" | ||
VAR_GLOBAL | ||
a: undefined; | ||
END_VAR | ||
FUNCTION_BLOCK foo | ||
VAR | ||
bar : REF_TO undefined := REF(a); | ||
END_VAR | ||
END_FUNCTION_BLOCK | ||
"#, | ||
); | ||
|
||
assert_snapshot!(diagnostics, @r###" | ||
error[E052]: Unknown type: undefined | ||
┌─ <internal>:7:26 | ||
│ | ||
7 │ bar : REF_TO undefined := REF(a); | ||
│ ^^^^^^^^^ Unknown type: undefined | ||
|
||
error[E052]: Unknown type: undefined | ||
┌─ <internal>:3:16 | ||
│ | ||
3 │ a: undefined; | ||
│ ^^^^^^^^^ Unknown type: undefined | ||
|
||
"###); | ||
} | ||
|
||
#[test] | ||
fn trying_to_initialize_a_pointer_with_builtin_ref_with_type_mismatch_leads_to_error() { | ||
let diagnostics = parse_and_validate_buffered( | ||
r#" | ||
VAR_GLOBAL | ||
a: DINT; | ||
END_VAR | ||
FUNCTION_BLOCK foo | ||
VAR | ||
bar : REF_TO STRING := REF(a); | ||
END_VAR | ||
END_FUNCTION_BLOCK | ||
"#, | ||
); | ||
|
||
assert_snapshot!(diagnostics, @r###" | ||
error[E037]: Invalid assignment: cannot assign 'DINT' to 'REF_TO STRING := REF(a)' | ||
┌─ <internal>:7:36 | ||
│ | ||
7 │ bar : REF_TO STRING := REF(a); | ||
│ ^^^^^^ Invalid assignment: cannot assign 'DINT' to 'REF_TO STRING := REF(a)' | ||
|
||
"###); | ||
} | ||
|
||
#[test] | ||
fn unconfigured_template_variables_are_validated() { | ||
let diagnostics = parse_and_validate_buffered( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fixes a stack-overflow in
typesystem::is_same_type_class
when dealing with pointers of undefined type