diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index ec0aa77cef38..473ce3d635de 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -547,7 +547,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { diag: &mut Diagnostic, ) { // 0. Extract fn_decl from hir - let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(hir::Closure { fn_decl, .. }), .. }) = hir else { return; }; + let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(hir::Closure { body, fn_decl, .. }), .. }) = hir else { return; }; + let hir::Body { params, .. } = self.tcx.hir().body(*body); // 1. Get the substs of the closure. // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1]. @@ -565,7 +566,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut is_first = true; let mut has_suggestion = false; - for ((expected, found), arg_hir) in expected.iter().zip(found.iter()).zip(fn_decl.inputs.iter()) { + for (((expected, found), param_hir), arg_hir) in expected.iter() + .zip(found.iter()) + .zip(params.iter()) + .zip(fn_decl.inputs.iter()) { if is_first { is_first = false; } else { @@ -579,11 +583,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let hir::TyKind::Infer = arg_hir.kind { // If the expected region is late bound, the found region is not, and users are asking compiler // to infer the type, we can suggest adding `: &_`. - let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(arg_hir.span) else { return; }; - suggestion += &format!("{}: &_", arg); + if param_hir.pat.span == param_hir.ty_span { + // for `|x|`, `|_|`, `|x: impl Foo|` + let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; }; + suggestion += &format!("{}: &_", pat); + } else { + // for `|x: ty|`, `|_: ty|` + let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; }; + let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; }; + suggestion += &format!("{}: &{}", pat, ty); + } has_suggestion = true; } else { - let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(arg_hir.span) else { return; }; + let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { return; }; // Otherwise, keep it as-is. suggestion += &arg; } diff --git a/tests/ui/lifetimes/issue-105675.rs b/tests/ui/lifetimes/issue-105675.rs index a01fbef4b3bc..58d8be8b65f7 100644 --- a/tests/ui/lifetimes/issue-105675.rs +++ b/tests/ui/lifetimes/issue-105675.rs @@ -1,13 +1,11 @@ -fn thing(x: impl FnOnce(&u32, &u32)) {} +fn thing(x: impl FnOnce(&u32, &u32, u32)) {} fn main() { - let f = |_, _| (); + let f = | _ , y: &u32 , z | (); thing(f); //~^ ERROR mismatched types //~^^ ERROR mismatched types - //~^^^ ERROR implementation of `FnOnce` is not general enough - //~^^^^ ERROR implementation of `FnOnce` is not general enough - let f = |x, y| (); + let f = | x, y: _ , z: u32 | (); thing(f); //~^ ERROR mismatched types //~^^ ERROR mismatched types diff --git a/tests/ui/lifetimes/issue-105675.stderr b/tests/ui/lifetimes/issue-105675.stderr index 3d8172ad14a3..66415f72bcb4 100644 --- a/tests/ui/lifetimes/issue-105675.stderr +++ b/tests/ui/lifetimes/issue-105675.stderr @@ -4,22 +4,22 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32)>` - found trait `FnOnce<(&u32, &u32)>` + = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` + found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:4:13 | -LL | let f = |_, _| (); - | ^^^^^^ +LL | let f = | _ , y: &u32 , z | (); + | ^^^^^^^^^^^^^^^^^^^ note: the lifetime requirement is introduced here --> $DIR/issue-105675.rs:1:18 | -LL | fn thing(x: impl FnOnce(&u32, &u32)) {} - | ^^^^^^^^^^^^^^^^^^ +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider specifying the type of the closure parameters | -LL | let f = |_: &_, _: &_| (); - | ~~~~~~~~~~~~~~ +LL | let f = |_: &_, y: &u32, z| (); + | ~~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/issue-105675.rs:5:5 @@ -27,105 +27,83 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32)>` - found trait `FnOnce<(&u32, &u32)>` + = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` + found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:4:13 | -LL | let f = |_, _| (); - | ^^^^^^ +LL | let f = | _ , y: &u32 , z | (); + | ^^^^^^^^^^^^^^^^^^^ note: the lifetime requirement is introduced here --> $DIR/issue-105675.rs:1:18 | -LL | fn thing(x: impl FnOnce(&u32, &u32)) {} - | ^^^^^^^^^^^^^^^^^^ -help: consider specifying the type of the closure parameters - | -LL | let f = |_: &_, _: &_| (); - | ~~~~~~~~~~~~~~ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-105675.rs:5:5 - | -LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 u32, &u32)` must implement `FnOnce<(&'1 u32, &u32)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 u32, &u32)>`, for some specific lifetime `'2` - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-105675.rs:5:5 - | -LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&u32, &'2 u32)` must implement `FnOnce<(&u32, &'1 u32)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&u32, &'2 u32)>`, for some specific lifetime `'2` +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/issue-105675.rs:11:5 + --> $DIR/issue-105675.rs:9:5 | LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32)>` - found trait `FnOnce<(&u32, &u32)>` + = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` + found trait `FnOnce<(&u32, &u32, u32)>` note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-105675.rs:10:13 + --> $DIR/issue-105675.rs:8:13 | -LL | let f = |x, y| (); - | ^^^^^^ +LL | let f = | x, y: _ , z: u32 | (); + | ^^^^^^^^^^^^^^^^^^^^^ note: the lifetime requirement is introduced here --> $DIR/issue-105675.rs:1:18 | -LL | fn thing(x: impl FnOnce(&u32, &u32)) {} - | ^^^^^^^^^^^^^^^^^^ +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider specifying the type of the closure parameters | -LL | let f = |x: &_, y: &_| (); - | ~~~~~~~~~~~~~~ +LL | let f = |x: &_, y: &_, z: u32| (); + | ~~~~~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types - --> $DIR/issue-105675.rs:11:5 + --> $DIR/issue-105675.rs:9:5 | LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32)>` - found trait `FnOnce<(&u32, &u32)>` + = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` + found trait `FnOnce<(&u32, &u32, u32)>` note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-105675.rs:10:13 + --> $DIR/issue-105675.rs:8:13 | -LL | let f = |x, y| (); - | ^^^^^^ +LL | let f = | x, y: _ , z: u32 | (); + | ^^^^^^^^^^^^^^^^^^^^^ note: the lifetime requirement is introduced here --> $DIR/issue-105675.rs:1:18 | -LL | fn thing(x: impl FnOnce(&u32, &u32)) {} - | ^^^^^^^^^^^^^^^^^^ +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider specifying the type of the closure parameters | -LL | let f = |x: &_, y: &_| (); - | ~~~~~~~~~~~~~~ +LL | let f = |x: &_, y: &_, z: u32| (); + | ~~~~~~~~~~~~~~~~~~~~~~ error: implementation of `FnOnce` is not general enough - --> $DIR/issue-105675.rs:11:5 + --> $DIR/issue-105675.rs:9:5 | LL | thing(f); | ^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: closure with signature `fn(&'2 u32, &u32)` must implement `FnOnce<(&'1 u32, &u32)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 u32, &u32)>`, for some specific lifetime `'2` + = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` error: implementation of `FnOnce` is not general enough - --> $DIR/issue-105675.rs:11:5 + --> $DIR/issue-105675.rs:9:5 | LL | thing(f); | ^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: closure with signature `fn(&u32, &'2 u32)` must implement `FnOnce<(&u32, &'1 u32)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&u32, &'2 u32)>`, for some specific lifetime `'2` + = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index c14d3e0c61b8..75fd87b3fe9b 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -43,9 +43,9 @@ note: the lifetime requirement is introduced here | LL | fn take_foo(_: impl Foo) {} | ^^^ -help: consider changing the type of the closure parameters +help: consider specifying the type of the closure parameters | -LL | take_foo(|_: &_| a); +LL | take_foo(|a: &_| a); | ~~~~~~~ error[E0308]: mismatched types