diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 2f011dba60b16..c1d333cb220c9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1364,10 +1364,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let node = hir_id.map(|hir_id| self.infcx.tcx.hir_node(hir_id)); let Some(hir::Node::LetStmt(local)) = node else { - err.span_label( - sugg_span, - format!("consider changing this binding's type to be: `{sugg_str}`"), - ); + // Don't suggest changing the binding's type for closure parameters, + // as the type is often constrained by the closure's context (e.g., when passed + // to methods like `Option::inspect`). + if !matches!(node, Some(hir::Node::Param(_))) { + err.span_label( + sugg_span, + format!("consider changing this binding's type to be: `{sugg_str}`"), + ); + } return; }; @@ -1494,9 +1499,7 @@ impl<'tcx> Visitor<'tcx> for BindingFinder { } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> Self::Result { - if let hir::Pat { kind: hir::PatKind::Ref(_, _), span, .. } = param.pat - && *span == self.span - { + if param.pat.span == self.span { ControlFlow::Break(param.hir_id) } else { ControlFlow::Continue(()) diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr index 61c01f0f024fe..0bc2b8c83fffe 100644 --- a/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr +++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr @@ -1,10 +1,8 @@ error[E0596]: cannot borrow `**layer` as mutable, as it is behind a `&` reference - --> $DIR/issue-115259-suggest-iter-mut.rs:15:65 + --> $DIR/issue-115259-suggest-iter-mut.rs:15:74 | LL | self.layers.iter().fold(0, |result, mut layer| result + layer.process()) - | --------- ^^^^^ `layer` is a `&` reference, so the data it refers to cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut Box` + | ^^^^^ `layer` is a `&` reference, so the data it refers to cannot be borrowed as mutable | help: you may want to use `iter_mut` here | diff --git a/tests/ui/borrowck/issue-128381-mutate-through-option-inspect.rs b/tests/ui/borrowck/issue-128381-mutate-through-option-inspect.rs new file mode 100644 index 0000000000000..5ec99920f1b72 --- /dev/null +++ b/tests/ui/borrowck/issue-128381-mutate-through-option-inspect.rs @@ -0,0 +1,16 @@ +// Issue #128381: Check that we don't suggest changing closure parameter types +// when they are constrained by method signatures like `Option::inspect`. + +#[derive(Debug)] +struct A { + a: u32, +} + +fn main() { + let mut opt = Some(A { a: 123 }); + let ref_mut_opt = opt.as_mut().inspect(|a| { + a.a += 123; + //~^ ERROR cannot assign to `a.a`, which is behind a `&` reference + }); + dbg!(ref_mut_opt); +} diff --git a/tests/ui/borrowck/issue-128381-mutate-through-option-inspect.stderr b/tests/ui/borrowck/issue-128381-mutate-through-option-inspect.stderr new file mode 100644 index 0000000000000..29130019b07fe --- /dev/null +++ b/tests/ui/borrowck/issue-128381-mutate-through-option-inspect.stderr @@ -0,0 +1,9 @@ +error[E0594]: cannot assign to `a.a`, which is behind a `&` reference + --> $DIR/issue-128381-mutate-through-option-inspect.rs:12:9 + | +LL | a.a += 123; + | ^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0594`. 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 c6955317d87d5..d247c1a8f902b 100644 --- a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr @@ -1,10 +1,8 @@ error[E0596]: cannot borrow `*container` as mutable, as it is behind a `&` reference - --> $DIR/issue-62387-suggest-iter-mut-2.rs:30:45 + --> $DIR/issue-62387-suggest-iter-mut-2.rs:30:56 | LL | vec.iter().flat_map(|container| container.things()).cloned().collect::>(); - | --------- ^^^^^^^^^ `container` is a `&` reference, so the data it refers to cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut Container` + | ^^^^^^^^^ `container` is a `&` reference, so the data it refers to 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 ae4920b2a8cb0..526a9d1d060ad 100644 --- a/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr @@ -1,10 +1,8 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference - --> $DIR/issue-62387-suggest-iter-mut.rs:18:27 + --> $DIR/issue-62387-suggest-iter-mut.rs:18:31 | LL | v.iter().for_each(|a| a.double()); - | - ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut A` + | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable | help: you may want to use `iter_mut` here | @@ -12,12 +10,10 @@ LL | v.iter_mut().for_each(|a| a.double()); | ++++ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference - --> $DIR/issue-62387-suggest-iter-mut.rs:25:39 + --> $DIR/issue-62387-suggest-iter-mut.rs:25:43 | LL | v.iter().rev().rev().for_each(|a| a.double()); - | - ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut A` + | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable | help: you may want to use `iter_mut` here | 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 1e98006a9a71e..79f45112a9c42 100644 --- a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr +++ b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr @@ -15,12 +15,10 @@ LL | as Clone>::clone(&cb).map(|cb| cb()); | ++++++++++++++++++++++++++++++++++++++++++++ + error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference - --> $DIR/suggest-as-ref-on-mut-closure.rs:12:26 + --> $DIR/suggest-as-ref-on-mut-closure.rs:12:30 | LL | cb.as_ref().map(|cb| cb()); - | -- ^^ `cb` is a `&` reference, so the data it refers to cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut &mut dyn FnMut()` + | ^^ `cb` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 2 previous errors