@@ -467,7 +467,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
467
467
span,
468
468
leaf_trait_predicate,
469
469
) ;
470
- self . note_version_mismatch ( & mut err, leaf_trait_predicate) ;
470
+ self . note_trait_version_mismatch ( & mut err, leaf_trait_predicate) ;
471
+ self . note_adt_version_mismatch ( & mut err, leaf_trait_predicate) ;
471
472
self . suggest_remove_await ( & obligation, & mut err) ;
472
473
self . suggest_derive ( & obligation, & mut err, leaf_trait_predicate) ;
473
474
@@ -2424,7 +2425,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
2424
2425
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
2425
2426
/// with the same path as `trait_ref`, a help message about
2426
2427
/// a probable version mismatch is added to `err`
2427
- fn note_version_mismatch (
2428
+ fn note_trait_version_mismatch (
2428
2429
& self ,
2429
2430
err : & mut Diag < ' _ > ,
2430
2431
trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
@@ -2464,15 +2465,87 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
2464
2465
impl_spans,
2465
2466
format ! ( "trait impl{} with same name found" , pluralize!( trait_impls. len( ) ) ) ,
2466
2467
) ;
2467
- let trait_crate = self . tcx . crate_name ( trait_with_same_path. krate ) ;
2468
- let crate_msg =
2469
- format ! ( "perhaps two different versions of crate `{trait_crate}` are being used?" ) ;
2470
- err. note ( crate_msg) ;
2468
+ self . note_two_crate_versions ( trait_with_same_path, err) ;
2471
2469
suggested = true ;
2472
2470
}
2473
2471
suggested
2474
2472
}
2475
2473
2474
+ fn note_two_crate_versions ( & self , did : DefId , err : & mut Diag < ' _ > ) {
2475
+ let crate_name = self . tcx . crate_name ( did. krate ) ;
2476
+ let crate_msg =
2477
+ format ! ( "perhaps two different versions of crate `{crate_name}` are being used?" ) ;
2478
+ err. note ( crate_msg) ;
2479
+ }
2480
+
2481
+ fn note_adt_version_mismatch (
2482
+ & self ,
2483
+ err : & mut Diag < ' _ > ,
2484
+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
2485
+ ) {
2486
+ let ty:: Adt ( impl_self_def, _) = trait_pred. self_ty ( ) . skip_binder ( ) . peel_refs ( ) . kind ( )
2487
+ else {
2488
+ return ;
2489
+ } ;
2490
+
2491
+ let impl_self_did = impl_self_def. did ( ) ;
2492
+
2493
+ // We only want to warn about different versions of a dependency.
2494
+ // If no dependency is involved, bail.
2495
+ if impl_self_did. krate == LOCAL_CRATE {
2496
+ return ;
2497
+ }
2498
+
2499
+ let impl_self_path = self . comparable_path ( impl_self_did) ;
2500
+ let impl_self_crate_name = self . tcx . crate_name ( impl_self_did. krate ) ;
2501
+ let similar_items: UnordSet < _ > = self
2502
+ . tcx
2503
+ . visible_parent_map ( ( ) )
2504
+ . items ( )
2505
+ . filter_map ( |( & item, _) | {
2506
+ // If we found ourselves, ignore.
2507
+ if impl_self_did == item {
2508
+ return None ;
2509
+ }
2510
+ // We only want to warn about different versions of a dependency.
2511
+ // Ignore items from our own crate.
2512
+ if item. krate == LOCAL_CRATE {
2513
+ return None ;
2514
+ }
2515
+ // We want to warn about different versions of a dependency.
2516
+ // So make sure the crate names are the same.
2517
+ if impl_self_crate_name != self . tcx . crate_name ( item. krate ) {
2518
+ return None ;
2519
+ }
2520
+ // Filter out e.g. constructors that often have the same path
2521
+ // str as the relevant ADT.
2522
+ if !self . tcx . def_kind ( item) . is_adt ( ) {
2523
+ return None ;
2524
+ }
2525
+ let path = self . comparable_path ( item) ;
2526
+ // We don't know if our item or the one we found is the re-exported one.
2527
+ // Check both cases.
2528
+ let is_similar = path. ends_with ( & impl_self_path) || impl_self_path. ends_with ( & path) ;
2529
+ is_similar. then_some ( ( item, path) )
2530
+ } )
2531
+ . collect ( ) ;
2532
+
2533
+ let mut similar_items =
2534
+ similar_items. into_items ( ) . into_sorted_stable_ord_by_key ( |( _, path) | path) ;
2535
+ similar_items. dedup ( ) ;
2536
+
2537
+ for ( similar_item, _) in similar_items {
2538
+ err. span_help ( self . tcx . def_span ( similar_item) , "item with same name found" ) ;
2539
+ self . note_two_crate_versions ( similar_item, err) ;
2540
+ }
2541
+ }
2542
+
2543
+ /// Add a `::` prefix when comparing paths so that paths with just one item
2544
+ /// like "Foo" does not equal the end of "OtherFoo".
2545
+ fn comparable_path ( & self , did : DefId ) -> String {
2546
+ format ! ( "::{}" , self . tcx. def_path_str( did) )
2547
+ }
2548
+
2476
2549
/// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
2477
2550
/// `trait_ref`.
2478
2551
///
0 commit comments