@@ -281,7 +281,79 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
281281 }
282282
283283 // Coroutine-closures don't implement `Fn` traits the normal way.
284- ty:: CoroutineClosure ( ..) => Err ( NoSolution ) ,
284+ // Instead, they always implement `FnOnce`, but only implement
285+ // `FnMut`/`Fn` if they capture no upvars, since those may borrow
286+ // from the closure.
287+ ty:: CoroutineClosure ( def_id, args) => {
288+ let args = args. as_coroutine_closure ( ) ;
289+ let kind_ty = args. kind_ty ( ) ;
290+ let sig = args. coroutine_closure_sig ( ) . skip_binder ( ) ;
291+
292+ let coroutine_ty = if let Some ( closure_kind) = kind_ty. to_opt_closure_kind ( ) {
293+ if !closure_kind. extends ( goal_kind) {
294+ return Err ( NoSolution ) ;
295+ }
296+
297+ // If `Fn`/`FnMut`, we only implement this goal if we
298+ // have no captures.
299+ let no_borrows = match args. tupled_upvars_ty ( ) . kind ( ) {
300+ ty:: Tuple ( tys) => tys. is_empty ( ) ,
301+ ty:: Error ( _) => false ,
302+ _ => bug ! ( "tuple_fields called on non-tuple" ) ,
303+ } ;
304+ if closure_kind != ty:: ClosureKind :: FnOnce && !no_borrows {
305+ return Err ( NoSolution ) ;
306+ }
307+
308+ sig. to_coroutine_given_kind_and_upvars (
309+ tcx,
310+ args. parent_args ( ) ,
311+ tcx. coroutine_for_closure ( def_id) ,
312+ goal_kind,
313+ // No captures by ref, so this doesn't matter.
314+ tcx. lifetimes . re_static ,
315+ args. tupled_upvars_ty ( ) ,
316+ args. coroutine_captures_by_ref_ty ( ) ,
317+ )
318+ } else {
319+ // Closure kind is not yet determined, so we return ambiguity unless
320+ // the expected kind is `FnOnce` as that is always implemented.
321+ if goal_kind != ty:: ClosureKind :: FnOnce {
322+ return Ok ( None ) ;
323+ }
324+
325+ let async_fn_kind_trait_def_id =
326+ tcx. require_lang_item ( LangItem :: AsyncFnKindHelper , None ) ;
327+ let upvars_projection_def_id = tcx
328+ . associated_items ( async_fn_kind_trait_def_id)
329+ . filter_by_name_unhygienic ( sym:: Upvars )
330+ . next ( )
331+ . unwrap ( )
332+ . def_id ;
333+ let tupled_upvars_ty = Ty :: new_projection (
334+ tcx,
335+ upvars_projection_def_id,
336+ [
337+ ty:: GenericArg :: from ( kind_ty) ,
338+ Ty :: from_closure_kind ( tcx, goal_kind) . into ( ) ,
339+ // No captures by ref, so this doesn't matter.
340+ tcx. lifetimes . re_static . into ( ) ,
341+ sig. tupled_inputs_ty . into ( ) ,
342+ args. tupled_upvars_ty ( ) . into ( ) ,
343+ args. coroutine_captures_by_ref_ty ( ) . into ( ) ,
344+ ] ,
345+ ) ;
346+ sig. to_coroutine (
347+ tcx,
348+ args. parent_args ( ) ,
349+ Ty :: from_closure_kind ( tcx, goal_kind) ,
350+ tcx. coroutine_for_closure ( def_id) ,
351+ tupled_upvars_ty,
352+ )
353+ } ;
354+
355+ Ok ( Some ( args. coroutine_closure_sig ( ) . rebind ( ( sig. tupled_inputs_ty , coroutine_ty) ) ) )
356+ }
285357
286358 ty:: Bool
287359 | ty:: Char
0 commit comments