@@ -14,7 +14,7 @@ use rustc_middle::span_bug;
1414use rustc_middle:: ty:: visit:: { TypeVisitable , TypeVisitableExt } ;
1515use rustc_middle:: ty:: { self , GenericArgs , Ty , TyCtxt , TypeSuperVisitable , TypeVisitor } ;
1616use rustc_span:: def_id:: LocalDefId ;
17- use rustc_span:: Span ;
17+ use rustc_span:: { Span , DUMMY_SP } ;
1818use rustc_target:: spec:: abi:: Abi ;
1919use rustc_trait_selection:: error_reporting:: traits:: ArgKind ;
2020use rustc_trait_selection:: traits;
@@ -539,6 +539,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
539539 /// we identify the `FnOnce<Args, Output = ?Fut>` bound, and if the output type is
540540 /// an inference variable `?Fut`, we check if that is bounded by a `Future<Output = Ty>`
541541 /// projection.
542+ ///
543+ /// This function is actually best-effort with the return type; if we don't find a
544+ /// `Future` projection, we still will return arguments that we extracted from the `FnOnce`
545+ /// projection, and the output will be an unconstrained type variable instead.
542546 fn extract_sig_from_projection_and_future_bound (
543547 & self ,
544548 cause_span : Option < Span > ,
@@ -564,24 +568,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
564568 } ;
565569
566570 // FIXME: We may want to elaborate here, though I assume this will be exceedingly rare.
571+ let mut return_ty = None ;
567572 for bound in self . obligations_for_self_ty ( return_vid) {
568573 if let Some ( ret_projection) = bound. predicate . as_projection_clause ( )
569574 && let Some ( ret_projection) = ret_projection. no_bound_vars ( )
570575 && self . tcx . is_lang_item ( ret_projection. def_id ( ) , LangItem :: FutureOutput )
571576 {
572- let sig = projection. rebind ( self . tcx . mk_fn_sig (
573- input_tys,
574- ret_projection. term . expect_type ( ) ,
575- false ,
576- hir:: Safety :: Safe ,
577- Abi :: Rust ,
578- ) ) ;
579-
580- return Some ( ExpectedSig { cause_span, sig } ) ;
577+ return_ty = Some ( ret_projection. term . expect_type ( ) ) ;
578+ break ;
581579 }
582580 }
583581
584- None
582+ // SUBTLE: If we didn't find a `Future<Output = ...>` bound for the return
583+ // vid, we still want to attempt to provide inference guidance for the async
584+ // closure's arguments. Instantiate a new vid to plug into the output type.
585+ //
586+ // You may be wondering, what if it's higher-ranked? Well, given that we
587+ // found a type variable for the `FnOnce::Output` projection above, we know
588+ // that the output can't mention any of the vars.
589+ //
590+ // Also note that we use a fresh var here for the signature since the signature
591+ // records the output of the *future*, and `return_vid` above is the type
592+ // variable of the future, not its output.
593+ //
594+ // FIXME: We probably should store this signature inference output in a way
595+ // that does not misuse a `FnSig` type, but that can be done separately.
596+ let return_ty =
597+ return_ty. unwrap_or_else ( || self . next_ty_var ( cause_span. unwrap_or ( DUMMY_SP ) ) ) ;
598+
599+ let sig = projection. rebind ( self . tcx . mk_fn_sig (
600+ input_tys,
601+ return_ty,
602+ false ,
603+ hir:: Safety :: Safe ,
604+ Abi :: Rust ,
605+ ) ) ;
606+
607+ return Some ( ExpectedSig { cause_span, sig } ) ;
585608 }
586609
587610 fn sig_of_closure (
0 commit comments