@@ -643,81 +643,8 @@ pub trait PrettyPrinter<'tcx>:
643643 }
644644 return Ok ( self ) ;
645645 }
646- // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
647- // by looking up the projections associated with the def_id.
648- let bounds = self . tcx ( ) . explicit_item_bounds ( def_id) ;
649-
650- let mut first = true ;
651- let mut is_sized = false ;
652- let mut is_future = false ;
653- let mut future_output_ty = None ;
654-
655- p ! ( "impl" ) ;
656- for ( predicate, _) in bounds {
657- let predicate = predicate. subst ( self . tcx ( ) , substs) ;
658- let bound_predicate = predicate. kind ( ) ;
659-
660- match bound_predicate. skip_binder ( ) {
661- ty:: PredicateKind :: Projection ( projection_predicate) => {
662- let Some ( future_trait) = self . tcx ( ) . lang_items ( ) . future_trait ( ) else { continue } ;
663- let future_output_def_id =
664- self . tcx ( ) . associated_item_def_ids ( future_trait) [ 0 ] ;
665-
666- if projection_predicate. projection_ty . item_def_id
667- == future_output_def_id
668- {
669- // We don't account for multiple `Future::Output = Ty` contraints.
670- is_future = true ;
671- future_output_ty = Some ( projection_predicate. ty ) ;
672- }
673- }
674- ty:: PredicateKind :: Trait ( pred) => {
675- let trait_ref = bound_predicate. rebind ( pred. trait_ref ) ;
676- // Don't print +Sized, but rather +?Sized if absent.
677- if Some ( trait_ref. def_id ( ) ) == self . tcx ( ) . lang_items ( ) . sized_trait ( )
678- {
679- is_sized = true ;
680- continue ;
681- }
682-
683- if Some ( trait_ref. def_id ( ) )
684- == self . tcx ( ) . lang_items ( ) . future_trait ( )
685- {
686- is_future = true ;
687- continue ;
688- }
689-
690- p ! (
691- write( "{}" , if first { " " } else { " + " } ) ,
692- print( trait_ref. print_only_trait_path( ) )
693- ) ;
694-
695- first = false ;
696- }
697- _ => { }
698- }
699- }
700-
701- if is_future {
702- p ! ( write( "{}Future" , if first { " " } else { " + " } ) ) ;
703- first = false ;
704646
705- if let Some ( future_output_ty) = future_output_ty {
706- // Don't print projection types, which we (unfortunately) see often
707- // in the error outputs involving async blocks.
708- if !matches ! ( future_output_ty. kind( ) , ty:: Projection ( _) ) {
709- p ! ( "<Output = " , print( future_output_ty) , ">" ) ;
710- }
711- }
712- }
713-
714- if !is_sized {
715- p ! ( write( "{}?Sized" , if first { " " } else { " + " } ) ) ;
716- } else if first {
717- p ! ( " Sized" ) ;
718- }
719-
720- Ok ( self )
647+ self . pretty_print_opaque_impl_type ( def_id, substs)
721648 } ) ;
722649 }
723650 ty:: Str => p ! ( "str" ) ,
@@ -826,6 +753,225 @@ pub trait PrettyPrinter<'tcx>:
826753 Ok ( self )
827754 }
828755
756+ fn pretty_print_opaque_impl_type (
757+ mut self ,
758+ def_id : DefId ,
759+ substs : & ' tcx ty:: List < ty:: GenericArg < ' tcx > > ,
760+ ) -> Result < Self :: Type , Self :: Error > {
761+ define_scoped_cx ! ( self ) ;
762+
763+ // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
764+ // by looking up the projections associated with the def_id.
765+ let bounds = self . tcx ( ) . explicit_item_bounds ( def_id) ;
766+
767+ let mut traits = BTreeMap :: new ( ) ;
768+ let mut fn_traits = BTreeMap :: new ( ) ;
769+ let mut is_sized = false ;
770+
771+ for ( predicate, _) in bounds {
772+ let predicate = predicate. subst ( self . tcx ( ) , substs) ;
773+ let bound_predicate = predicate. kind ( ) ;
774+
775+ match bound_predicate. skip_binder ( ) {
776+ ty:: PredicateKind :: Trait ( pred) => {
777+ let trait_ref = bound_predicate. rebind ( pred. trait_ref ) ;
778+
779+ // Don't print + Sized, but rather + ?Sized if absent.
780+ if Some ( trait_ref. def_id ( ) ) == self . tcx ( ) . lang_items ( ) . sized_trait ( ) {
781+ is_sized = true ;
782+ continue ;
783+ }
784+
785+ self . insert_trait_and_projection ( trait_ref, None , & mut traits, & mut fn_traits) ;
786+ }
787+ ty:: PredicateKind :: Projection ( pred) => {
788+ let proj_ref = bound_predicate. rebind ( pred) ;
789+ let trait_ref = proj_ref. required_poly_trait_ref ( self . tcx ( ) ) ;
790+
791+ // Projection type entry -- the def-id for naming, and the ty.
792+ let proj_ty = ( proj_ref. projection_def_id ( ) , proj_ref. ty ( ) ) ;
793+
794+ self . insert_trait_and_projection (
795+ trait_ref,
796+ Some ( proj_ty) ,
797+ & mut traits,
798+ & mut fn_traits,
799+ ) ;
800+ }
801+ _ => { }
802+ }
803+ }
804+
805+ let mut first = true ;
806+ // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
807+ let paren_needed = fn_traits. len ( ) > 1 || traits. len ( ) > 0 || !is_sized;
808+
809+ p ! ( "impl" ) ;
810+
811+ for ( fn_once_trait_ref, entry) in fn_traits {
812+ // Get the (single) generic ty (the args) of this FnOnce trait ref.
813+ let generics = self . generic_args_to_print (
814+ self . tcx ( ) . generics_of ( fn_once_trait_ref. def_id ( ) ) ,
815+ fn_once_trait_ref. skip_binder ( ) . substs ,
816+ ) ;
817+
818+ match ( entry. return_ty , generics[ 0 ] . expect_ty ( ) ) {
819+ // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded
820+ // a return type.
821+ ( Some ( return_ty) , arg_tys) if matches ! ( arg_tys. kind( ) , ty:: Tuple ( _) ) => {
822+ let name = if entry. fn_trait_ref . is_some ( ) {
823+ "Fn"
824+ } else if entry. fn_mut_trait_ref . is_some ( ) {
825+ "FnMut"
826+ } else {
827+ "FnOnce"
828+ } ;
829+
830+ p ! (
831+ write( "{}" , if first { " " } else { " + " } ) ,
832+ write( "{}{}(" , if paren_needed { "(" } else { "" } , name)
833+ ) ;
834+
835+ for ( idx, ty) in arg_tys. tuple_fields ( ) . enumerate ( ) {
836+ if idx > 0 {
837+ p ! ( ", " ) ;
838+ }
839+ p ! ( print( ty) ) ;
840+ }
841+
842+ p ! ( ")" ) ;
843+ if !return_ty. skip_binder ( ) . is_unit ( ) {
844+ p ! ( "-> " , print( return_ty) ) ;
845+ }
846+ p ! ( write( "{}" , if paren_needed { ")" } else { "" } ) ) ;
847+
848+ first = false ;
849+ }
850+ // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
851+ // trait_refs we collected in the OpaqueFnEntry as normal trait refs.
852+ _ => {
853+ if entry. has_fn_once {
854+ traits. entry ( fn_once_trait_ref) . or_default ( ) . extend (
855+ // Group the return ty with its def id, if we had one.
856+ entry
857+ . return_ty
858+ . map ( |ty| ( self . tcx ( ) . lang_items ( ) . fn_once_output ( ) . unwrap ( ) , ty) ) ,
859+ ) ;
860+ }
861+ if let Some ( trait_ref) = entry. fn_mut_trait_ref {
862+ traits. entry ( trait_ref) . or_default ( ) ;
863+ }
864+ if let Some ( trait_ref) = entry. fn_trait_ref {
865+ traits. entry ( trait_ref) . or_default ( ) ;
866+ }
867+ }
868+ }
869+ }
870+
871+ // Print the rest of the trait types (that aren't Fn* family of traits)
872+ for ( trait_ref, assoc_items) in traits {
873+ p ! (
874+ write( "{}" , if first { " " } else { " + " } ) ,
875+ print( trait_ref. skip_binder( ) . print_only_trait_name( ) )
876+ ) ;
877+
878+ let generics = self . generic_args_to_print (
879+ self . tcx ( ) . generics_of ( trait_ref. def_id ( ) ) ,
880+ trait_ref. skip_binder ( ) . substs ,
881+ ) ;
882+
883+ if !generics. is_empty ( ) || !assoc_items. is_empty ( ) {
884+ p ! ( "<" ) ;
885+ let mut first = true ;
886+
887+ for ty in generics {
888+ if !first {
889+ p ! ( ", " ) ;
890+ }
891+ p ! ( print( trait_ref. rebind( * ty) ) ) ;
892+ first = false ;
893+ }
894+
895+ for ( assoc_item_def_id, ty) in assoc_items {
896+ if !first {
897+ p ! ( ", " ) ;
898+ }
899+ p ! ( write( "{} = " , self . tcx( ) . associated_item( assoc_item_def_id) . ident) ) ;
900+
901+ // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
902+ match ty. skip_binder ( ) . kind ( ) {
903+ ty:: Projection ( ty:: ProjectionTy { item_def_id, .. } )
904+ if Some ( * item_def_id) == self . tcx ( ) . lang_items ( ) . generator_return ( ) =>
905+ {
906+ p ! ( "[async output]" )
907+ }
908+ _ => {
909+ p ! ( print( ty) )
910+ }
911+ }
912+
913+ first = false ;
914+ }
915+
916+ p ! ( ">" ) ;
917+ }
918+
919+ first = false ;
920+ }
921+
922+ if !is_sized {
923+ p ! ( write( "{}?Sized" , if first { " " } else { " + " } ) ) ;
924+ } else if first {
925+ p ! ( " Sized" ) ;
926+ }
927+
928+ Ok ( self )
929+ }
930+
931+ /// Insert the trait ref and optionally a projection type associated with it into either the
932+ /// traits map or fn_traits map, depending on if the trait is in the Fn* family of traits.
933+ fn insert_trait_and_projection (
934+ & mut self ,
935+ trait_ref : ty:: PolyTraitRef < ' tcx > ,
936+ proj_ty : Option < ( DefId , ty:: Binder < ' tcx , Ty < ' tcx > > ) > ,
937+ traits : & mut BTreeMap < ty:: PolyTraitRef < ' tcx > , BTreeMap < DefId , ty:: Binder < ' tcx , Ty < ' tcx > > > > ,
938+ fn_traits : & mut BTreeMap < ty:: PolyTraitRef < ' tcx > , OpaqueFnEntry < ' tcx > > ,
939+ ) {
940+ let trait_def_id = trait_ref. def_id ( ) ;
941+
942+ // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
943+ // super-trait ref and record it there.
944+ if let Some ( fn_once_trait) = self . tcx ( ) . lang_items ( ) . fn_once_trait ( ) {
945+ // If we have a FnOnce, then insert it into
946+ if trait_def_id == fn_once_trait {
947+ let entry = fn_traits. entry ( trait_ref) . or_default ( ) ;
948+ // Optionally insert the return_ty as well.
949+ if let Some ( ( _, ty) ) = proj_ty {
950+ entry. return_ty = Some ( ty) ;
951+ }
952+ entry. has_fn_once = true ;
953+ return ;
954+ } else if Some ( trait_def_id) == self . tcx ( ) . lang_items ( ) . fn_mut_trait ( ) {
955+ let super_trait_ref = crate :: traits:: util:: supertraits ( self . tcx ( ) , trait_ref)
956+ . find ( |super_trait_ref| super_trait_ref. def_id ( ) == fn_once_trait)
957+ . unwrap ( ) ;
958+
959+ fn_traits. entry ( super_trait_ref) . or_default ( ) . fn_mut_trait_ref = Some ( trait_ref) ;
960+ return ;
961+ } else if Some ( trait_def_id) == self . tcx ( ) . lang_items ( ) . fn_trait ( ) {
962+ let super_trait_ref = crate :: traits:: util:: supertraits ( self . tcx ( ) , trait_ref)
963+ . find ( |super_trait_ref| super_trait_ref. def_id ( ) == fn_once_trait)
964+ . unwrap ( ) ;
965+
966+ fn_traits. entry ( super_trait_ref) . or_default ( ) . fn_trait_ref = Some ( trait_ref) ;
967+ return ;
968+ }
969+ }
970+
971+ // Otherwise, just group our traits and projection types.
972+ traits. entry ( trait_ref) . or_default ( ) . extend ( proj_ty) ;
973+ }
974+
829975 fn pretty_print_bound_var (
830976 & mut self ,
831977 debruijn : ty:: DebruijnIndex ,
@@ -2553,3 +2699,12 @@ fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
25532699pub fn provide ( providers : & mut ty:: query:: Providers ) {
25542700 * providers = ty:: query:: Providers { trimmed_def_paths, ..* providers } ;
25552701}
2702+
2703+ #[ derive( Default ) ]
2704+ pub struct OpaqueFnEntry < ' tcx > {
2705+ // The trait ref is already stored as a key, so just track if we have it as a real predicate
2706+ has_fn_once : bool ,
2707+ fn_mut_trait_ref : Option < ty:: PolyTraitRef < ' tcx > > ,
2708+ fn_trait_ref : Option < ty:: PolyTraitRef < ' tcx > > ,
2709+ return_ty : Option < ty:: Binder < ' tcx , Ty < ' tcx > > > ,
2710+ }
0 commit comments