@@ -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
@@ -2406,7 +2407,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
24062407 /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
24072408 /// with the same path as `trait_ref`, a help message about
24082409 /// a probable version mismatch is added to `err`
2409- fn note_version_mismatch (
2410+ fn note_trait_version_mismatch (
24102411 & self ,
24112412 err : & mut Diag < ' _ > ,
24122413 trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
@@ -2446,15 +2447,87 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
24462447 impl_spans,
24472448 format ! ( "trait impl{} with same name found" , pluralize!( trait_impls. len( ) ) ) ,
24482449 ) ;
2449- let trait_crate = self . tcx . crate_name ( trait_with_same_path. krate ) ;
2450- let crate_msg =
2451- format ! ( "perhaps two different versions of crate `{trait_crate}` are being used?" ) ;
2452- err. note ( crate_msg) ;
2450+ self . note_two_crate_versions ( trait_with_same_path, err) ;
24532451 suggested = true ;
24542452 }
24552453 suggested
24562454 }
24572455
2456+ fn note_two_crate_versions ( & self , did : DefId , err : & mut Diag < ' _ > ) {
2457+ let crate_name = self . tcx . crate_name ( did. krate ) ;
2458+ let crate_msg =
2459+ format ! ( "perhaps two different versions of crate `{crate_name}` are being used?" ) ;
2460+ err. note ( crate_msg) ;
2461+ }
2462+
2463+ fn note_adt_version_mismatch (
2464+ & self ,
2465+ err : & mut Diag < ' _ > ,
2466+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
2467+ ) {
2468+ let ty:: Adt ( impl_self_def, _) = trait_pred. self_ty ( ) . skip_binder ( ) . peel_refs ( ) . kind ( )
2469+ else {
2470+ return ;
2471+ } ;
2472+
2473+ let impl_self_did = impl_self_def. did ( ) ;
2474+
2475+ // We only want to warn about different versions of a dependency.
2476+ // If no dependency is involved, bail.
2477+ if impl_self_did. krate == LOCAL_CRATE {
2478+ return ;
2479+ }
2480+
2481+ let impl_self_path = self . comparable_path ( impl_self_did) ;
2482+ let impl_self_crate_name = self . tcx . crate_name ( impl_self_did. krate ) ;
2483+ let similar_items: UnordSet < _ > = self
2484+ . tcx
2485+ . visible_parent_map ( ( ) )
2486+ . items ( )
2487+ . filter_map ( |( & item, _) | {
2488+ // If we found ourselves, ignore.
2489+ if impl_self_did == item {
2490+ return None ;
2491+ }
2492+ // We only want to warn about different versions of a dependency.
2493+ // Ignore items from our own crate.
2494+ if item. krate == LOCAL_CRATE {
2495+ return None ;
2496+ }
2497+ // We want to warn about different versions of a dependency.
2498+ // So make sure the crate names are the same.
2499+ if impl_self_crate_name != self . tcx . crate_name ( item. krate ) {
2500+ return None ;
2501+ }
2502+ // Filter out e.g. constructors that often have the same path
2503+ // str as the relevant ADT.
2504+ if !self . tcx . def_kind ( item) . is_adt ( ) {
2505+ return None ;
2506+ }
2507+ let path = self . comparable_path ( item) ;
2508+ // We don't know if our item or the one we found is the re-exported one.
2509+ // Check both cases.
2510+ let is_similar = path. ends_with ( & impl_self_path) || impl_self_path. ends_with ( & path) ;
2511+ is_similar. then_some ( ( item, path) )
2512+ } )
2513+ . collect ( ) ;
2514+
2515+ let mut similar_items =
2516+ similar_items. into_items ( ) . into_sorted_stable_ord_by_key ( |( _, path) | path) ;
2517+ similar_items. dedup ( ) ;
2518+
2519+ for ( similar_item, _) in similar_items {
2520+ err. span_help ( self . tcx . def_span ( similar_item) , "item with same name found" ) ;
2521+ self . note_two_crate_versions ( similar_item, err) ;
2522+ }
2523+ }
2524+
2525+ /// Add a `::` prefix when comparing paths so that paths with just one item
2526+ /// like "Foo" does not equal the end of "OtherFoo".
2527+ fn comparable_path ( & self , did : DefId ) -> String {
2528+ format ! ( "::{}" , self . tcx. def_path_str( did) )
2529+ }
2530+
24582531 /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
24592532 /// `trait_ref`.
24602533 ///
0 commit comments