@@ -352,6 +352,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
352352 /// will always be printed.)
353353 fn should_print_optional_region ( & self , region : ty:: Region < ' tcx > ) -> bool ;
354354
355+ /// Whether `pretty_print_type` should wrap a multi-bound `impl` / `dyn`
356+ /// inner in parens after a prefix type constructor (`&`, `&mut`, `*const`,
357+ /// `*mut`), so the output is `&(impl A + B)` rather than the parser-
358+ /// ambiguous `&impl A + B`. Byte-stable printers (mangling, `type_name`)
359+ /// override this to `false`.
360+ fn add_disambiguating_parens_in_prefix_position ( & self ) -> bool {
361+ true
362+ }
363+
355364 fn reset_type_limit ( & mut self ) { }
356365
357366 // Defaults (should not be overridden):
@@ -723,15 +732,17 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
723732 }
724733 ty:: RawPtr ( ty, mutbl) => {
725734 write ! ( self , "*{} " , mutbl. ptr_str( ) ) ?;
726- ty . print ( self ) ?;
735+ self . print_inner_with_disambiguating_parens ( ty ) ?;
727736 }
728737 ty:: Ref ( r, ty, mutbl) => {
729738 write ! ( self , "&" ) ?;
730739 if self . should_print_optional_region ( r) {
731740 r. print ( self ) ?;
732741 write ! ( self , " " ) ?;
733742 }
734- ty:: TypeAndMut { ty, mutbl } . print ( self ) ?;
743+ // `&mut (impl A + B)`, not `&(mut impl A + B)`: emit `mut ` before the parens.
744+ write ! ( self , "{}" , mutbl. prefix_str( ) ) ?;
745+ self . print_inner_with_disambiguating_parens ( ty) ?;
735746 }
736747 ty:: Never => write ! ( self , "!" ) ?,
737748 ty:: Tuple ( tys) => {
@@ -1071,6 +1082,121 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
10711082 Ok ( ( ) )
10721083 }
10731084
1085+ /// Prints `ty` after a prefix type constructor, wrapping in parens iff
1086+ /// [`Self::inner_needs_disambiguating_parens`] returns `true`.
1087+ fn print_inner_with_disambiguating_parens ( & mut self , ty : Ty < ' tcx > ) -> Result < ( ) , PrintError > {
1088+ let need_paren = self . inner_needs_disambiguating_parens ( ty) ;
1089+ if need_paren {
1090+ write ! ( self , "(" ) ?;
1091+ }
1092+ ty. print ( self ) ?;
1093+ if need_paren {
1094+ write ! ( self , ")" ) ?;
1095+ }
1096+ Ok ( ( ) )
1097+ }
1098+
1099+ /// Whether `ty`, sitting right after a prefix type constructor, would
1100+ /// print with a top-level `+`. Without the wrap, `&impl A + B` parses as
1101+ /// the ambiguous `(&impl A) + B`.
1102+ fn inner_needs_disambiguating_parens ( & self , ty : Ty < ' tcx > ) -> bool {
1103+ if !self . add_disambiguating_parens_in_prefix_position ( ) || self . should_print_verbose ( ) {
1104+ return false ;
1105+ }
1106+ match ty. kind ( ) {
1107+ // RPITIT trait-side appears as `Projection`, not `Opaque`.
1108+ ty:: Alias ( ty:: AliasTy { kind : ty:: Opaque { def_id } , args, .. } ) => {
1109+ self . opaque_has_multiple_bounds ( * def_id, args)
1110+ }
1111+ ty:: Alias ( ty:: AliasTy { kind : ty:: Projection { def_id } , args, .. } )
1112+ if self . tcx ( ) . is_impl_trait_in_trait ( * def_id) =>
1113+ {
1114+ self . opaque_has_multiple_bounds ( * def_id, args)
1115+ }
1116+ ty:: Dynamic ( predicates, region) => {
1117+ if self . should_print_optional_region ( * region) {
1118+ // `ty::Dynamic` self-wraps when it has an explicit region.
1119+ false
1120+ } else {
1121+ // Projections inline into the principal as `<Item = X>`;
1122+ // only principal/auto traits produce a top-level `+`.
1123+ predicates
1124+ . iter ( )
1125+ . filter ( |pred| {
1126+ matches ! (
1127+ pred. skip_binder( ) ,
1128+ ty:: ExistentialPredicate :: Trait ( _)
1129+ | ty:: ExistentialPredicate :: AutoTrait ( _)
1130+ )
1131+ } )
1132+ . count ( )
1133+ > 1
1134+ }
1135+ }
1136+ _ => false ,
1137+ }
1138+ }
1139+
1140+ /// Whether `Alias(Opaque)` would print with more than one top-level
1141+ /// `+`-joined component. Must stay in sync with
1142+ /// `pretty_print_opaque_impl_type`'s sized-bound handling. `?Sized` and
1143+ /// the synthetic `Sized` / `?Sized` / `MetaSized` / `PointeeSized` suffix
1144+ /// each contribute one top-level joinable component. Regressions land in
1145+ /// `tests/ui/impl-trait/in-trait/refine-rustfix-parens.rs`.
1146+ fn opaque_has_multiple_bounds ( & self , def_id : DefId , args : ty:: GenericArgsRef < ' tcx > ) -> bool {
1147+ let tcx = self . tcx ( ) ;
1148+ let bounds = tcx. explicit_item_bounds ( def_id) ;
1149+
1150+ // Mirror `pretty_print_opaque_impl_type`'s sized-bound handling:
1151+ // positive `Sized` and `MetaSized` are absorbed into the synthetic
1152+ // suffix below; negative `Sized` (`?Sized`) falls through and is
1153+ // printed inline.
1154+ let mut trait_emits = 0usize ;
1155+ let mut lifetimes_count = 0usize ;
1156+ let mut has_sized_bound = false ;
1157+ let mut has_negative_sized_bound = false ;
1158+ let mut has_meta_sized_bound = false ;
1159+
1160+ for ( predicate, _) in
1161+ bounds. iter_instantiated_copied ( tcx, args) . map ( Unnormalized :: skip_norm_wip)
1162+ {
1163+ match predicate. kind ( ) . skip_binder ( ) {
1164+ ty:: ClauseKind :: Trait ( pred) => match tcx. as_lang_item ( pred. def_id ( ) ) {
1165+ Some ( LangItem :: Sized ) => match pred. polarity {
1166+ ty:: PredicatePolarity :: Positive => {
1167+ has_sized_bound = true ;
1168+ }
1169+ ty:: PredicatePolarity :: Negative => {
1170+ has_negative_sized_bound = true ;
1171+ trait_emits += 1 ;
1172+ }
1173+ } ,
1174+ Some ( LangItem :: MetaSized ) => {
1175+ has_meta_sized_bound = true ;
1176+ }
1177+ Some ( LangItem :: PointeeSized ) => { }
1178+ _ => trait_emits += 1 ,
1179+ } ,
1180+ ty:: ClauseKind :: TypeOutlives ( _) => lifetimes_count += 1 ,
1181+ _ => { }
1182+ }
1183+ }
1184+
1185+ // The synthetic suffix in `pretty_print_opaque_impl_type` emits at most
1186+ // one extra bound (`Sized` / `?Sized` / `MetaSized` / `PointeeSized`).
1187+ let using_sized_hierarchy = tcx. features ( ) . sized_hierarchy ( ) ;
1188+ let add_sized = has_sized_bound && ( trait_emits == 0 || has_negative_sized_bound) ;
1189+ let add_maybe_sized =
1190+ has_meta_sized_bound && !has_negative_sized_bound && !using_sized_hierarchy;
1191+ let has_pointee_sized =
1192+ !has_sized_bound && !has_meta_sized_bound && !has_negative_sized_bound;
1193+ let synthetic = add_sized
1194+ || add_maybe_sized
1195+ || ( using_sized_hierarchy && ( has_meta_sized_bound || has_pointee_sized) ) ;
1196+
1197+ trait_emits + lifetimes_count + usize:: from ( synthetic) > 1
1198+ }
1199+
10741200 fn pretty_print_opaque_impl_type (
10751201 & mut self ,
10761202 def_id : DefId ,
0 commit comments