2
2
3
3
use crate :: ty:: TyKind :: * ;
4
4
use crate :: ty:: { InferTy , TyCtxt , TyS } ;
5
+ use rustc_data_structures:: fx:: FxHashSet ;
5
6
use rustc_errors:: { Applicability , DiagnosticBuilder } ;
6
7
use rustc_hir as hir;
7
8
use rustc_hir:: def_id:: DefId ;
@@ -105,6 +106,116 @@ pub fn suggest_arbitrary_trait_bound(
105
106
true
106
107
}
107
108
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
+
108
219
/// Suggest restricting a type param with a new bound.
109
220
pub fn suggest_constraining_type_param (
110
221
tcx : TyCtxt < ' _ > ,
@@ -130,6 +241,7 @@ pub fn suggest_constraining_type_param(
130
241
if def_id == tcx. lang_items ( ) . sized_trait ( ) {
131
242
// Type parameters are already `Sized` by default.
132
243
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) ;
133
245
return true ;
134
246
}
135
247
let mut suggest_restrict = |span| {
0 commit comments