@@ -611,9 +611,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
611611 // function.
612612 Some ( hir:: GeneratorKind :: Async ( hir:: AsyncGeneratorKind :: Fn ) ) => {
613613 debug ! ( "supplied_sig_of_closure: closure is async fn body" ) ;
614-
615- // FIXME
616- astconv. ty_infer ( None , decl. output . span ( ) )
614+ self . deduce_future_output_from_obligations ( expr_def_id)
617615 }
618616
619617 _ => astconv. ty_infer ( None , decl. output . span ( ) ) ,
@@ -639,6 +637,104 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
639637 result
640638 }
641639
640+ /// Invoked when we are translating the generator that results
641+ /// from desugaring an `async fn`. Returns the "sugared" return
642+ /// type of the `async fn` -- that is, the return type that the
643+ /// user specified. The "desugared" return type is a `impl
644+ /// Future<Output = T>`, so we do this by searching through the
645+ /// obligations to extract the `T`.
646+ fn deduce_future_output_from_obligations (
647+ & self ,
648+ expr_def_id : DefId ,
649+ ) -> Ty < ' tcx > {
650+ debug ! ( "deduce_future_output_from_obligations(expr_def_id={:?})" , expr_def_id) ;
651+
652+ let ret_coercion =
653+ self . ret_coercion
654+ . as_ref ( )
655+ . unwrap_or_else ( || span_bug ! (
656+ self . tcx. def_span( expr_def_id) ,
657+ "async fn generator outside of a fn"
658+ ) ) ;
659+
660+ // In practice, the return type of the surrounding function is
661+ // always a (not yet resolved) inference variable, because it
662+ // is the hidden type for an `impl Trait` that we are going to
663+ // be inferring.
664+ let ret_ty = ret_coercion. borrow ( ) . expected_ty ( ) ;
665+ let ret_ty = self . inh . infcx . shallow_resolve ( ret_ty) ;
666+ let ret_vid = match ret_ty. sty {
667+ ty:: Infer ( ty:: TyVar ( ret_vid) ) => ret_vid,
668+ _ => {
669+ span_bug ! (
670+ self . tcx. def_span( expr_def_id) ,
671+ "async fn generator return type not an inference variable"
672+ )
673+ }
674+ } ;
675+
676+ // Search for a pending obligation like
677+ //
678+ // `<R as Future>::Output = T`
679+ //
680+ // where R is the return type we are expecting. This type `T`
681+ // will be our output.
682+ let output_ty = self . obligations_for_self_ty ( ret_vid)
683+ . find_map ( |( _, obligation) | {
684+ if let ty:: Predicate :: Projection ( ref proj_predicate) = obligation. predicate {
685+ self . deduce_future_output_from_projection (
686+ obligation. cause . span ,
687+ proj_predicate
688+ )
689+ } else {
690+ None
691+ }
692+ } )
693+ . unwrap ( ) ;
694+
695+ debug ! ( "deduce_future_output_from_obligations: output_ty={:?}" , output_ty) ;
696+ output_ty
697+ }
698+
699+ /// Given a projection like
700+ ///
701+ /// `<_ as Future>::Output = T`
702+ ///
703+ /// returns `Some(T)`. If the projection is for some other trait,
704+ /// returns `None`.
705+ fn deduce_future_output_from_projection (
706+ & self ,
707+ cause_span : Span ,
708+ projection : & ty:: PolyProjectionPredicate < ' tcx > ,
709+ ) -> Option < Ty < ' tcx > > {
710+ debug ! ( "deduce_future_output_from_projection(projection={:?})" , projection) ;
711+
712+ let trait_ref = projection. to_poly_trait_ref ( self . tcx ) ;
713+ let future_trait = self . tcx . lang_items ( ) . future_trait ( ) . unwrap ( ) ;
714+ if trait_ref. def_id ( ) != future_trait {
715+ debug ! ( "deduce_future_output_from_projection: not a future" ) ;
716+ return None ;
717+ }
718+
719+ // The `Future` trait has only one associted item, `Output`,
720+ // so check that this is what we see.
721+ let output_assoc_item = self . tcx . associated_items ( future_trait) . nth ( 0 ) . unwrap ( ) . def_id ;
722+ if output_assoc_item != projection. projection_def_id ( ) {
723+ span_bug ! (
724+ cause_span,
725+ "projecting associated item `{:?}` from future, which is not Output `{:?}`" ,
726+ projection. projection_def_id( ) ,
727+ output_assoc_item,
728+ ) ;
729+ }
730+
731+ // Extract the type from the projection.
732+ let output_ty = projection. skip_binder ( ) . ty ;
733+ let output_ty = self . resolve_vars_if_possible ( & output_ty) ;
734+ debug ! ( "deduce_future_output_from_projection: output_ty={:?}" , output_ty) ;
735+ Some ( output_ty)
736+ }
737+
642738 /// Converts the types that the user supplied, in case that doing
643739 /// so should yield an error, but returns back a signature where
644740 /// all parameters are of type `TyErr`.
0 commit comments