22
33use  crate :: ty:: TyKind :: * ; 
44use  crate :: ty:: { InferTy ,  TyCtxt ,  TyS } ; 
5+ use  rustc_data_structures:: fx:: FxHashSet ; 
56use  rustc_errors:: { Applicability ,  DiagnosticBuilder } ; 
67use  rustc_hir as  hir; 
78use  rustc_hir:: def_id:: DefId ; 
@@ -105,6 +106,116 @@ pub fn suggest_arbitrary_trait_bound(
105106    true 
106107} 
107108
109+ fn  suggest_removing_unsized_bound ( 
110+     generics :  & hir:: Generics < ' _ > , 
111+     err :  & mut  DiagnosticBuilder < ' _ > , 
112+     param_name :  & str , 
113+     param :  & hir:: GenericParam < ' _ > , 
114+     def_id :  Option < DefId > , 
115+ )  { 
116+     // See if there's a `?Sized` bound that can be removed to suggest that. 
117+     // First look at the `where` clause because we can have `where T: ?Sized`, but that 
118+     // `?Sized` bound is *also* included in the `GenericParam` as a bound, which breaks 
119+     // the spans. Hence the somewhat involved logic that follows. 
120+     let  mut  where_unsized_bounds = FxHashSet :: default ( ) ; 
121+     for  ( where_pos,  predicate)  in  generics. where_clause . predicates . iter ( ) . enumerate ( )  { 
122+         match  predicate { 
123+             WherePredicate :: BoundPredicate ( WhereBoundPredicate  { 
124+                 bounded_ty : 
125+                     hir:: Ty  { 
126+                         kind : 
127+                             hir:: TyKind :: Path ( hir:: QPath :: Resolved ( 
128+                                 None , 
129+                                 hir:: Path  { 
130+                                     segments :  [ segment] , 
131+                                     res :  hir:: def:: Res :: Def ( hir:: def:: DefKind :: TyParam ,  _) , 
132+                                     ..
133+                                 } , 
134+                             ) ) , 
135+                         ..
136+                     } , 
137+                 bounds, 
138+                 span, 
139+                 ..
140+             } )  if  segment. ident . as_str ( )  == param_name => { 
141+                 for  ( pos,  bound)  in  bounds. iter ( ) . enumerate ( )  { 
142+                     match  bound { 
143+                         hir:: GenericBound :: Unsized ( _)  => { } 
144+                         hir:: GenericBound :: Trait ( poly,  hir:: TraitBoundModifier :: Maybe ) 
145+                             if  poly. trait_ref . trait_def_id ( )  == def_id => { } 
146+                         _ => continue , 
147+                     } 
148+                     let  sp = match  ( 
149+                         bounds. len ( ) , 
150+                         pos, 
151+                         generics. where_clause . predicates . len ( ) , 
152+                         where_pos, 
153+                     )  { 
154+                         // where T: ?Sized 
155+                         // ^^^^^^^^^^^^^^^ 
156+                         ( 1 ,  _,  1 ,  _)  => generics. where_clause . span , 
157+                         // where Foo: Bar, T: ?Sized, 
158+                         //               ^^^^^^^^^^^ 
159+                         ( 1 ,  _,  len,  pos)  if  pos == len - 1  => generics. where_clause . predicates 
160+                             [ pos - 1 ] 
161+                             . span ( ) 
162+                             . shrink_to_hi ( ) 
163+                             . to ( * span) , 
164+                         // where T: ?Sized, Foo: Bar, 
165+                         //       ^^^^^^^^^^^ 
166+                         ( 1 ,  _,  _,  pos)  => { 
167+                             span. until ( generics. where_clause . predicates [ pos + 1 ] . span ( ) ) 
168+                         } 
169+                         // where T: ?Sized + Bar, Foo: Bar, 
170+                         //          ^^^^^^^^^ 
171+                         ( _,  0 ,  _,  _)  => bound. span ( ) . to ( bounds[ 1 ] . span ( ) . shrink_to_lo ( ) ) , 
172+                         // where T: Bar + ?Sized, Foo: Bar, 
173+                         //             ^^^^^^^^^ 
174+                         ( _,  pos,  _,  _)  => bounds[ pos - 1 ] . span ( ) . shrink_to_hi ( ) . to ( bound. span ( ) ) , 
175+                     } ; 
176+                     where_unsized_bounds. insert ( bound. span ( ) ) ; 
177+                     err. span_suggestion_verbose ( 
178+                         sp, 
179+                         "consider removing the `?Sized` bound to make the \  
180+                              type parameter `Sized`", 
181+                         String :: new ( ) , 
182+                         Applicability :: MaybeIncorrect , 
183+                     ) ; 
184+                 } 
185+             } 
186+             _ => { } 
187+         } 
188+     } 
189+     for  ( pos,  bound)  in  param. bounds . iter ( ) . enumerate ( )  { 
190+         match  bound { 
191+             hir:: GenericBound :: Trait ( poly,  hir:: TraitBoundModifier :: Maybe ) 
192+                 if  poly. trait_ref . trait_def_id ( )  == def_id
193+                     && !where_unsized_bounds. contains ( & bound. span ( ) )  =>
194+             { 
195+                 let  sp = match  ( param. bounds . len ( ) ,  pos)  { 
196+                     // T: ?Sized, 
197+                     //  ^^^^^^^^ 
198+                     ( 1 ,  _)  => param. span . shrink_to_hi ( ) . to ( bound. span ( ) ) , 
199+                     // T: ?Sized + Bar, 
200+                     //    ^^^^^^^^^ 
201+                     ( _,  0 )  => bound. span ( ) . to ( param. bounds [ 1 ] . span ( ) . shrink_to_lo ( ) ) , 
202+                     // T: Bar + ?Sized, 
203+                     //       ^^^^^^^^^ 
204+                     ( _,  pos)  => param. bounds [ pos - 1 ] . span ( ) . shrink_to_hi ( ) . to ( bound. span ( ) ) , 
205+                 } ; 
206+                 err. span_suggestion_verbose ( 
207+                     sp, 
208+                     "consider removing the `?Sized` bound to make the type parameter \  
209+                          `Sized`", 
210+                     String :: new ( ) , 
211+                     Applicability :: MaybeIncorrect , 
212+                 ) ; 
213+             } 
214+             _ => { } 
215+         } 
216+     } 
217+ } 
218+ 
108219/// Suggest restricting a type param with a new bound. 
109220pub  fn  suggest_constraining_type_param ( 
110221    tcx :  TyCtxt < ' _ > , 
@@ -130,6 +241,7 @@ pub fn suggest_constraining_type_param(
130241    if  def_id == tcx. lang_items ( ) . sized_trait ( )  { 
131242        // Type parameters are already `Sized` by default. 
132243        err. span_label ( param. span ,  & format ! ( "this type parameter needs to be `{}`" ,  constraint) ) ; 
244+         suggest_removing_unsized_bound ( generics,  err,  param_name,  param,  def_id) ; 
133245        return  true ; 
134246    } 
135247    let  mut  suggest_restrict = |span| { 
0 commit comments