diff --git a/crates/analyzer/src/traversal/expressions.rs b/crates/analyzer/src/traversal/expressions.rs index 59479052c1..97ee3a7446 100644 --- a/crates/analyzer/src/traversal/expressions.rs +++ b/crates/analyzer/src/traversal/expressions.rs @@ -1654,10 +1654,9 @@ fn expr_call_method( method: *method, generic_type: inner, }, - ty => { + _ => { let method = method.function(context.db()).unwrap(); - - if let Type::SPtr(inner) = ty { + if let Type::SPtr(inner) = target_attributes.typ.typ(context.db()) { if matches!( inner.typ(context.db()), Type::Struct(_) | Type::Tuple(_) | Type::Array(_) diff --git a/crates/analyzer/tests/errors.rs b/crates/analyzer/tests/errors.rs index 1e109116e3..426aa833b1 100644 --- a/crates/analyzer/tests/errors.rs +++ b/crates/analyzer/tests/errors.rs @@ -319,6 +319,8 @@ test_file! { init_call_on_external_contract } test_file! { call_wrong_return_type } test_file! { call_duplicate_def } test_file! { call_call_on_self } + +test_file! { call_method_in_storage } test_file! { call_call_on_external_contract } test_file! { call_with_pub_fns } test_file! { abi_encode_u256 } diff --git a/crates/analyzer/tests/snapshots/errors__call_method_in_storage.snap b/crates/analyzer/tests/snapshots/errors__call_method_in_storage.snap new file mode 100644 index 0000000000..21fc94c7db --- /dev/null +++ b/crates/analyzer/tests/snapshots/errors__call_method_in_storage.snap @@ -0,0 +1,14 @@ +--- +source: crates/analyzer/tests/errors.rs +assertion_line: 323 +expression: "error_string(&path, test_files::fixture(path))" +--- +error: struct functions can only be called on struct in memory + ┌─ compile_errors/call_method_in_storage.fe:16:9 + │ +16 │ self.bar.get_x() + │ ^^^^^^^^ ----- hint: copy the struct to memory with `.to_mem()` + │ │ + │ this value is in storage + + diff --git a/crates/test-files/fixtures/compile_errors/call_method_in_storage.fe b/crates/test-files/fixtures/compile_errors/call_method_in_storage.fe new file mode 100644 index 0000000000..ddeb3b3820 --- /dev/null +++ b/crates/test-files/fixtures/compile_errors/call_method_in_storage.fe @@ -0,0 +1,18 @@ +struct Bar { + pub x: u256 + + pub fn get_x(self) -> u256{ + return self.x + } +} + +contract Foo { + bar: Bar + + pub fn __init__(mut self) { + self.bar = Bar( x: 2 ) + } + fn yay(self) { + self.bar.get_x() + } +} diff --git a/newsfragments/881.bugfix.md b/newsfragments/881.bugfix.md new file mode 100644 index 0000000000..e40454ed75 --- /dev/null +++ b/newsfragments/881.bugfix.md @@ -0,0 +1,26 @@ +Fixed a regression where the compiler would not reject a method call on a struct in storage. + +E.g. the follwing code should be rejected as it is missing a `to_mem()` call: + +``` +struct Bar { + pub x: u256 + + pub fn get_x(self) -> u256{ + return self.x + } +} + +contract Foo { + bar: Bar + + pub fn __init__(mut self) { + self.bar = Bar( x: 2 ) + } + fn yay(self) { + self.bar.get_x() + } +} +``` + +The compiler will now reject the code and suggest a `to_mem()` before calling`get_x()`.