Skip to content

Commit 28de27b

Browse files
extract fn arg mutable reference validation logic
1 parent 5fd0ce0 commit 28de27b

File tree

2 files changed

+24
-15
lines changed

2 files changed

+24
-15
lines changed

soroban-sdk-macros/src/derive_fn.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::{
2-
attribute::pass_through_attr_to_gen_code, map_type::map_type, syn_ext::ty_to_safe_ident_str,
2+
attribute::pass_through_attr_to_gen_code,
3+
map_type::map_type,
4+
syn_ext::{fn_arg_type_validate_no_mut, ty_to_safe_ident_str},
35
};
46
use itertools::MultiUnzip;
57
use proc_macro2::TokenStream as TokenStream2;
@@ -63,6 +65,11 @@ pub fn derive_pub_fn(
6365
// signature_payload of type Bytes (32 size), to be a Hash.
6466
let allow_hash = ident == "__check_auth" && i == 0;
6567

68+
// Error if the type of the fn arg is mutable.
69+
if let Err(e) = fn_arg_type_validate_no_mut(&pat_ty.ty) {
70+
errors.push(e);
71+
}
72+
6673
// Error if the type of the fn is not mappable.
6774
if let Err(e) = map_type(&pat_ty.ty, true, allow_hash) {
6875
errors.push(e);
@@ -84,20 +91,7 @@ pub fn derive_pub_fn(
8491
let passthrough_call = quote! { #ident };
8592

8693
let call_prefix = match *pat_ty.ty {
87-
// Disallow &mut because it is semantically confusing for a contract function
88-
// to receive an input that would mutate a value coming from outside the
89-
// program.
90-
Type::Reference(TypeReference { mutability: Some(_), .. }) => {
91-
errors.push(syn::Error::new(
92-
pat_ty.ty.span(),
93-
"mutable references (&mut) are not supported in contract function parameters, use immutable references (&) instead",
94-
));
95-
quote!(&)
96-
}
97-
// Allow & because it is convenient to be able to define contract functions
98-
// with borrowed parameters.
99-
Type::Reference(TypeReference { mutability: None, .. }) => quote!(&),
100-
// Any other parameter type doesn't need a call prefix.
94+
Type::Reference(TypeReference { .. }) => quote!(&),
10195
_ => quote!(),
10296
};
10397
let call = quote! {

soroban-sdk-macros/src/syn_ext.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,21 @@ pub fn fn_arg_ident(arg: &FnArg) -> Result<Ident, Error> {
4848
))
4949
}
5050

51+
/// Validate that the function argument type is not a mutable reference.
52+
///
53+
/// Returns an error indicating that contract functions arguments cannot be a mutable reference.
54+
/// Even though reference (&) are supported, mutable references (&mut) are not, because it is
55+
/// semanatically confusing for a contract function to receive an external input that it looks like
56+
/// it could mutate.
57+
pub fn fn_arg_type_validate_no_mut(ty: &Type) -> Result<(), Error> {
58+
match ty {
59+
Type::Reference(TypeReference { mutability: Some(_), .. }) => {
60+
Err(Error::new(ty.span(), "mutable references (&mut) are not supported in contract function parameters, use immutable references (&) instead"))
61+
}
62+
_ => Ok(()),
63+
}
64+
}
65+
5166
/// Modifies a Pat removing any 'mut' on an Ident.
5267
pub fn pat_unwrap_mut(p: Pat) -> Pat {
5368
match p {

0 commit comments

Comments
 (0)