@@ -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
-
701
- if is_future {
702
- p ! ( write( "{}Future" , if first { " " } else { " + " } ) ) ;
703
- first = false ;
704
646
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,225 @@ 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 ! ( ")" ) ;
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
+
829
975
fn pretty_print_bound_var (
830
976
& mut self ,
831
977
debruijn : ty:: DebruijnIndex ,
@@ -2553,3 +2699,12 @@ fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
2553
2699
pub fn provide ( providers : & mut ty:: query:: Providers ) {
2554
2700
* providers = ty:: query:: Providers { trimmed_def_paths, ..* providers } ;
2555
2701
}
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