@@ -281,7 +281,79 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
281
281
}
282
282
283
283
// 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
+ }
285
357
286
358
ty:: Bool
287
359
| ty:: Char
0 commit comments