diff --git a/sway-core/src/language/ty/declaration/declaration.rs b/sway-core/src/language/ty/declaration/declaration.rs index a4888f5c405..c766d336fd0 100644 --- a/sway-core/src/language/ty/declaration/declaration.rs +++ b/sway-core/src/language/ty/declaration/declaration.rs @@ -385,6 +385,7 @@ impl DisplayWithEngines for TyDecl { match mutability { VariableMutability::Mutable => builder.push_str("mut"), VariableMutability::RefMutable => builder.push_str("ref mut"), + VariableMutability::RefImmutable => builder.push_str("ref"), VariableMutability::Immutable => {} } builder.push_str(name.as_str()); @@ -441,6 +442,7 @@ impl DebugWithEngines for TyDecl { match mutability { VariableMutability::Mutable => builder.push_str("mut"), VariableMutability::RefMutable => builder.push_str("ref mut"), + VariableMutability::RefImmutable => builder.push_str("ref"), VariableMutability::Immutable => {} } builder.push_str(name.as_str()); diff --git a/sway-core/src/language/ty/variable_mutability.rs b/sway-core/src/language/ty/variable_mutability.rs index b1831af1279..6dd564d760b 100644 --- a/sway-core/src/language/ty/variable_mutability.rs +++ b/sway-core/src/language/ty/variable_mutability.rs @@ -7,6 +7,8 @@ pub enum VariableMutability { Mutable, // referenceable + mutable RefMutable, + // referenceable + immutable + RefImmutable, // immutable #[default] Immutable, @@ -14,8 +16,10 @@ pub enum VariableMutability { impl VariableMutability { pub fn new_from_ref_mut(is_reference: bool, is_mutable: bool) -> VariableMutability { - if is_reference { + if is_reference && is_mutable { VariableMutability::RefMutable + } else if is_reference { + VariableMutability::RefImmutable } else if is_mutable { VariableMutability::Mutable } else { diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs index 288b068983e..1aa3c259d37 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs @@ -216,9 +216,11 @@ fn unify_arguments_and_parameters( } // check for matching mutability - let param_mutability = - ty::VariableMutability::new_from_ref_mut(param.is_reference, param.is_mutable); - if arg.gather_mutability().is_immutable() && param_mutability.is_mutable() { + // Only ref mut params require mutable args. + if arg.gather_mutability().is_immutable() + && param.is_reference + && param.is_mutable + { handler.emit_err(CompileError::ImmutableArgumentToMutableParameter { span: arg.span.clone(), }); diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/Forc.lock new file mode 100644 index 00000000000..bf17bb8948f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/Forc.lock @@ -0,0 +1,3 @@ +[[package]] +name = "ref_without_mut_not_assignable" +source = "member" diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/Forc.toml new file mode 100644 index 00000000000..4b63aa2b632 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/Forc.toml @@ -0,0 +1,6 @@ +[project] +name = "ref_without_mut_not_assignable" +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +implicit-std = false diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/src/main.sw new file mode 100644 index 00000000000..001f040173d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/src/main.sw @@ -0,0 +1,17 @@ +script; + +fn ref_immutable(ref x: u64) { + x = 10; +} + +fn ref_mut_immutable_arg(ref mut _x: u64) { } + +fn main() -> u64 { + let y = 42; + + ref_immutable(y); + + ref_mut_immutable_arg(y); + + y +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/test.toml new file mode 100644 index 00000000000..4f555d0677d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/ref_without_mut_not_assignable/test.toml @@ -0,0 +1,9 @@ +category = "fail" + +# ref without mut: parameter should be immutable inside the function body +# check: $()x = 10; +# nextln: $()cannot be assigned to, because it is an immutable variable + +# ref mut with immutable argument: should still require mutable arg +# check: $()ref_mut_immutable_arg(y); +# nextln: $()Cannot pass immutable argument to mutable parameter diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/Forc.lock new file mode 100644 index 00000000000..49e78da9c46 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "ref_without_mut" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-9C22439F46EC1A75" diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/Forc.toml new file mode 100644 index 00000000000..efa76705040 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +name = "ref_without_mut" +entry = "main.sw" +implicit-std = false + +[dependencies] +std = { path = "../../../../reduced_std_libs/sway-lib-std-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/src/main.sw new file mode 100644 index 00000000000..1e5250dd270 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/src/main.sw @@ -0,0 +1,33 @@ +script; + +struct S { + value: u64, +} + +impl S { + fn method(self, ref _x: u64) -> u64 { + _x + } + + fn associated_fn(ref _x: u64) -> u64 { + _x + } +} + +fn ref_pass(ref _x: u64) -> u64 { + _x +} + +fn main() -> u64 { + let x = 42; + + let a = ref_pass(x); + let b = S { value: 1 }.method(x); + let c = S::associated_fn(x); + + if a == 42 && b == 42 && c == 42 { + 42 + } else { + 0 + } +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/test.toml new file mode 100644 index 00000000000..09db9a2bd63 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/ref_without_mut/test.toml @@ -0,0 +1,3 @@ +category = "run" +expected_result = { action = "return", value = 42 } +expected_result_new_encoding = { action = "return_data", value = "000000000000002A" }