@@ -7,7 +7,7 @@ pub mod suggestions;
77use std:: { fmt, iter} ;
88
99use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
10- use rustc_errors:: { Applicability , Diag , E0038 , E0276 , MultiSpan , struct_span_code_err} ;
10+ use rustc_errors:: { Applicability , Diag , E0038 , E0276 , E0802 , MultiSpan , struct_span_code_err} ;
1111use rustc_hir:: def_id:: { DefId , LocalDefId } ;
1212use rustc_hir:: intravisit:: Visitor ;
1313use rustc_hir:: { self as hir, LangItem } ;
@@ -428,10 +428,46 @@ pub fn report_dyn_incompatibility<'tcx>(
428428 violations : & [ DynCompatibilityViolation ] ,
429429) -> Diag < ' tcx > {
430430 let trait_str = tcx. def_path_str ( trait_def_id) ;
431+
432+ // Avoid errors diving into the details of the `AsyncFn` traits if this is
433+ // a straightforward "`AsyncFn` is not yet dyn-compatible" error.
434+ if let Some ( async_fn_trait_kind) = tcx. async_fn_trait_kind_from_def_id ( trait_def_id) {
435+ let async_fn_trait_name = match async_fn_trait_kind {
436+ ty:: ClosureKind :: Fn => "AsyncFn" ,
437+ ty:: ClosureKind :: FnMut => "AsyncFnMut" ,
438+ ty:: ClosureKind :: FnOnce => "AsyncFnOnce" ,
439+ } ;
440+
441+ let mut err = struct_span_code_err ! (
442+ tcx. dcx( ) ,
443+ span,
444+ E0802 ,
445+ "the trait `{}` is not yet dyn-compatible" ,
446+ async_fn_trait_name
447+ ) ;
448+ // Note: this check is quite imprecise.
449+ // Comparing the DefIds or similar would be better, but we can't store
450+ // DefIds in `DynCompatibilityViolation`.
451+ if async_fn_trait_name == trait_str {
452+ err. span_label ( span, format ! ( "`{async_fn_trait_name}` is not yet dyn compatible" ) ) ;
453+ } else {
454+ let trait_str = tcx. def_path_str ( trait_def_id) ;
455+ err. span_label (
456+ span,
457+ format ! (
458+ "`{trait_str}` inherits from `{async_fn_trait_name}` which is not yet dyn-compatible'"
459+ ) ,
460+ ) ;
461+ }
462+ attempt_dyn_to_impl_suggestion ( tcx, hir_id, & mut err) ;
463+ return err;
464+ }
465+
431466 let trait_span = tcx. hir ( ) . get_if_local ( trait_def_id) . and_then ( |node| match node {
432467 hir:: Node :: Item ( item) => Some ( item. ident . span ) ,
433468 _ => None ,
434469 } ) ;
470+
435471 let mut err = struct_span_code_err ! (
436472 tcx. dcx( ) ,
437473 span,
@@ -441,24 +477,8 @@ pub fn report_dyn_incompatibility<'tcx>(
441477 ) ;
442478 err. span_label ( span, format ! ( "`{trait_str}` cannot be made into an object" ) ) ;
443479
444- if let Some ( hir_id) = hir_id
445- && let hir:: Node :: Ty ( ty) = tcx. hir_node ( hir_id)
446- && let hir:: TyKind :: TraitObject ( [ trait_ref, ..] , ..) = ty. kind
447- {
448- let mut hir_id = hir_id;
449- while let hir:: Node :: Ty ( ty) = tcx. parent_hir_node ( hir_id) {
450- hir_id = ty. hir_id ;
451- }
452- if tcx. parent_hir_node ( hir_id) . fn_sig ( ) . is_some ( ) {
453- // Do not suggest `impl Trait` when dealing with things like super-traits.
454- err. span_suggestion_verbose (
455- ty. span . until ( trait_ref. span ) ,
456- "consider using an opaque type instead" ,
457- "impl " ,
458- Applicability :: MaybeIncorrect ,
459- ) ;
460- }
461- }
480+ attempt_dyn_to_impl_suggestion ( tcx, hir_id, & mut err) ;
481+
462482 let mut reported_violations = FxIndexSet :: default ( ) ;
463483 let mut multi_span = vec ! [ ] ;
464484 let mut messages = vec ! [ ] ;
@@ -583,3 +603,27 @@ pub fn report_dyn_incompatibility<'tcx>(
583603
584604 err
585605}
606+
607+ fn attempt_dyn_to_impl_suggestion ( tcx : TyCtxt < ' _ > , hir_id : Option < hir:: HirId > , err : & mut Diag < ' _ > ) {
608+ let Some ( hir_id) = hir_id else { return } ;
609+ let hir:: Node :: Ty ( ty) = tcx. hir_node ( hir_id) else { return } ;
610+ let hir:: TyKind :: TraitObject ( [ trait_ref, ..] , ..) = ty. kind else { return } ;
611+ // Get the top-most parent element which is a type.
612+ let parent_ty_hir_id = tcx
613+ . hir ( )
614+ . parent_iter ( hir_id)
615+ . take_while ( |( _id, node) | matches ! ( node, hir:: Node :: Ty ( _) ) )
616+ . last ( )
617+ . map ( |( id, _node) | id)
618+ . unwrap_or ( hir_id) ;
619+ if tcx. parent_hir_node ( parent_ty_hir_id) . fn_sig ( ) . is_none ( ) {
620+ // Do not suggest `impl Trait` when dealing with things like super-traits.
621+ return ;
622+ }
623+ err. span_suggestion_verbose (
624+ ty. span . until ( trait_ref. span ) ,
625+ "consider using an opaque type instead" ,
626+ "impl " ,
627+ Applicability :: MaybeIncorrect ,
628+ ) ;
629+ }
0 commit comments