@@ -643,81 +643,8 @@ pub trait PrettyPrinter<'tcx>:
643
643
}
644
644
return Ok ( self ) ;
645
645
}
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
646
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)
721
648
} ) ;
722
649
}
723
650
ty:: Str => p ! ( "str" ) ,
@@ -826,6 +753,208 @@ pub trait PrettyPrinter<'tcx>:
826
753
Ok ( self )
827
754
}
828
755
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
+
829
958
fn pretty_print_bound_var (
830
959
& mut self ,
831
960
debruijn : ty:: DebruijnIndex ,
@@ -2553,3 +2682,10 @@ fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
2553
2682
pub fn provide ( providers : & mut ty:: query:: Providers ) {
2554
2683
* providers = ty:: query:: Providers { trimmed_def_paths, ..* providers } ;
2555
2684
}
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