diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index c06e3c8b3c174..93677bc94cb89 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1198,6 +1198,26 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ); return; } + + // If `local` is a closure arg, and the type of the arg is not under + // local control, do not suggest to change its type. + if self.body.local_kind(local) == LocalKind::Arg + && let InstanceKind::Item(def_id) = self.body.source.instance + && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = + self.infcx.tcx.hir_get_if_local(def_id) + && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind + && let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id) + && let ExprKind::MethodCall(path_segment, _, _, _) = expr.kind + && self + .infcx + .tcx + .typeck(path_segment.hir_id.owner.def_id) + .type_dependent_def_id(expr.hir_id) + .is_some_and(|def_id| !def_id.is_local()) + { + return; + } + let decl_span = local_decl.source_info.span; let (amp_mut_sugg, local_var_ty_info) = match *local_decl.local_info() { diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr index 8191f1f4394b7..60ff010193fd2 100644 --- a/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr +++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr @@ -2,9 +2,7 @@ error[E0596]: cannot borrow `**layer` as mutable, as it is behind a `&` referenc --> $DIR/issue-115259-suggest-iter-mut.rs:15:65 | LL | self.layers.iter().fold(0, |result, mut layer| result + layer.process()) - | --------- ^^^^^ `layer` is a `&` reference, so it cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut Box` + | ^^^^^ `layer` is a `&` reference, so it cannot be borrowed as mutable | help: you may want to use `iter_mut` here | diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr index 29121b85f3a08..ba765f06a2c8f 100644 --- a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr @@ -2,9 +2,7 @@ error[E0596]: cannot borrow `*container` as mutable, as it is behind a `&` refer --> $DIR/issue-62387-suggest-iter-mut-2.rs:30:45 | LL | vec.iter().flat_map(|container| container.things()).cloned().collect::>(); - | --------- ^^^^^^^^^ `container` is a `&` reference, so it cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut Container` + | ^^^^^^^^^ `container` is a `&` reference, so it cannot be borrowed as mutable | help: you may want to use `iter_mut` here | diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr index 55c17ab6cdea1..677d71d85580d 100644 --- a/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr @@ -2,9 +2,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/issue-62387-suggest-iter-mut.rs:18:27 | LL | v.iter().for_each(|a| a.double()); - | - ^ `a` is a `&` reference, so it cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut A` + | ^ `a` is a `&` reference, so it cannot be borrowed as mutable | help: you may want to use `iter_mut` here | @@ -15,9 +13,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/issue-62387-suggest-iter-mut.rs:25:39 | LL | v.iter().rev().rev().for_each(|a| a.double()); - | - ^ `a` is a `&` reference, so it cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut A` + | ^ `a` is a `&` reference, so it cannot be borrowed as mutable | help: you may want to use `iter_mut` here | diff --git a/tests/ui/borrowck/option-inspect-mutation.rs b/tests/ui/borrowck/option-inspect-mutation.rs new file mode 100644 index 0000000000000..124f21553b666 --- /dev/null +++ b/tests/ui/borrowck/option-inspect-mutation.rs @@ -0,0 +1,13 @@ +//! Regression test for . + +struct Struct { + field: u32, +} + +fn main() { + let mut some_struct = Some(Struct { field: 42 }); + some_struct.as_mut().inspect(|some_struct| { + some_struct.field *= 10; //~ ERROR cannot assign to `some_struct.field`, which is behind a `&` reference + // Users can't change type of `some_struct` param, so above error must not suggest it. + }); +} diff --git a/tests/ui/borrowck/option-inspect-mutation.stderr b/tests/ui/borrowck/option-inspect-mutation.stderr new file mode 100644 index 0000000000000..d947827b238e0 --- /dev/null +++ b/tests/ui/borrowck/option-inspect-mutation.stderr @@ -0,0 +1,9 @@ +error[E0594]: cannot assign to `some_struct.field`, which is behind a `&` reference + --> $DIR/option-inspect-mutation.rs:10:9 + | +LL | some_struct.field *= 10; + | ^^^^^^^^^^^^^^^^^^^^^^^ `some_struct` is a `&` reference, so it cannot be written to + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr index ca0d0bd8a3caa..9b4061af967ed 100644 --- a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr +++ b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr @@ -18,9 +18,7 @@ error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference --> $DIR/suggest-as-ref-on-mut-closure.rs:12:26 | LL | cb.as_ref().map(|cb| cb()); - | -- ^^ `cb` is a `&` reference, so it cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut &mut dyn FnMut()` + | ^^ `cb` is a `&` reference, so it cannot be borrowed as mutable error: aborting due to 2 previous errors