Tweak "borrow closure argument" suggestion

Fix #45727.
This commit is contained in:
Esteban Küber 2023-01-14 23:53:56 +00:00
parent 19423b5944
commit 33e11a3b2e
9 changed files with 127 additions and 47 deletions

View File

@ -1350,6 +1350,7 @@ fn report_selection_error(
expected_trait_ref, expected_trait_ref,
obligation.cause.code(), obligation.cause.code(),
found_node, found_node,
obligation.param_env,
) )
} else { } else {
let (closure_span, closure_arg_span, found) = found_did let (closure_span, closure_arg_span, found) = found_did

View File

@ -283,6 +283,7 @@ fn report_closure_arg_mismatch(
expected: ty::PolyTraitRef<'tcx>, expected: ty::PolyTraitRef<'tcx>,
cause: &ObligationCauseCode<'tcx>, cause: &ObligationCauseCode<'tcx>,
found_node: Option<Node<'_>>, found_node: Option<Node<'_>>,
param_env: ty::ParamEnv<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
fn note_conflicting_closure_bounds( fn note_conflicting_closure_bounds(
@ -1978,6 +1979,7 @@ fn report_closure_arg_mismatch(
expected: ty::PolyTraitRef<'tcx>, expected: ty::PolyTraitRef<'tcx>,
cause: &ObligationCauseCode<'tcx>, cause: &ObligationCauseCode<'tcx>,
found_node: Option<Node<'_>>, found_node: Option<Node<'_>>,
param_env: ty::ParamEnv<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
pub(crate) fn build_fn_sig_ty<'tcx>( pub(crate) fn build_fn_sig_ty<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
@ -2040,7 +2042,7 @@ pub(crate) fn build_fn_sig_ty<'tcx>(
self.note_conflicting_closure_bounds(cause, &mut err); self.note_conflicting_closure_bounds(cause, &mut err);
if let Some(found_node) = found_node { if let Some(found_node) = found_node {
hint_missing_borrow(span, found, expected, found_node, &mut err); hint_missing_borrow(self, param_env, span, found, expected, found_node, &mut err);
} }
err err
@ -3747,6 +3749,8 @@ fn probe_assoc_types_at_expr(
/// Add a hint to add a missing borrow or remove an unnecessary one. /// Add a hint to add a missing borrow or remove an unnecessary one.
fn hint_missing_borrow<'tcx>( fn hint_missing_borrow<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
span: Span, span: Span,
found: Ty<'tcx>, found: Ty<'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
@ -3769,7 +3773,7 @@ fn hint_missing_borrow<'tcx>(
// This could be a variant constructor, for example. // This could be a variant constructor, for example.
let Some(fn_decl) = found_node.fn_decl() else { return; }; let Some(fn_decl) = found_node.fn_decl() else { return; };
let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span); let args = fn_decl.inputs.iter().map(|ty| ty);
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
let mut refs = 0; let mut refs = 0;
@ -3785,21 +3789,34 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
let mut to_borrow = Vec::new(); let mut to_borrow = Vec::new();
let mut remove_borrow = Vec::new(); let mut remove_borrow = Vec::new();
for ((found_arg, expected_arg), arg_span) in found_args.zip(expected_args).zip(arg_spans) { for ((found_arg, expected_arg), arg) in found_args.zip(expected_args).zip(args) {
let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg); let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg);
let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg); let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
if found_ty == expected_ty { if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() {
if found_refs < expected_refs { if found_refs < expected_refs {
to_borrow.push((arg_span, expected_arg.to_string())); to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs)));
} else if found_refs > expected_refs { } else if found_refs > expected_refs {
remove_borrow.push((arg_span, expected_arg.to_string())); let mut span = arg.span.shrink_to_lo();
let mut left = found_refs - expected_refs;
let mut ty = arg;
while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
span = span.with_hi(mut_ty.ty.span.lo());
ty = mut_ty.ty;
left -= 1;
}
let sugg = if left == 0 {
(span, String::new())
} else {
(arg.span, expected_arg.to_string())
};
remove_borrow.push(sugg);
} }
} }
} }
if !to_borrow.is_empty() { if !to_borrow.is_empty() {
err.multipart_suggestion( err.multipart_suggestion_verbose(
"consider borrowing the argument", "consider borrowing the argument",
to_borrow, to_borrow,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
@ -3807,7 +3824,7 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
} }
if !remove_borrow.is_empty() { if !remove_borrow.is_empty() {
err.multipart_suggestion( err.multipart_suggestion_verbose(
"do not borrow the argument", "do not borrow the argument",
remove_borrow, remove_borrow,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,

View File

@ -16,7 +16,7 @@ LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
help: consider borrowing the argument help: consider borrowing the argument
| |
LL | f1(|_: &(), _: &()| {}); LL | f1(|_: &(), _: &()| {});
| ~~~ ~~~ | + +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:3:5 --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5
@ -35,8 +35,8 @@ LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f2` | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f2`
help: consider borrowing the argument help: consider borrowing the argument
| |
LL | f2(|_: &'a (), _: &()| {}); LL | f2(|_: &(), _: &()| {});
| ~~~~~~ ~~~ | + +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
@ -56,7 +56,7 @@ LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
help: consider borrowing the argument help: consider borrowing the argument
| |
LL | f3(|_: &(), _: &()| {}); LL | f3(|_: &(), _: &()| {});
| ~~~ ~~~ | + +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:5:5 --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5
@ -75,8 +75,8 @@ LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f4` | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f4`
help: consider borrowing the argument help: consider borrowing the argument
| |
LL | f4(|_: &(), _: &'r ()| {}); LL | f4(|_: &(), _: &()| {});
| ~~~ ~~~~~~ | + +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
@ -95,17 +95,15 @@ LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f5` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f5`
help: consider borrowing the argument help: consider borrowing the argument
| |
LL | f5(|_: &'r (), _: &'r ()| {}); LL | f5(|_: &(), _: &()| {});
| ~~~~~~ ~~~~~~ | + +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:7:5 --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5
| |
LL | g1(|_: (), _: ()| {}); LL | g1(|_: (), _: ()| {});
| ^^ -------------- | ^^ -------------- found signature defined here
| | | | | |
| | | help: consider borrowing the argument: `&()`
| | found signature defined here
| expected due to this | expected due to this
| |
= note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _` = note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
@ -115,15 +113,17 @@ note: required by a bound in `g1`
| |
LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {} LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g1` | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g1`
help: consider borrowing the argument
|
LL | g1(|_: &(), _: ()| {});
| +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
| |
LL | g2(|_: (), _: ()| {}); LL | g2(|_: (), _: ()| {});
| ^^ -------------- | ^^ -------------- found signature defined here
| | | | | |
| | | help: consider borrowing the argument: `&()`
| | found signature defined here
| expected due to this | expected due to this
| |
= note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _` = note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _`
@ -133,15 +133,17 @@ note: required by a bound in `g2`
| |
LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {} LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
| ^^^^^^^^^^^^^^^^ required by this bound in `g2` | ^^^^^^^^^^^^^^^^ required by this bound in `g2`
help: consider borrowing the argument
|
LL | g2(|_: &(), _: ()| {});
| +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:9:5 --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5
| |
LL | g3(|_: (), _: ()| {}); LL | g3(|_: (), _: ()| {});
| ^^ -------------- | ^^ -------------- found signature defined here
| | | | | |
| | | help: consider borrowing the argument: `&'s ()`
| | found signature defined here
| expected due to this | expected due to this
| |
= note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _` = note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
@ -151,15 +153,17 @@ note: required by a bound in `g3`
| |
LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {} LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g3` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g3`
help: consider borrowing the argument
|
LL | g3(|_: &(), _: ()| {});
| +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
| |
LL | g4(|_: (), _: ()| {}); LL | g4(|_: (), _: ()| {});
| ^^ -------------- | ^^ -------------- found signature defined here
| | | | | |
| | | help: consider borrowing the argument: `&()`
| | found signature defined here
| expected due to this | expected due to this
| |
= note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _` = note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _`
@ -169,6 +173,10 @@ note: required by a bound in `g4`
| |
LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g4` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g4`
help: consider borrowing the argument
|
LL | g4(|_: &(), _: ()| {});
| +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:11:5 --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5
@ -188,7 +196,7 @@ LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {}
help: consider borrowing the argument help: consider borrowing the argument
| |
LL | h1(|_: &(), _: (), _: &(), _: ()| {}); LL | h1(|_: &(), _: (), _: &(), _: ()| {});
| ~~~ ~~~ | + +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
@ -207,8 +215,8 @@ LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h2` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h2`
help: consider borrowing the argument help: consider borrowing the argument
| |
LL | h2(|_: &(), _: (), _: &'t0 (), _: ()| {}); LL | h2(|_: &(), _: (), _: &(), _: ()| {});
| ~~~ ~~~~~~~ | + +
error: aborting due to 11 previous errors error: aborting due to 11 previous errors

View File

@ -2,10 +2,8 @@ error[E0631]: type mismatch in closure arguments
--> $DIR/multiple-fn-bounds.rs:10:5 --> $DIR/multiple-fn-bounds.rs:10:5
| |
LL | foo(move |x| v); LL | foo(move |x| v);
| ^^^ -------- | ^^^ -------- found signature defined here
| | | | | |
| | | help: do not borrow the argument: `char`
| | found signature defined here
| expected due to this | expected due to this
| |
= note: expected closure signature `fn(char) -> _` = note: expected closure signature `fn(char) -> _`
@ -20,6 +18,10 @@ note: required by a bound in `foo`
| |
LL | fn foo<F: Fn(&char) -> bool + Fn(char) -> bool>(f: F) { LL | fn foo<F: Fn(&char) -> bool + Fn(char) -> bool>(f: F) {
| ^^^^^^^^^^^^^^^^ required by this bound in `foo` | ^^^^^^^^^^^^^^^^ required by this bound in `foo`
help: do not borrow the argument
|
LL | foo(move |char| v);
| ~~~~
error: aborting due to previous error error: aborting due to previous error

View File

@ -0,0 +1,5 @@
// run-rustfix
fn main() {
let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
}

View File

@ -0,0 +1,5 @@
// run-rustfix
fn main() {
let _ = (-10..=10).find(|x: i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
}

View File

@ -0,0 +1,38 @@
error[E0631]: type mismatch in closure arguments
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:3:24
|
LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0);
| ^^^^ -------- found signature defined here
| |
| expected due to this
|
= note: expected closure signature `for<'a> fn(&'a {integer}) -> _`
found closure signature `fn(i32) -> _`
note: required by a bound in `find`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
help: consider borrowing the argument
|
LL | let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
| +
error[E0631]: type mismatch in closure arguments
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:4:24
|
LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
| ^^^^ ----------- found signature defined here
| |
| expected due to this
|
= note: expected closure signature `for<'a> fn(&'a {integer}) -> _`
found closure signature `for<'a, 'b, 'c> fn(&'a &'b &'c i32) -> _`
note: required by a bound in `find`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
help: do not borrow the argument
|
LL - let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
LL + let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
|
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0631`.

View File

@ -2,16 +2,18 @@ error[E0631]: type mismatch in closure arguments
--> $DIR/closure-arg-type-mismatch.rs:3:14 --> $DIR/closure-arg-type-mismatch.rs:3:14
| |
LL | a.iter().map(|_: (u32, u32)| 45); LL | a.iter().map(|_: (u32, u32)| 45);
| ^^^ --------------- | ^^^ --------------- found signature defined here
| | | | | |
| | | help: consider borrowing the argument: `&(u32, u32)`
| | found signature defined here
| expected due to this | expected due to this
| |
= note: expected closure signature `fn(&(u32, u32)) -> _` = note: expected closure signature `fn(&(u32, u32)) -> _`
found closure signature `fn((u32, u32)) -> _` found closure signature `fn((u32, u32)) -> _`
note: required by a bound in `map` note: required by a bound in `map`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
help: consider borrowing the argument
|
LL | a.iter().map(|_: &(u32, u32)| 45);
| +
error[E0631]: type mismatch in closure arguments error[E0631]: type mismatch in closure arguments
--> $DIR/closure-arg-type-mismatch.rs:4:14 --> $DIR/closure-arg-type-mismatch.rs:4:14

View File

@ -2,16 +2,18 @@ error[E0631]: type mismatch in closure arguments
--> $DIR/issue-36053-2.rs:7:32 --> $DIR/issue-36053-2.rs:7:32
| |
LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); LL | once::<&str>("str").fuse().filter(|a: &str| true).count();
| ^^^^^^ --------- | ^^^^^^ --------- found signature defined here
| | | | | |
| | | help: consider borrowing the argument: `&&str`
| | found signature defined here
| expected due to this | expected due to this
| |
= note: expected closure signature `for<'a> fn(&'a &str) -> _` = note: expected closure signature `for<'a> fn(&'a &str) -> _`
found closure signature `for<'a> fn(&'a str) -> _` found closure signature `for<'a> fn(&'a str) -> _`
note: required by a bound in `filter` note: required by a bound in `filter`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
help: consider borrowing the argument
|
LL | once::<&str>("str").fuse().filter(|a: &&str| true).count();
| +
error[E0599]: the method `count` exists for struct `Filter<Fuse<Once<&str>>, [closure@issue-36053-2.rs:7:39]>`, but its trait bounds were not satisfied error[E0599]: the method `count` exists for struct `Filter<Fuse<Once<&str>>, [closure@issue-36053-2.rs:7:39]>`, but its trait bounds were not satisfied
--> $DIR/issue-36053-2.rs:7:55 --> $DIR/issue-36053-2.rs:7:55