@@ -5,6 +5,7 @@ use rustc_ast::TraitObjectSyntax;
55use rustc_data_structures:: fx:: FxIndexSet ;
66use rustc_errors:: { codes:: * , struct_span_code_err, Applicability , Diag , MultiSpan } ;
77use rustc_hir as hir;
8+ use rustc_hir:: def:: { DefKind , Res } ;
89use rustc_hir:: def_id:: { DefId , LocalDefId } ;
910use rustc_hir:: intravisit:: Visitor ;
1011use rustc_middle:: ty:: print:: with_no_trimmed_paths;
@@ -228,100 +229,10 @@ pub fn report_object_safety_error<'tcx>(
228229 let mut has_suggested = false ;
229230 if let Some ( hir_id) = hir_id {
230231 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) ;
324234 }
235+ has_suggested |= suggest_path_on_bare_trait ( tcx, & mut err, node) ;
325236 }
326237 match & impls[ ..] {
327238 _ if has_suggested => { }
@@ -366,3 +277,130 @@ pub fn report_object_safety_error<'tcx>(
366277
367278 err
368279}
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