@@ -7,7 +7,7 @@ pub mod suggestions;
7
7
use std:: { fmt, iter} ;
8
8
9
9
use 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} ;
11
11
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
12
12
use rustc_hir:: intravisit:: Visitor ;
13
13
use rustc_hir:: { self as hir, LangItem } ;
@@ -17,7 +17,7 @@ use rustc_infer::traits::{
17
17
} ;
18
18
use rustc_middle:: ty:: print:: { PrintTraitRefExt as _, with_no_trimmed_paths} ;
19
19
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
20
- use rustc_span:: { ErrorGuaranteed , ExpnKind , Span } ;
20
+ use rustc_span:: { ErrorGuaranteed , ExpnKind , Span , Symbol } ;
21
21
use tracing:: { info, instrument} ;
22
22
23
23
pub use self :: overflow:: * ;
@@ -428,10 +428,50 @@ pub fn report_dyn_incompatibility<'tcx>(
428
428
violations : & [ DynCompatibilityViolation ] ,
429
429
) -> Diag < ' tcx > {
430
430
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 tcx. trait_is_async_fn ( trait_def_id) {
435
+ let fn_trait: Symbol = violations
436
+ . iter ( )
437
+ . find_map ( |violation| {
438
+ // Try to find the original trait that caused the violation.
439
+ match * violation {
440
+ DynCompatibilityViolation :: AsyncFnTrait { fn_trait } => Some ( fn_trait) ,
441
+ _ => None ,
442
+ }
443
+ } )
444
+ . expect ( "AsyncFn traits should report a corresponding DynCompatibilityViolation" ) ;
445
+ let mut err = struct_span_code_err ! (
446
+ tcx. dcx( ) ,
447
+ span,
448
+ E0802 ,
449
+ "the trait `{}` is not yet `dyn`-compatible" ,
450
+ fn_trait
451
+ ) ;
452
+ // Note: this check is quite imprecise.
453
+ // Comparing the DefIds or similar would be better, but we can't store
454
+ // DefIds in `DynCompatibilityViolation`.
455
+ if fn_trait. as_str ( ) == trait_str {
456
+ err. span_label ( span, format ! ( "`{fn_trait}` is not yet `dyn`-compatible" ) ) ;
457
+ } else {
458
+ let trait_str = tcx. def_path_str ( trait_def_id) ;
459
+ err. span_label (
460
+ span,
461
+ format ! (
462
+ "`{trait_str}` inherits from `{fn_trait}` which is not yet `dyn`-compatible'"
463
+ ) ,
464
+ ) ;
465
+ }
466
+ attempt_dyn_to_impl_suggestion ( tcx, hir_id, & mut err) ;
467
+ return err;
468
+ }
469
+
431
470
let trait_span = tcx. hir ( ) . get_if_local ( trait_def_id) . and_then ( |node| match node {
432
471
hir:: Node :: Item ( item) => Some ( item. ident . span ) ,
433
472
_ => None ,
434
473
} ) ;
474
+
435
475
let mut err = struct_span_code_err ! (
436
476
tcx. dcx( ) ,
437
477
span,
@@ -441,24 +481,8 @@ pub fn report_dyn_incompatibility<'tcx>(
441
481
) ;
442
482
err. span_label ( span, format ! ( "`{trait_str}` cannot be made into an object" ) ) ;
443
483
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
- }
484
+ attempt_dyn_to_impl_suggestion ( tcx, hir_id, & mut err) ;
485
+
462
486
let mut reported_violations = FxIndexSet :: default ( ) ;
463
487
let mut multi_span = vec ! [ ] ;
464
488
let mut messages = vec ! [ ] ;
@@ -583,3 +607,23 @@ pub fn report_dyn_incompatibility<'tcx>(
583
607
584
608
err
585
609
}
610
+
611
+ fn attempt_dyn_to_impl_suggestion ( tcx : TyCtxt < ' _ > , hir_id : Option < hir:: HirId > , err : & mut Diag < ' _ > ) {
612
+ let Some ( hir_id) = hir_id else { return } ;
613
+ let hir:: Node :: Ty ( ty) = tcx. hir_node ( hir_id) else { return } ;
614
+ let hir:: TyKind :: TraitObject ( [ trait_ref, ..] , ..) = ty. kind else { return } ;
615
+ let mut hir_id = hir_id;
616
+ while let hir:: Node :: Ty ( ty) = tcx. parent_hir_node ( hir_id) {
617
+ hir_id = ty. hir_id ;
618
+ }
619
+ if tcx. parent_hir_node ( 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