Description
Currently, the compiler silently replaces calls to mutates
functions with their non-mutating counterparts when the receiver isn't recognized as an lvalue. This can unintentionally prevent expected state mutations.
Example (current behavior):
struct Data { n: Int }
contract Test {
d: Data? = null;
receive() {
self.d!!.n.inc(); // Developer expects mutation
}
}
extends mutates fun inc(self: Int) { self += 1 }
Generated FunC (non-mutating call):
$Int$_fun_inc$not_mut($Data$_get_n($Data$_not_null($self'd)));
This matches current compiler behavior but can mislead developers who expect mutations. The developer might not realize that their intended mutation isn't occurring due to using a non-lvalue receiver.
Suggested Improvement (for next major release):
Explicitly disallow calls to mutating functions (mutates
) with non-lvalue arguments. Instead of silently substituting a non-mutating variant, the compiler should clearly report an error or warning, informing developers that mutations require lvalue receivers.
LLM Fuzzing discovery (see #3123)