rustc_borrowck: Don't suggest changing closure param type not under user control
All removed suggestions in tests were invalid.
This commit is contained in:
parent
6004968e4a
commit
f186e53db9
6 changed files with 65 additions and 19 deletions
|
|
@ -1198,6 +1198,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not suggest changing type if that is not under user control.
|
||||
if self.is_closure_arg_with_non_locally_decided_type(local) {
|
||||
return;
|
||||
}
|
||||
|
||||
let decl_span = local_decl.source_info.span;
|
||||
|
||||
let (amp_mut_sugg, local_var_ty_info) = match *local_decl.local_info() {
|
||||
|
|
@ -1500,6 +1506,60 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns `true` if `local` is an argument in a closure passed to a
|
||||
/// function defined in another crate.
|
||||
///
|
||||
/// For example, in the following code this function returns `true` for `x`
|
||||
/// since `Option::inspect()` is not defined in the current crate:
|
||||
///
|
||||
/// ```text
|
||||
/// some_option.as_mut().inspect(|x| {
|
||||
/// ```
|
||||
fn is_closure_arg_with_non_locally_decided_type(&self, local: Local) -> bool {
|
||||
// We don't care about regular local variables, only args.
|
||||
if self.body.local_kind(local) != LocalKind::Arg {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure we are inside a closure.
|
||||
let InstanceKind::Item(body_def_id) = self.body.source.instance else {
|
||||
return false;
|
||||
};
|
||||
let Some(Node::Expr(hir::Expr { hir_id: body_hir_id, kind, .. })) =
|
||||
self.infcx.tcx.hir_get_if_local(body_def_id)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Check if the method/function that our closure is passed to is defined
|
||||
// in another crate.
|
||||
let Node::Expr(closure_parent) = self.infcx.tcx.parent_hir_node(*body_hir_id) else {
|
||||
return false;
|
||||
};
|
||||
match closure_parent.kind {
|
||||
ExprKind::MethodCall(method, _, _, _) => self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck(method.hir_id.owner.def_id)
|
||||
.type_dependent_def_id(closure_parent.hir_id)
|
||||
.is_some_and(|def_id| !def_id.is_local()),
|
||||
ExprKind::Call(func, _) => self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck(func.hir_id.owner.def_id)
|
||||
.node_type_opt(func.hir_id)
|
||||
.and_then(|ty| match ty.kind() {
|
||||
ty::FnDef(def_id, _) => Some(def_id),
|
||||
_ => None,
|
||||
})
|
||||
.is_some_and(|def_id| !def_id.is_local()),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BindingFinder {
|
||||
|
|
|
|||
|
|
@ -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<dyn Layer>`
|
||||
| ^^^^^ `layer` is a `&` reference, so it cannot be borrowed as mutable
|
||||
|
|
||||
help: you may want to use `iter_mut` here
|
||||
|
|
||||
|
|
|
|||
|
|
@ -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::<Vec<PathBuf>>();
|
||||
| --------- ^^^^^^^^^ `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
|
||||
|
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
error[E0594]: cannot assign to `some_struct.field`, which is behind a `&` reference
|
||||
--> $DIR/option-inspect-mutation.rs:10:9
|
||||
|
|
||||
LL | some_struct.as_mut().inspect(|some_struct| {
|
||||
| ----------- consider changing this binding's type to be: `&mut &mut Struct`
|
||||
LL | some_struct.field *= 10;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ `some_struct` is a `&` reference, so it cannot be written to
|
||||
|
||||
error[E0594]: cannot assign to `some_struct.field`, which is behind a `&` reference
|
||||
--> $DIR/option-inspect-mutation.rs:16:9
|
||||
|
|
||||
LL | Option::inspect(some_struct.as_mut(), |some_struct| {
|
||||
| ----------- consider changing this binding's type to be: `&mut &mut Struct`
|
||||
LL | some_struct.field *= 20;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ `some_struct` is a `&` reference, so it cannot be written to
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue