Change:
a new project with (in my case, it used pathfinding version 4.0.0 or 4.0.1) with: produces the following output: For the two closures ( and ), if I add a type for the parameter by changing to , it builds without any errors. If it had told me that it needed type annotations, I would have understood the problem and been able to fix it right away. (I assumed that there was enough type information for it to infer the correct types.) The first confusing bit is that both errors highlight the entire call to , including all parameters. This makes it harder to figure out which one it is complaining about (though the second note contains the line number). Does the first argument have something to do with the lifetimes it is complaining about? I found this part of the message hard to understand: The type parameters look almost identical, and the didn't make sense to me. Could it somehow indicate the bounds of that lifetime (2), or better explain why that lifetime doesn't last long enough? FYI: found as part of solving Advent of Code 2022, Day 12. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
A smaller MCVE:
I'm thinking whether we should fix this as a compiler bug (i.e., make it compile) or suggesting people write explicit type here
maybe related:
Also if we move the closure to the parameter: This will also compile. Combined with , I guess something is wrong with propagating lifetime of closures when we store it in a variable...
claim

Discussion:
{ let span = self.tcx.def_span(def_id); diag.span_note(span, "this closure does not fulfill the lifetime requirements"); <ins> self.suggest_for_all_lifetime_closure(span, self.tcx.hir().get_by_def_id(def_id), &exp_found, diag); </ins> } // It reads better to have the error origin as the final

use hir::def::CtorKind; use hir::intravisit::{walk_expr, walk_stmt, Visitor}; use rustc_data_structures::fx::FxIndexSet; <del> use rustc_errors::Diagnostic; </del> <ins> use rustc_errors::{Applicability, Diagnostic}; </ins> use rustc_hir as hir; use rustc_middle::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, StatementAsExpression, }; use rustc_middle::ty::print::with_no_trimmed_paths; <del> use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitableExt}; </del> <ins> use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt}; </ins> use rustc_span::{sym, BytePos, Span}; use rustc_target::abi::FieldIdx;

} None } <ins> /// For "one type is more general than the other" errors on closures, suggest changing the lifetime /// of the parameters to accept all lifetimes. pub(super) fn suggest_for_all_lifetime_closure( &self, span: Span, hir: hir::Node<'_>, exp_found: &ty::error::ExpectedFound<ty::PolyTraitRef<'tcx>>, diag: &mut Diagnostic, ) { // 0. Extract fn_decl from hir 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]. let Some(expected) = exp_found.expected.skip_binder().substs.get(1) else { return; }; let Some(found) = exp_found.found.skip_binder().substs.get(1) else { return; }; let expected = expected.unpack(); let found = found.unpack(); // 3. Extract the tuple type from Fn trait and suggest the change. if let GenericArgKind::Type(expected) = expected && let GenericArgKind::Type(found) = found && let ty::Tuple(expected) = expected.kind() && let ty::Tuple(found)= found.kind() && expected.len() == found.len() { let mut suggestion = "|".to_string(); let mut is_first = true; let mut has_suggestion = false; 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 { suggestion += ", "; } if let ty::Ref(expected_region, _, _) = expected.kind() && let ty::Ref(found_region, _, _) = found.kind() && expected_region.is_late_bound() && !found_region.is_late_bound() && 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 `: &_`. 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(param_hir.span) else { return; }; // Otherwise, keep it as-is. suggestion += &arg; } } suggestion += "|"; if has_suggestion { diag.span_suggestion_verbose( span, "consider specifying the type of the closure parameters", suggestion, Applicability::MaybeIncorrect, ); } } } </ins> } impl<'tcx> TypeErrCtxt<'_, 'tcx> {

<ins> fn thing(x: impl FnOnce(&u32, &u32, u32)) {} fn main() { let f = | _ , y: &u32 , z | (); thing(f); //~^ ERROR mismatched types //~^^ ERROR mismatched types let f = | x, y: _  , z: u32 | (); thing(f); //~^ ERROR mismatched types //~^^ ERROR mismatched types //~^^^ ERROR implementation of `FnOnce` is not general enough //~^^^^ ERROR implementation of `FnOnce` is not general enough } </ins>

<ins> error[E0308]: mismatched types --> $DIR/issue-105675.rs:5:5 | LL |     thing(f); |     ^^^^^^^^ one type is more general than the other | = 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 = | _ , y: &u32 , z | (); |             ^^^^^^^^^^^^^^^^^^^ note: the lifetime requirement is introduced here --> $DIR/issue-105675.rs:1:18 | LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} |                  ^^^^^^^^^^^^^^^^^^^^^^^ help: consider specifying the type of the closure parameters | LL |     let f = |_: &_, y: &u32, z| (); |             ~~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/issue-105675.rs:5:5 | LL |     thing(f); |     ^^^^^^^^ one type is more general than the other | = 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 = | _ , y: &u32 , z | (); |             ^^^^^^^^^^^^^^^^^^^ note: the lifetime requirement is introduced here --> $DIR/issue-105675.rs:1:18 | LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} |                  ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $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, u32)>` found trait `FnOnce<(&u32, &u32, u32)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:8:13 | 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, u32)) {} |                  ^^^^^^^^^^^^^^^^^^^^^^^ help: consider specifying the type of the closure parameters | LL |     let f = |x: &_, y: &_, z: u32| (); |             ~~~~~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types --> $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, u32)>` found trait `FnOnce<(&u32, &u32, u32)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:8:13 | 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, u32)) {} |                  ^^^^^^^^^^^^^^^^^^^^^^^ help: consider specifying the type of the closure parameters | LL |     let f = |x: &_, y: &_, z: u32| (); |             ~~~~~~~~~~~~~~~~~~~~~~ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 | LL |     thing(f); |     ^^^^^^^^ implementation of `FnOnce` is not general enough | = 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:9:5 | LL |     thing(f); |     ^^^^^^^^ implementation of `FnOnce` is not general enough | = 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 6 previous errors For more information about this error, try `rustc --explain E0308`. </ins>

| LL | fn take_foo(_: impl Foo) {} |                     ^^^ <ins> help: consider specifying the type of the closure parameters | LL |     take_foo(|a: &_| a); |              ~~~~~~~ </ins> error[E0308]: mismatched types --> $DIR/issue-79187-2.rs:11:5

| LL | fn thing(x: impl FnOnce(&u32)) {} |                  ^^^^^^^^^^^^ <ins> help: consider specifying the type of the closure parameters | LL |     let f = |_: &_| (); |             ~~~~~~~ </ins> error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5

baz(|_| ()); //~^ ERROR implementation of `FnOnce` is not general enough //~| ERROR mismatched types <ins> baz(|x| ()); //~^ ERROR implementation of `FnOnce` is not general enough //~| ERROR mismatched types </ins> }

| LL | fn baz<T: Foo>(_: T) {} |           ^^^ <ins> help: consider specifying the type of the closure parameters | LL |     baz(|_: &_| ()); |         ~~~~~~~ error: implementation of `FnOnce` is not general enough --> $DIR/closure-mismatch.rs:11:5 | LL |     baz(|x| ()); |     ^^^^^^^^^^^ implementation of `FnOnce` is not general enough | = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` error[E0308]: mismatched types --> $DIR/closure-mismatch.rs:11:5 | LL |     baz(|x| ()); |     ^^^^^^^^^^^ one type is more general than the other | = note: expected trait `for<'a> Fn<(&'a (),)>` found trait `Fn<(&(),)>` note: this closure does not fulfill the lifetime requirements --> $DIR/closure-mismatch.rs:11:9 | LL |     baz(|x| ()); |         ^^^ note: the lifetime requirement is introduced here --> $DIR/closure-mismatch.rs:5:11 | LL | fn baz<T: Foo>(_: T) {} |           ^^^ help: consider specifying the type of the closure parameters | LL |     baz(|x: &_| ()); |         ~~~~~~~ </ins> <del> error: aborting due to 2 previous errors </del> <ins> error: aborting due to 4 previous errors </ins> For more information about this error, try `rustc --explain E0308`.