@@ -467,7 +467,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
467467 span,
468468 leaf_trait_predicate,
469469 ) ;
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) ;
471472 self . suggest_remove_await ( & obligation, & mut err) ;
472473 self . suggest_derive ( & obligation, & mut err, leaf_trait_predicate) ;
473474
@@ -2424,7 +2425,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
24242425 /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
24252426 /// with the same path as `trait_ref`, a help message about
24262427 /// a probable version mismatch is added to `err`
2427- fn note_version_mismatch (
2428+ fn note_trait_version_mismatch (
24282429 & self ,
24292430 err : & mut Diag < ' _ > ,
24302431 trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
@@ -2464,15 +2465,87 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
24642465 impl_spans,
24652466 format ! ( "trait impl{} with same name found" , pluralize!( trait_impls. len( ) ) ) ,
24662467 ) ;
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) ;
24712469 suggested = true ;
24722470 }
24732471 suggested
24742472 }
24752473
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+
24762549 /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
24772550 /// `trait_ref`.
24782551 ///
0 commit comments