@@ -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- }
700646
701- if is_future {
702- p ! ( write( "{}Future" , if first { " " } else { " + " } ) ) ;
703- first = false ;
704-
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,208 @@ 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 ! ( ") -> " , print( return_ty) , write( "{}" , if paren_needed { ")" } else { "" } ) ) ;
843+
844+ first = false ;
845+ }
846+ // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
847+ // trait_refs we collected in the OpaqueFnEntry as normal trait refs.
848+ _ => {
849+ traits. entry ( fn_once_trait_ref) . or_default ( ) . extend (
850+ // Group the return ty with its def id, if we had one.
851+ entry
852+ . return_ty
853+ . map ( |ty| ( self . tcx ( ) . lang_items ( ) . fn_once_output ( ) . unwrap ( ) , ty) ) ,
854+ ) ;
855+ if let Some ( trait_ref) = entry. fn_mut_trait_ref {
856+ traits. entry ( trait_ref) . or_default ( ) ;
857+ }
858+ if let Some ( trait_ref) = entry. fn_trait_ref {
859+ traits. entry ( trait_ref) . or_default ( ) ;
860+ }
861+ }
862+ }
863+ }
864+
865+ // Print the rest of the trait types (that aren't Fn* family of traits)
866+ for ( trait_ref, assoc_items) in traits {
867+ p ! (
868+ write( "{}" , if first { " " } else { " + " } ) ,
869+ print( trait_ref. skip_binder( ) . print_only_trait_name( ) )
870+ ) ;
871+
872+ let generics = self . generic_args_to_print (
873+ self . tcx ( ) . generics_of ( trait_ref. def_id ( ) ) ,
874+ trait_ref. skip_binder ( ) . substs ,
875+ ) ;
876+
877+ if !generics. is_empty ( ) || !assoc_items. is_empty ( ) {
878+ p ! ( "<" ) ;
879+ let mut first = true ;
880+
881+ for ty in generics {
882+ if !first {
883+ p ! ( ", " ) ;
884+ }
885+ p ! ( print( trait_ref. rebind( * ty) ) ) ;
886+ first = false ;
887+ }
888+
889+ for ( assoc_item_def_id, ty) in assoc_items {
890+ if !first {
891+ p ! ( ", " ) ;
892+ }
893+ p ! (
894+ write( "{} = " , self . tcx( ) . associated_item( assoc_item_def_id) . ident) ,
895+ print( ty)
896+ ) ;
897+ first = false ;
898+ }
899+
900+ p ! ( ">" ) ;
901+ }
902+
903+ first = false ;
904+ }
905+
906+ if !is_sized {
907+ p ! ( write( "{}?Sized" , if first { " " } else { " + " } ) ) ;
908+ } else if first {
909+ p ! ( " Sized" ) ;
910+ }
911+
912+ Ok ( self )
913+ }
914+
915+ /// Insert the trait ref and optionally a projection type associated with it into either the
916+ /// traits map or fn_traits map, depending on if the trait is in the Fn* family of traits.
917+ fn insert_trait_and_projection (
918+ & mut self ,
919+ trait_ref : ty:: PolyTraitRef < ' tcx > ,
920+ proj_ty : Option < ( DefId , ty:: Binder < ' tcx , Ty < ' tcx > > ) > ,
921+ traits : & mut BTreeMap < ty:: PolyTraitRef < ' tcx > , BTreeMap < DefId , ty:: Binder < ' tcx , Ty < ' tcx > > > > ,
922+ fn_traits : & mut BTreeMap < ty:: PolyTraitRef < ' tcx > , OpaqueFnEntry < ' tcx > > ,
923+ ) {
924+ let trait_def_id = trait_ref. def_id ( ) ;
925+
926+ // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
927+ // super-trait ref and record it there.
928+ if let Some ( fn_once_trait) = self . tcx ( ) . lang_items ( ) . fn_once_trait ( ) {
929+ // If we have a FnOnce, then insert it into
930+ if trait_def_id == fn_once_trait {
931+ let entry = fn_traits. entry ( trait_ref) . or_default ( ) ;
932+ // Optionally insert the return_ty as well.
933+ if let Some ( ( _, ty) ) = proj_ty {
934+ entry. return_ty = Some ( ty) ;
935+ }
936+ return ;
937+ } else if Some ( trait_def_id) == self . tcx ( ) . lang_items ( ) . fn_mut_trait ( ) {
938+ let super_trait_ref = crate :: traits:: util:: supertraits ( self . tcx ( ) , trait_ref)
939+ . find ( |super_trait_ref| super_trait_ref. def_id ( ) == fn_once_trait)
940+ . unwrap ( ) ;
941+
942+ fn_traits. entry ( super_trait_ref) . or_default ( ) . fn_mut_trait_ref = Some ( trait_ref) ;
943+ return ;
944+ } else if Some ( trait_def_id) == self . tcx ( ) . lang_items ( ) . fn_trait ( ) {
945+ let super_trait_ref = crate :: traits:: util:: supertraits ( self . tcx ( ) , trait_ref)
946+ . find ( |super_trait_ref| super_trait_ref. def_id ( ) == fn_once_trait)
947+ . unwrap ( ) ;
948+
949+ fn_traits. entry ( super_trait_ref) . or_default ( ) . fn_trait_ref = Some ( trait_ref) ;
950+ return ;
951+ }
952+ }
953+
954+ // Otherwise, just group our traits and projection types.
955+ traits. entry ( trait_ref) . or_default ( ) . extend ( proj_ty) ;
956+ }
957+
829958 fn pretty_print_bound_var (
830959 & mut self ,
831960 debruijn : ty:: DebruijnIndex ,
@@ -2553,3 +2682,10 @@ fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
25532682pub fn provide ( providers : & mut ty:: query:: Providers ) {
25542683 * providers = ty:: query:: Providers { trimmed_def_paths, ..* providers } ;
25552684}
2685+
2686+ #[ derive( Default ) ]
2687+ pub struct OpaqueFnEntry < ' tcx > {
2688+ fn_mut_trait_ref : Option < ty:: PolyTraitRef < ' tcx > > ,
2689+ fn_trait_ref : Option < ty:: PolyTraitRef < ' tcx > > ,
2690+ return_ty : Option < ty:: Binder < ' tcx , Ty < ' tcx > > > ,
2691+ }
0 commit comments