about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs22
-rw-r--r--tests/ui/lifetimes/issue-105675.rs8
-rw-r--r--tests/ui/lifetimes/issue-105675.stderr104
-rw-r--r--tests/ui/lifetimes/issue-79187-2.stderr4
4 files changed, 63 insertions, 75 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index ec0aa77cef3..473ce3d635d 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 a01fbef4b3b..58d8be8b65f 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 3d8172ad14a..66415f72bcb 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 c14d3e0c61b..75fd87b3fe9 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