Change:
When using async closures, rust since around 1.80 fails to infer parameter type in most scenarios. I expected to see this happen: All options used to work in past versions of rust Instead, this happened: Without explicit type hint it fails It used to work in the past, around 1.79
We don't typically mark nightly features with labels, so I'm removing those. Are you certain this regressed in 1.80? This should have regressed in , when I reimplemented async closures completely.
I am not 100% sure when it happened. I used to work with 1.7x a couple of months ago. Then I left my project for a moment. When I came back, after updating to 1.81 it no longer works. IIRC before leaving it was around 1.79, but I'm not sure.
This limitation to async closure signature inference has to do with the fact that the combinators you're using (e.g. ) take regular trait bounds. Is there a particular reason you're using async closures here? They're really not gaining you anything other than a dependency on the nightly compiler.
I posted a minimal example, indeed async does not make much sense here, but in project I work on it does. As a workaround I've just annotated parameters with original types, but I still believe this is a bug.
This indeed regressed in .
While the problem from first message in issue seems to be fixed, there are still cases when this fails. One of examples is when using instead of , when closure is expected to return : Should I open new issue, or this one will be reopened?
Please open a new issue, since it's likely a different root cause

Discussion:
if let Some(trait_def_id) = trait_def_id { let found_kind = match closure_kind { hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id), <del> hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => { self.tcx.async_fn_trait_kind_from_def_id(trait_def_id) } </del> <ins> hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self .tcx .async_fn_trait_kind_from_def_id(trait_def_id) .or_else(|| self.tcx.fn_trait_kind_from_def_id(trait_def_id)), </ins> _ => None, };

// for closures and async closures, respectively. match closure_kind { hir::ClosureKind::Closure <del> if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() => {} </del> <ins> if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() => { self.extract_sig_from_projection(cause_span, projection) } hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() => { self.extract_sig_from_projection(cause_span, projection) } // It's possible we've passed the closure to a (somewhat out-of-fashion) // `F: FnOnce() -> Fut, Fut: Future<Output = T>` style bound. Let's still // guide inference here, since it's beneficial for the user. </ins> hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) <del> if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() => {} _ => return None, </del> <ins> if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() => { self.extract_sig_from_projection_and_future_bound(cause_span, projection) } _ => None, </ins> } <ins> } /// Given an `FnOnce::Output` or `AsyncFn::Output` projection, extract the args /// and return type to infer a [`ty::PolyFnSig`] for the closure. fn extract_sig_from_projection( &self, cause_span: Option<Span>, projection: ty::PolyProjectionPredicate<'tcx>, ) -> Option<ExpectedSig<'tcx>> { let projection = self.resolve_vars_if_possible(projection); </ins> let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1); <del> let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty); </del> debug!(?arg_param_ty); let ty::Tuple(input_tys) = *arg_param_ty.kind() else {

// Since this is a return parameter type it is safe to unwrap. let ret_param_ty = projection.skip_binder().term.expect_type(); <del> let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty); </del> debug!(?ret_param_ty); let sig = projection.rebind(self.tcx.mk_fn_sig(

Some(ExpectedSig { cause_span, sig }) } <ins> /// When an async closure is passed to a function that has a "two-part" `Fn` /// and `Future` trait bound, like: /// /// ```rust /// use std::future::Future; /// /// fn not_exactly_an_async_closure<F, Fut>(_f: F) /// where ///     F: FnOnce(String, u32) -> Fut, ///     Fut: Future<Output = i32>, /// {} /// ``` /// /// The we want to be able to extract the signature to guide inference in the async /// closure. We will have two projection predicates registered in this case. First, /// we identify the `FnOnce<Args, Output = ?Fut>` bound, and if the output type is /// an inference variable `?Fut`, we check if that is bounded by a `Future<Output = Ty>` /// projection. fn extract_sig_from_projection_and_future_bound( &self, cause_span: Option<Span>, projection: ty::PolyProjectionPredicate<'tcx>, ) -> Option<ExpectedSig<'tcx>> { let projection = self.resolve_vars_if_possible(projection); let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1); debug!(?arg_param_ty); let ty::Tuple(input_tys) = *arg_param_ty.kind() else { return None; }; // If the return type is a type variable, look for bounds on it. // We could theoretically support other kinds of return types here, // but none of them would be useful, since async closures return // concrete anonymous future types, and their futures are not coerced // into any other type within the body of the async closure. let ty::Infer(ty::TyVar(return_vid)) = *projection.skip_binder().term.expect_type().kind() else { return None; }; // FIXME: We may want to elaborate here, though I assume this will be exceedingly rare. for bound in self.obligations_for_self_ty(return_vid) { if let Some(ret_projection) = bound.predicate.as_projection_clause() && let Some(ret_projection) = ret_projection.no_bound_vars() && self.tcx.is_lang_item(ret_projection.def_id(), LangItem::FutureOutput) { let sig = projection.rebind(self.tcx.mk_fn_sig( input_tys, ret_projection.term.expect_type(), false, hir::Safety::Safe, Abi::Rust, )); return Some(ExpectedSig { cause_span, sig }); } } None } </ins> fn sig_of_closure( &self, expr_def_id: LocalDefId,

<ins> //@ edition: 2021 //@ check-pass //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver #![feature(async_closure)] use std::future::Future; use std::any::Any; struct Struct; impl Struct { fn method(&self) {} } fn fake_async_closure<F, Fut>(_: F) where F: Fn(Struct) -> Fut, Fut: Future<Output = ()>, {} fn main() { fake_async_closure(async |s| { s.method(); }) } </ins>