@@ -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
@@ -2406,7 +2407,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
2406
2407
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
2407
2408
/// with the same path as `trait_ref`, a help message about
2408
2409
/// a probable version mismatch is added to `err`
2409
- fn note_version_mismatch (
2410
+ fn note_trait_version_mismatch (
2410
2411
& self ,
2411
2412
err : & mut Diag < ' _ > ,
2412
2413
trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
@@ -2446,15 +2447,87 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
2446
2447
impl_spans,
2447
2448
format ! ( "trait impl{} with same name found" , pluralize!( trait_impls. len( ) ) ) ,
2448
2449
) ;
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) ;
2453
2451
suggested = true ;
2454
2452
}
2455
2453
suggested
2456
2454
}
2457
2455
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
+
2458
2531
/// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
2459
2532
/// `trait_ref`.
2460
2533
///
0 commit comments