@@ -5,6 +5,7 @@ use rustc_ast::TraitObjectSyntax;
5
5
use rustc_data_structures:: fx:: FxIndexSet ;
6
6
use rustc_errors:: { codes:: * , struct_span_code_err, Applicability , Diag , MultiSpan } ;
7
7
use rustc_hir as hir;
8
+ use rustc_hir:: def:: { DefKind , Res } ;
8
9
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
9
10
use rustc_hir:: intravisit:: Visitor ;
10
11
use rustc_middle:: ty:: print:: with_no_trimmed_paths;
@@ -228,100 +229,10 @@ pub fn report_object_safety_error<'tcx>(
228
229
let mut has_suggested = false ;
229
230
if let Some ( hir_id) = hir_id {
230
231
let node = tcx. hir_node ( hir_id) ;
231
- if let hir:: Node :: Ty ( ty) = node
232
- && let hir:: TyKind :: TraitObject ( [ trait_ref, ..] , ..) = ty. kind
233
- {
234
- let mut hir_id = hir_id;
235
- while let hir:: Node :: Ty ( ty) = tcx. parent_hir_node ( hir_id) {
236
- hir_id = ty. hir_id ;
237
- }
238
- if tcx. parent_hir_node ( hir_id) . fn_sig ( ) . is_some ( ) {
239
- // Do not suggest `impl Trait` when dealing with things like super-traits.
240
- err. span_suggestion_verbose (
241
- ty. span . until ( trait_ref. span ) ,
242
- "consider using an opaque type instead" ,
243
- "impl " ,
244
- Applicability :: MaybeIncorrect ,
245
- ) ;
246
- has_suggested = true ;
247
- }
248
- }
249
- if let hir:: Node :: Expr ( expr) = node
250
- && let hir:: ExprKind :: Path ( hir:: QPath :: TypeRelative ( ty, path_segment) ) = expr. kind
251
- && let hir:: TyKind :: TraitObject ( [ trait_ref, ..] , _, trait_object_syntax) = ty. kind
252
- {
253
- if let TraitObjectSyntax :: None = trait_object_syntax
254
- && !expr. span . edition ( ) . at_least_rust_2021 ( )
255
- {
256
- err. span_note (
257
- trait_ref. trait_ref . path . span ,
258
- format ! (
259
- "`{trait_str}` is the type for the trait in editions 2015 and 2018 and is \
260
- equivalent to writing `dyn {trait_str}`",
261
- ) ,
262
- ) ;
263
- }
264
- let segment = path_segment. ident ;
265
- err. help ( format ! (
266
- "when writing `<dyn {trait_str}>::{segment}` you are requiring `{trait_str}` be \
267
- \" object safe\" , which it isn't",
268
- ) ) ;
269
- let ( only, msg, sugg, appl) = if let [ only] = & impls[ ..] {
270
- // We know there's a single implementation for this trait, so we can be explicit on
271
- // the type they should have used.
272
- let ty = tcx. type_of ( * only) . instantiate_identity ( ) ;
273
- (
274
- true ,
275
- format ! (
276
- "specify the specific `impl` for type `{ty}` to avoid requiring \" object \
277
- safety\" from `{trait_str}`",
278
- ) ,
279
- with_no_trimmed_paths ! ( format!( "{ty} as " ) ) ,
280
- Applicability :: MachineApplicable ,
281
- )
282
- } else {
283
- (
284
- false ,
285
- format ! (
286
- "you might have meant to access the associated function of a specific \
287
- `impl` to avoid requiring \" object safety\" from `{trait_str}`, either \
288
- with some explicit type...",
289
- ) ,
290
- "/* Type */ as " . to_string ( ) ,
291
- Applicability :: HasPlaceholders ,
292
- )
293
- } ;
294
- // `<dyn Trait>::segment()` or `<Trait>::segment()` to `<Type as Trait>::segment()`
295
- let sp = ty. span . until ( trait_ref. trait_ref . path . span ) ;
296
- err. span_suggestion_verbose ( sp, msg, sugg, appl) ;
297
- if !only {
298
- // `<dyn Trait>::segment()` or `<Trait>::segment()` to `Trait::segment()`
299
- err. multipart_suggestion_verbose (
300
- "...or rely on inference if the compiler has enough context to identify the \
301
- desired type on its own...",
302
- vec ! [
303
- ( expr. span. until( trait_ref. trait_ref. path. span) , String :: new( ) ) ,
304
- (
305
- path_segment
306
- . ident
307
- . span
308
- . shrink_to_lo( )
309
- . with_lo( trait_ref. trait_ref. path. span. hi( ) ) ,
310
- "::" . to_string( ) ,
311
- ) ,
312
- ] ,
313
- Applicability :: MaybeIncorrect ,
314
- ) ;
315
- // `<dyn Trait>::segment()` or `<Trait>::segment()` to `<_ as Trait>::segment()`
316
- err. span_suggestion_verbose (
317
- ty. span . until ( trait_ref. trait_ref . path . span ) ,
318
- "...which is equivalent to" ,
319
- format ! ( "_ as " ) ,
320
- Applicability :: MaybeIncorrect ,
321
- ) ;
322
- }
323
- has_suggested = true ;
232
+ if let hir:: Node :: Ty ( ty) = node {
233
+ has_suggested |= suggest_impl_trait_on_bare_trait ( tcx, & mut err, ty) ;
324
234
}
235
+ has_suggested |= suggest_path_on_bare_trait ( tcx, & mut err, node) ;
325
236
}
326
237
match & impls[ ..] {
327
238
_ if has_suggested => { }
@@ -366,3 +277,130 @@ pub fn report_object_safety_error<'tcx>(
366
277
367
278
err
368
279
}
280
+
281
+ pub fn suggest_impl_trait_on_bare_trait (
282
+ tcx : TyCtxt < ' _ > ,
283
+ err : & mut Diag < ' _ > ,
284
+ ty : & hir:: Ty < ' _ > ,
285
+ ) -> bool {
286
+ let hir:: TyKind :: TraitObject ( [ trait_ref, ..] , ..) = ty. kind else { return false } ;
287
+ let mut hir_id = ty. hir_id ;
288
+ while let hir:: Node :: Ty ( ty) = tcx. parent_hir_node ( hir_id) {
289
+ hir_id = ty. hir_id ;
290
+ }
291
+ if tcx. parent_hir_node ( hir_id) . fn_sig ( ) . is_none ( ) {
292
+ return false ;
293
+ }
294
+ // Do not suggest `impl Trait` when dealing with things like super-traits.
295
+ err. span_suggestion_verbose (
296
+ ty. span . until ( trait_ref. span ) ,
297
+ "consider using an opaque type instead" ,
298
+ "impl " ,
299
+ Applicability :: MaybeIncorrect ,
300
+ ) ;
301
+ true
302
+ }
303
+
304
+ pub fn suggest_path_on_bare_trait (
305
+ tcx : TyCtxt < ' _ > ,
306
+ err : & mut Diag < ' _ > ,
307
+ node : hir:: Node < ' _ > ,
308
+ ) -> bool {
309
+ let hir:: Node :: Expr ( expr) = node else { return false } ;
310
+ let hir:: ExprKind :: Path ( hir:: QPath :: TypeRelative ( ty, path_segment) ) = expr. kind else {
311
+ return false ;
312
+ } ;
313
+ let hir:: TyKind :: TraitObject ( [ trait_ref, ..] , _, trait_object_syntax) = ty. kind else {
314
+ return false ;
315
+ } ;
316
+ let trait_def_id = match trait_ref. trait_ref . path . res {
317
+ Res :: Def ( DefKind :: Trait , def_id) => def_id,
318
+ _ => return false ,
319
+ } ;
320
+ let trait_str = tcx. def_path_str ( trait_def_id) ;
321
+ if let TraitObjectSyntax :: None = trait_object_syntax
322
+ && !expr. span . edition ( ) . at_least_rust_2021 ( )
323
+ {
324
+ err. span_note (
325
+ trait_ref. trait_ref . path . span ,
326
+ format ! (
327
+ "`{trait_str}` is the type for the trait in editions 2015 and 2018 and is \
328
+ equivalent to writing `dyn {trait_str}`",
329
+ ) ,
330
+ ) ;
331
+ }
332
+ let segment = path_segment. ident ;
333
+ err. help ( format ! (
334
+ "when writing `<{}{trait_str}>::{segment}` you are requiring `{trait_str}` be \" object \
335
+ safe\" , which it isn't",
336
+ if let TraitObjectSyntax :: None = trait_object_syntax { "" } else { "dyn " } ,
337
+ ) ) ;
338
+ let impls_of = tcx. trait_impls_of ( trait_def_id) ;
339
+ let impls = if impls_of. blanket_impls ( ) . is_empty ( ) {
340
+ impls_of
341
+ . non_blanket_impls ( )
342
+ . values ( )
343
+ . flatten ( )
344
+ . filter ( |def_id| {
345
+ !matches ! ( tcx. type_of( * def_id) . instantiate_identity( ) . kind( ) , ty:: Dynamic ( ..) )
346
+ } )
347
+ . collect :: < Vec < _ > > ( )
348
+ } else {
349
+ vec ! [ ]
350
+ } ;
351
+ let ( only, msg, sugg, appl) = if let [ only] = & impls[ ..] {
352
+ // We know there's a single implementation for this trait, so we can be explicit on
353
+ // the type they should have used.
354
+ let ty = tcx. type_of ( * only) . instantiate_identity ( ) ;
355
+ (
356
+ true ,
357
+ format ! (
358
+ "specify the specific `impl` for type `{ty}` to avoid requiring \" object safety\" \
359
+ from `{trait_str}`",
360
+ ) ,
361
+ with_no_trimmed_paths ! ( format!( "{ty} as " ) ) ,
362
+ Applicability :: MachineApplicable ,
363
+ )
364
+ } else {
365
+ (
366
+ false ,
367
+ format ! (
368
+ "you might have meant to access the associated function of a specific `impl` to \
369
+ avoid requiring \" object safety\" from `{trait_str}`, either with some explicit \
370
+ type...",
371
+ ) ,
372
+ "/* Type */ as " . to_string ( ) ,
373
+ Applicability :: HasPlaceholders ,
374
+ )
375
+ } ;
376
+ // `<dyn Trait>::segment()` or `<Trait>::segment()` to `<Type as Trait>::segment()`
377
+ let sp = ty. span . until ( trait_ref. trait_ref . path . span ) ;
378
+ err. span_suggestion_verbose ( sp, msg, sugg, appl) ;
379
+ if !only {
380
+ // `<dyn Trait>::segment()` or `<Trait>::segment()` to `Trait::segment()`
381
+ err. multipart_suggestion_verbose (
382
+ "...or rely on inference if the compiler has enough context to identify the desired \
383
+ type on its own...",
384
+ vec ! [
385
+ ( expr. span. until( trait_ref. trait_ref. path. span) , String :: new( ) ) ,
386
+ (
387
+ path_segment
388
+ . ident
389
+ . span
390
+ . shrink_to_lo( )
391
+ . with_lo( trait_ref. trait_ref. path. span. hi( ) ) ,
392
+ "::" . to_string( ) ,
393
+ ) ,
394
+ ] ,
395
+ Applicability :: MaybeIncorrect ,
396
+ ) ;
397
+ // `<dyn Trait>::segment()` or `<Trait>::segment()` to `<_ as Trait>::segment()`
398
+ err. span_suggestion_verbose (
399
+ ty. span . until ( trait_ref. trait_ref . path . span ) ,
400
+ "...which is equivalent to" ,
401
+ format ! ( "_ as " ) ,
402
+ Applicability :: MaybeIncorrect ,
403
+ ) ;
404
+ }
405
+ true
406
+ }
0 commit comments