@@ -12,7 +12,6 @@ use either::Either;
1212use hir_def:: {
1313 FindPathConfig , GenericDefId , GenericParamId , HasModule , LocalFieldId , Lookup , ModuleDefId ,
1414 ModuleId , TraitId ,
15- db:: DefDatabase ,
1615 expr_store:: { ExpressionStore , path:: Path } ,
1716 find_path:: { self , PrefixKind } ,
1817 hir:: generics:: { TypeOrConstParamData , TypeParamProvenance , WherePredicate } ,
@@ -100,6 +99,9 @@ pub struct HirFormatter<'a, 'db> {
10099 display_kind : DisplayKind ,
101100 display_target : DisplayTarget ,
102101 bounds_formatting_ctx : BoundsFormattingCtx < ' db > ,
102+ /// Whether formatting `impl Trait1 + Trait2` or `dyn Trait1 + Trait2` needs parentheses around it,
103+ /// for example when formatting `&(impl Trait1 + Trait2)`.
104+ trait_bounds_need_parens : bool ,
103105}
104106
105107// FIXME: To consider, ref and dyn trait lifetimes can be omitted if they are `'_`, path args should
@@ -331,6 +333,7 @@ pub trait HirDisplay<'db> {
331333 show_container_bounds : false ,
332334 display_lifetimes : DisplayLifetime :: OnlyNamedOrStatic ,
333335 bounds_formatting_ctx : Default :: default ( ) ,
336+ trait_bounds_need_parens : false ,
334337 } ) {
335338 Ok ( ( ) ) => { }
336339 Err ( HirDisplayError :: FmtError ) => panic ! ( "Writing to String can't fail!" ) ,
@@ -566,6 +569,7 @@ impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> {
566569 show_container_bounds : self . show_container_bounds ,
567570 display_lifetimes : self . display_lifetimes ,
568571 bounds_formatting_ctx : Default :: default ( ) ,
572+ trait_bounds_need_parens : false ,
569573 } )
570574 }
571575
@@ -612,7 +616,11 @@ impl<'db, T: HirDisplay<'db> + Internable> HirDisplay<'db> for Interned<T> {
612616 }
613617}
614618
615- fn write_projection < ' db > ( f : & mut HirFormatter < ' _ , ' db > , alias : & AliasTy < ' db > ) -> Result {
619+ fn write_projection < ' db > (
620+ f : & mut HirFormatter < ' _ , ' db > ,
621+ alias : & AliasTy < ' db > ,
622+ needs_parens_if_multi : bool ,
623+ ) -> Result {
616624 if f. should_truncate ( ) {
617625 return write ! ( f, "{TYPE_HINT_TRUNCATION}" ) ;
618626 }
@@ -650,6 +658,7 @@ fn write_projection<'db>(f: &mut HirFormatter<'_, 'db>, alias: &AliasTy<'db>) ->
650658 Either :: Left ( Ty :: new_alias ( f. interner , AliasTyKind :: Projection , * alias) ) ,
651659 & bounds,
652660 SizedByDefault :: NotSized ,
661+ needs_parens_if_multi,
653662 )
654663 } ) ;
655664 }
@@ -1056,7 +1065,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
10561065 return write ! ( f, "{TYPE_HINT_TRUNCATION}" ) ;
10571066 }
10581067
1059- use TyKind ;
1068+ let trait_bounds_need_parens = mem :: replace ( & mut f . trait_bounds_need_parens , false ) ;
10601069 match self . kind ( ) {
10611070 TyKind :: Never => write ! ( f, "!" ) ?,
10621071 TyKind :: Str => write ! ( f, "str" ) ?,
@@ -1077,103 +1086,34 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
10771086 c. hir_fmt ( f) ?;
10781087 write ! ( f, "]" ) ?;
10791088 }
1080- kind @ ( TyKind :: RawPtr ( t, m) | TyKind :: Ref ( _, t, m) ) => {
1081- if let TyKind :: Ref ( l, _, _) = kind {
1082- f. write_char ( '&' ) ?;
1083- if f. render_region ( l) {
1084- l. hir_fmt ( f) ?;
1085- f. write_char ( ' ' ) ?;
1086- }
1087- match m {
1088- rustc_ast_ir:: Mutability :: Not => ( ) ,
1089- rustc_ast_ir:: Mutability :: Mut => f. write_str ( "mut " ) ?,
1090- }
1091- } else {
1092- write ! (
1093- f,
1094- "*{}" ,
1095- match m {
1096- rustc_ast_ir:: Mutability :: Not => "const " ,
1097- rustc_ast_ir:: Mutability :: Mut => "mut " ,
1098- }
1099- ) ?;
1089+ TyKind :: Ref ( l, t, m) => {
1090+ f. write_char ( '&' ) ?;
1091+ if f. render_region ( l) {
1092+ l. hir_fmt ( f) ?;
1093+ f. write_char ( ' ' ) ?;
1094+ }
1095+ match m {
1096+ rustc_ast_ir:: Mutability :: Not => ( ) ,
1097+ rustc_ast_ir:: Mutability :: Mut => f. write_str ( "mut " ) ?,
11001098 }
11011099
1102- // FIXME: all this just to decide whether to use parentheses...
1103- let ( preds_to_print, has_impl_fn_pred) = match t. kind ( ) {
1104- TyKind :: Dynamic ( bounds, region) => {
1105- let contains_impl_fn =
1106- bounds. iter ( ) . any ( |bound| match bound. skip_binder ( ) {
1107- ExistentialPredicate :: Trait ( trait_ref) => {
1108- let trait_ = trait_ref. def_id . 0 ;
1109- fn_traits ( f. lang_items ( ) ) . any ( |it| it == trait_)
1110- }
1111- _ => false ,
1112- } ) ;
1113- let render_lifetime = f. render_region ( region) ;
1114- ( bounds. len ( ) + render_lifetime as usize , contains_impl_fn)
1115- }
1116- TyKind :: Alias ( AliasTyKind :: Opaque , ty) => {
1117- let opaque_ty_id = match ty. def_id {
1118- SolverDefId :: InternedOpaqueTyId ( id) => id,
1119- _ => unreachable ! ( ) ,
1120- } ;
1121- let impl_trait_id = db. lookup_intern_impl_trait_id ( opaque_ty_id) ;
1122- if let ImplTraitId :: ReturnTypeImplTrait ( func, _) = impl_trait_id {
1123- let data = impl_trait_id. predicates ( db) ;
1124- let bounds =
1125- || data. iter_instantiated_copied ( f. interner , ty. args . as_slice ( ) ) ;
1126- let mut len = bounds ( ) . count ( ) ;
1127-
1128- // Don't count Sized but count when it absent
1129- // (i.e. when explicit ?Sized bound is set).
1130- let default_sized = SizedByDefault :: Sized { anchor : func. krate ( db) } ;
1131- let sized_bounds = bounds ( )
1132- . filter ( |b| {
1133- matches ! (
1134- b. kind( ) . skip_binder( ) ,
1135- ClauseKind :: Trait ( trait_ref)
1136- if default_sized. is_sized_trait(
1137- trait_ref. def_id( ) . 0 ,
1138- db,
1139- ) ,
1140- )
1141- } )
1142- . count ( ) ;
1143- match sized_bounds {
1144- 0 => len += 1 ,
1145- _ => {
1146- len = len. saturating_sub ( sized_bounds) ;
1147- }
1148- }
1149-
1150- let contains_impl_fn = bounds ( ) . any ( |bound| {
1151- if let ClauseKind :: Trait ( trait_ref) = bound. kind ( ) . skip_binder ( ) {
1152- let trait_ = trait_ref. def_id ( ) . 0 ;
1153- fn_traits ( f. lang_items ( ) ) . any ( |it| it == trait_)
1154- } else {
1155- false
1156- }
1157- } ) ;
1158- ( len, contains_impl_fn)
1159- } else {
1160- ( 0 , false )
1161- }
1100+ f. trait_bounds_need_parens = true ;
1101+ t. hir_fmt ( f) ?;
1102+ f. trait_bounds_need_parens = false ;
1103+ }
1104+ TyKind :: RawPtr ( t, m) => {
1105+ write ! (
1106+ f,
1107+ "*{}" ,
1108+ match m {
1109+ rustc_ast_ir:: Mutability :: Not => "const " ,
1110+ rustc_ast_ir:: Mutability :: Mut => "mut " ,
11621111 }
1163- _ => ( 0 , false ) ,
1164- } ;
1165-
1166- if has_impl_fn_pred && preds_to_print <= 2 {
1167- return t. hir_fmt ( f) ;
1168- }
1112+ ) ?;
11691113
1170- if preds_to_print > 1 {
1171- write ! ( f, "(" ) ?;
1172- t. hir_fmt ( f) ?;
1173- write ! ( f, ")" ) ?;
1174- } else {
1175- t. hir_fmt ( f) ?;
1176- }
1114+ f. trait_bounds_need_parens = true ;
1115+ t. hir_fmt ( f) ?;
1116+ f. trait_bounds_need_parens = false ;
11771117 }
11781118 TyKind :: Tuple ( tys) => {
11791119 if tys. len ( ) == 1 {
@@ -1328,7 +1268,9 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
13281268
13291269 hir_fmt_generics ( f, parameters. as_slice ( ) , Some ( def. def_id ( ) . 0 . into ( ) ) , None ) ?;
13301270 }
1331- TyKind :: Alias ( AliasTyKind :: Projection , alias_ty) => write_projection ( f, & alias_ty) ?,
1271+ TyKind :: Alias ( AliasTyKind :: Projection , alias_ty) => {
1272+ write_projection ( f, & alias_ty, trait_bounds_need_parens) ?
1273+ }
13321274 TyKind :: Foreign ( alias) => {
13331275 let type_alias = db. type_alias_signature ( alias. 0 ) ;
13341276 f. start_location_link ( alias. 0 . into ( ) ) ;
@@ -1363,6 +1305,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
13631305 Either :: Left ( * self ) ,
13641306 & bounds,
13651307 SizedByDefault :: Sized { anchor : krate } ,
1308+ trait_bounds_need_parens,
13661309 ) ?;
13671310 }
13681311 TyKind :: Closure ( id, substs) => {
@@ -1525,6 +1468,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
15251468 Either :: Left ( * self ) ,
15261469 & bounds,
15271470 SizedByDefault :: Sized { anchor : krate } ,
1471+ trait_bounds_need_parens,
15281472 ) ?;
15291473 }
15301474 } ,
@@ -1567,6 +1511,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
15671511 Either :: Left ( * self ) ,
15681512 & bounds_to_display,
15691513 SizedByDefault :: NotSized ,
1514+ trait_bounds_need_parens,
15701515 ) ?;
15711516 }
15721517 TyKind :: Error ( _) => {
@@ -1806,11 +1751,11 @@ pub enum SizedByDefault {
18061751}
18071752
18081753impl SizedByDefault {
1809- fn is_sized_trait ( self , trait_ : TraitId , db : & dyn DefDatabase ) -> bool {
1754+ fn is_sized_trait ( self , trait_ : TraitId , interner : DbInterner < ' _ > ) -> bool {
18101755 match self {
18111756 Self :: NotSized => false ,
1812- Self :: Sized { anchor } => {
1813- let sized_trait = hir_def :: lang_item :: lang_items ( db , anchor ) . Sized ;
1757+ Self :: Sized { .. } => {
1758+ let sized_trait = interner . lang_items ( ) . Sized ;
18141759 Some ( trait_) == sized_trait
18151760 }
18161761 }
@@ -1823,16 +1768,62 @@ pub fn write_bounds_like_dyn_trait_with_prefix<'db>(
18231768 this : Either < Ty < ' db > , Region < ' db > > ,
18241769 predicates : & [ Clause < ' db > ] ,
18251770 default_sized : SizedByDefault ,
1771+ needs_parens_if_multi : bool ,
18261772) -> Result {
1773+ let needs_parens =
1774+ needs_parens_if_multi && trait_bounds_need_parens ( f, this, predicates, default_sized) ;
1775+ if needs_parens {
1776+ write ! ( f, "(" ) ?;
1777+ }
18271778 write ! ( f, "{prefix}" ) ?;
18281779 if !predicates. is_empty ( )
18291780 || predicates. is_empty ( ) && matches ! ( default_sized, SizedByDefault :: Sized { .. } )
18301781 {
18311782 write ! ( f, " " ) ?;
1832- write_bounds_like_dyn_trait ( f, this, predicates, default_sized)
1833- } else {
1834- Ok ( ( ) )
1783+ write_bounds_like_dyn_trait ( f, this, predicates, default_sized) ?;
1784+ }
1785+ if needs_parens {
1786+ write ! ( f, ")" ) ?;
1787+ }
1788+ Ok ( ( ) )
1789+ }
1790+
1791+ fn trait_bounds_need_parens < ' db > (
1792+ f : & mut HirFormatter < ' _ , ' db > ,
1793+ this : Either < Ty < ' db > , Region < ' db > > ,
1794+ predicates : & [ Clause < ' db > ] ,
1795+ default_sized : SizedByDefault ,
1796+ ) -> bool {
1797+ // This needs to be kept in sync with `write_bounds_like_dyn_trait()`.
1798+ let mut distinct_bounds = 0usize ;
1799+ let mut is_sized = false ;
1800+ for p in predicates {
1801+ match p. kind ( ) . skip_binder ( ) {
1802+ ClauseKind :: Trait ( trait_ref) => {
1803+ let trait_ = trait_ref. def_id ( ) . 0 ;
1804+ if default_sized. is_sized_trait ( trait_, f. interner ) {
1805+ is_sized = true ;
1806+ if matches ! ( default_sized, SizedByDefault :: Sized { .. } ) {
1807+ // Don't print +Sized, but rather +?Sized if absent.
1808+ continue ;
1809+ }
1810+ }
1811+
1812+ distinct_bounds += 1 ;
1813+ }
1814+ ClauseKind :: TypeOutlives ( to) if Either :: Left ( to. 0 ) == this => distinct_bounds += 1 ,
1815+ ClauseKind :: RegionOutlives ( lo) if Either :: Right ( lo. 0 ) == this => distinct_bounds += 1 ,
1816+ _ => { }
1817+ }
18351818 }
1819+
1820+ if let SizedByDefault :: Sized { .. } = default_sized
1821+ && !is_sized
1822+ {
1823+ distinct_bounds += 1 ;
1824+ }
1825+
1826+ distinct_bounds > 1
18361827}
18371828
18381829fn write_bounds_like_dyn_trait < ' db > (
@@ -1855,7 +1846,7 @@ fn write_bounds_like_dyn_trait<'db>(
18551846 match p. kind ( ) . skip_binder ( ) {
18561847 ClauseKind :: Trait ( trait_ref) => {
18571848 let trait_ = trait_ref. def_id ( ) . 0 ;
1858- if default_sized. is_sized_trait ( trait_, f. db ) {
1849+ if default_sized. is_sized_trait ( trait_, f. interner ) {
18591850 is_sized = true ;
18601851 if matches ! ( default_sized, SizedByDefault :: Sized { .. } ) {
18611852 // Don't print +Sized, but rather +?Sized if absent.
0 commit comments