Change:
I'm writing this as a continuation of 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 : 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 most recently worked on: Not 100% sure, some explanations have been made in original issue
This is because the signature of  is: We only extract an async closure bound from cases where there is bound on the trait, which is not. There isn't even a supertrait bound that constrains the output type. I also do not expect this to ever be fixed, because that would require overly complicating the closure signature inference algorithm in ways that make me quite uncomfortable[^1][^2]. The correct solution is to rework the futures crate to have first-class async closure support, so for now I'd recommend just ascribing your type names. Sorry! [^1]: Firstly, this would break if another blanket implementation for were ever . [^2]: Secondly, the combinator shouldn't really be using bounds either -- it should be using bounds.
Alternatively, would fix this when paired with a slight adjustment to the closure signature inference that I'd be happy to make, but it seems like that PR is blocked.

Discussion:
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, GenericArgs, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; <del> use rustc_span::Span; </del> <ins> use rustc_span::{Span, DUMMY_SP}; </ins> use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::traits::ArgKind; use rustc_trait_selection::traits;

/// 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. <ins> /// /// This function is actually best-effort with the return type; if we don't find a /// `Future` projection, we still will return arguments that we extracted from the `FnOnce` /// projection, and the output will be an unconstrained type variable instead. </ins> fn extract_sig_from_projection_and_future_bound( &self, cause_span: Option<Span>,

}; // FIXME: We may want to elaborate here, though I assume this will be exceedingly rare. <ins> let mut return_ty = None; </ins> 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) { <del> 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 }); </del> <ins> return_ty = Some(ret_projection.term.expect_type()); break; </ins> } } <del> None </del> <ins> // SUBTLE: If we didn't find a `Future<Output = ...>` bound for the return // vid, we still want to attempt to provide inference guidance for the async // closure's arguments. Instantiate a new vid to plug into the output type. // // You may be wondering, what if it's higher-ranked? Well, given that we // found a type variable for the `FnOnce::Output` projection above, we know // that the output can't mention any of the vars. // // Also note that we use a fresh var here for the signature since the signature // records the output of the *future*, and `return_vid` above is the type // variable of the future, not its output. // // FIXME: We probably should store this signature inference output in a way // that does not misuse a `FnSig` type, but that can be done separately. let return_ty = return_ty.unwrap_or_else(|| self.next_ty_var(cause_span.unwrap_or(DUMMY_SP))); let sig = projection.rebind(self.tcx.mk_fn_sig( input_tys, return_ty, false, hir::Safety::Safe, Abi::Rust, )); return Some(ExpectedSig { cause_span, sig }); </ins> } fn sig_of_closure(

<ins> //@ check-pass //@ edition: 2021 // Make sure that we infer the args of an async closure even if it's passed to // a function that requires the async closure implement `Fn*` but does *not* have // a `Future` bound on the return type. #![feature(async_closure)] use std::future::Future; trait TryStream { type Ok; type Err; } trait TryFuture { type Ok; type Err; } impl<F, T, E> TryFuture for F where F: Future<Output = Result<T, E>> { type Ok = T; type Err = E; } trait TryStreamExt: TryStream { fn try_for_each<F, Fut>(&self, f: F) where F: FnMut(Self::Ok) -> Fut, Fut: TryFuture<Ok = (), Err = Self::Err>; } impl<S> TryStreamExt for S where S: TryStream { fn try_for_each<F, Fut>(&self, f: F) where F: FnMut(Self::Ok) -> Fut, Fut: TryFuture<Ok = (), Err = Self::Err>, { } } fn test(stream: impl TryStream<Ok = &'static str, Err = ()>) { stream.try_for_each(async |s| { s.trim(); // Make sure we know the type of `s` at this point. Ok(()) }); } fn main() {} </ins>