@@ -611,9 +611,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
611
611
// function.
612
612
Some ( hir:: GeneratorKind :: Async ( hir:: AsyncGeneratorKind :: Fn ) ) => {
613
613
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)
617
615
}
618
616
619
617
_ => astconv. ty_infer ( None , decl. output . span ( ) ) ,
@@ -639,6 +637,104 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
639
637
result
640
638
}
641
639
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
+
642
738
/// Converts the types that the user supplied, in case that doing
643
739
/// so should yield an error, but returns back a signature where
644
740
/// all parameters are of type `TyErr`.
0 commit comments