@@ -467,7 +467,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
467
467
span,
468
468
leaf_trait_predicate,
469
469
) ;
470
- self . note_trait_version_mismatch ( & mut err, leaf_trait_predicate) ;
470
+ self . note_different_trait_with_same_name ( & mut err, & obligation , leaf_trait_predicate) ;
471
471
self . note_adt_version_mismatch ( & mut err, leaf_trait_predicate) ;
472
472
self . suggest_remove_await ( & obligation, & mut err) ;
473
473
self . suggest_derive ( & obligation, & mut err, leaf_trait_predicate) ;
@@ -1949,115 +1949,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1949
1949
impl_candidates
1950
1950
} ;
1951
1951
1952
- // We'll check for the case where the reason for the mismatch is that the trait comes from
1953
- // one crate version and the type comes from another crate version, even though they both
1954
- // are from the same crate.
1955
- let trait_def_id = trait_pred. def_id ( ) ;
1956
- let trait_name = self . tcx . item_name ( trait_def_id) ;
1957
- let crate_name = self . tcx . crate_name ( trait_def_id. krate ) ;
1958
- if let Some ( other_trait_def_id) = self . tcx . all_traits_including_private ( ) . find ( |def_id| {
1959
- trait_name == self . tcx . item_name ( trait_def_id)
1960
- && trait_def_id. krate != def_id. krate
1961
- && crate_name == self . tcx . crate_name ( def_id. krate )
1962
- } ) {
1963
- // We've found two different traits with the same name, same crate name, but
1964
- // different crate `DefId`. We highlight the traits.
1965
-
1966
- let found_type =
1967
- if let ty:: Adt ( def, _) = trait_pred. self_ty ( ) . skip_binder ( ) . peel_refs ( ) . kind ( ) {
1968
- Some ( def. did ( ) )
1969
- } else {
1970
- None
1971
- } ;
1972
- let candidates = if impl_candidates. is_empty ( ) {
1973
- alternative_candidates ( trait_def_id)
1974
- } else {
1975
- impl_candidates. into_iter ( ) . map ( |cand| cand. trait_ref ) . collect ( )
1976
- } ;
1977
- let mut span: MultiSpan = self . tcx . def_span ( trait_def_id) . into ( ) ;
1978
- span. push_span_label ( self . tcx . def_span ( trait_def_id) , "this is the required trait" ) ;
1979
- for ( sp, label) in [ trait_def_id, other_trait_def_id]
1980
- . iter ( )
1981
- // The current crate-version might depend on another version of the same crate
1982
- // (Think "semver-trick"). Do not call `extern_crate` in that case for the local
1983
- // crate as that doesn't make sense and ICEs (#133563).
1984
- . filter ( |def_id| !def_id. is_local ( ) )
1985
- . filter_map ( |def_id| self . tcx . extern_crate ( def_id. krate ) )
1986
- . map ( |data| {
1987
- let dependency = if data. dependency_of == LOCAL_CRATE {
1988
- "direct dependency of the current crate" . to_string ( )
1989
- } else {
1990
- let dep = self . tcx . crate_name ( data. dependency_of ) ;
1991
- format ! ( "dependency of crate `{dep}`" )
1992
- } ;
1993
- (
1994
- data. span ,
1995
- format ! ( "one version of crate `{crate_name}` used here, as a {dependency}" ) ,
1996
- )
1997
- } )
1998
- {
1999
- span. push_span_label ( sp, label) ;
2000
- }
2001
- let mut points_at_type = false ;
2002
- if let Some ( found_type) = found_type {
2003
- span. push_span_label (
2004
- self . tcx . def_span ( found_type) ,
2005
- "this type doesn't implement the required trait" ,
2006
- ) ;
2007
- for trait_ref in candidates {
2008
- if let ty:: Adt ( def, _) = trait_ref. self_ty ( ) . peel_refs ( ) . kind ( )
2009
- && let candidate_def_id = def. did ( )
2010
- && let Some ( name) = self . tcx . opt_item_name ( candidate_def_id)
2011
- && let Some ( found) = self . tcx . opt_item_name ( found_type)
2012
- && name == found
2013
- && candidate_def_id. krate != found_type. krate
2014
- && self . tcx . crate_name ( candidate_def_id. krate )
2015
- == self . tcx . crate_name ( found_type. krate )
2016
- {
2017
- // A candidate was found of an item with the same name, from two separate
2018
- // versions of the same crate, let's clarify.
2019
- let candidate_span = self . tcx . def_span ( candidate_def_id) ;
2020
- span. push_span_label (
2021
- candidate_span,
2022
- "this type implements the required trait" ,
2023
- ) ;
2024
- points_at_type = true ;
2025
- }
2026
- }
2027
- }
2028
- span. push_span_label ( self . tcx . def_span ( other_trait_def_id) , "this is the found trait" ) ;
2029
- err. highlighted_span_note (
2030
- span,
2031
- vec ! [
2032
- StringPart :: normal( "there are " . to_string( ) ) ,
2033
- StringPart :: highlighted( "multiple different versions" . to_string( ) ) ,
2034
- StringPart :: normal( " of crate `" . to_string( ) ) ,
2035
- StringPart :: highlighted( format!( "{crate_name}" ) ) ,
2036
- StringPart :: normal( "` in the dependency graph" . to_string( ) ) ,
2037
- ] ,
2038
- ) ;
2039
- if points_at_type {
2040
- // We only clarify that the same type from different crate versions are not the
2041
- // same when we *find* the same type coming from different crate versions, otherwise
2042
- // it could be that it was a type provided by a different crate than the one that
2043
- // provides the trait, and mentioning this adds verbosity without clarification.
2044
- err. highlighted_note ( vec ! [
2045
- StringPart :: normal(
2046
- "two types coming from two different versions of the same crate are \
2047
- different types "
2048
- . to_string( ) ,
2049
- ) ,
2050
- StringPart :: highlighted( "even if they look the same" . to_string( ) ) ,
2051
- ] ) ;
2052
- }
2053
- err. highlighted_help ( vec ! [
2054
- StringPart :: normal( "you can use `" . to_string( ) ) ,
2055
- StringPart :: highlighted( "cargo tree" . to_string( ) ) ,
2056
- StringPart :: normal( "` to explore your dependency tree" . to_string( ) ) ,
2057
- ] ) ;
2058
- return true ;
2059
- }
2060
-
2061
1952
if let [ single] = & impl_candidates {
2062
1953
// If we have a single implementation, try to unify it with the trait ref
2063
1954
// that failed. This should uncover a better hint for what *is* implemented.
@@ -2422,10 +2313,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
2422
2313
}
2423
2314
}
2424
2315
2425
- /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
2426
- /// with the same path as `trait_ref`, a help message about
2427
- /// a probable version mismatch is added to `err`
2428
- fn note_trait_version_mismatch (
2316
+ fn check_same_trait_different_version (
2429
2317
& self ,
2430
2318
err : & mut Diag < ' _ > ,
2431
2319
trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
@@ -2442,40 +2330,69 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
2442
2330
trait_impls
2443
2331
} ;
2444
2332
2333
+ let krate = self . tcx . crate_name ( trait_pred. def_id ( ) . krate ) ;
2334
+ let name = self . tcx . item_name ( trait_pred. def_id ( ) ) ;
2445
2335
let required_trait_path = self . tcx . def_path_str ( trait_pred. def_id ( ) ) ;
2446
2336
let traits_with_same_path: UnordSet < _ > = self
2447
2337
. tcx
2448
2338
. visible_traits ( )
2449
- . filter ( |trait_def_id| * trait_def_id != trait_pred. def_id ( ) )
2339
+ . filter ( |trait_def_id| {
2340
+ trait_def_id. krate != trait_pred. def_id ( ) . krate
2341
+ && ( self . tcx . def_path_str ( trait_def_id) == required_trait_path
2342
+ || self . tcx . crate_name ( trait_def_id. krate ) == krate
2343
+ && self . tcx . item_name ( trait_def_id) == name)
2344
+ } )
2450
2345
. map ( |trait_def_id| ( self . tcx . def_path_str ( trait_def_id) , trait_def_id) )
2451
- . filter ( |( p, _) | * p == required_trait_path)
2452
2346
. collect ( ) ;
2453
2347
2454
2348
let traits_with_same_path =
2455
2349
traits_with_same_path. into_items ( ) . into_sorted_stable_ord_by_key ( |( p, _) | p) ;
2456
2350
let mut suggested = false ;
2457
- for ( _, trait_with_same_path) in traits_with_same_path {
2458
- let trait_impls = get_trait_impls ( trait_with_same_path) ;
2459
- if trait_impls. is_empty ( ) {
2460
- continue ;
2461
- }
2462
- let impl_spans: Vec < _ > =
2463
- trait_impls. iter ( ) . map ( |impl_def_id| self . tcx . def_span ( * impl_def_id) ) . collect ( ) ;
2464
- err. span_help (
2465
- impl_spans,
2466
- format ! ( "trait impl{} with same name found" , pluralize!( trait_impls. len( ) ) ) ,
2351
+ let mut trait_is_impl = false ;
2352
+
2353
+ if !traits_with_same_path. is_empty ( ) {
2354
+ let mut span: MultiSpan = self . tcx . def_span ( trait_pred. def_id ( ) ) . into ( ) ;
2355
+ span. push_span_label (
2356
+ self . tcx . def_span ( trait_pred. def_id ( ) ) ,
2357
+ "this is the required trait" ,
2467
2358
) ;
2468
- self . note_two_crate_versions ( trait_with_same_path, err) ;
2469
2359
suggested = true ;
2360
+ for ( _, trait_with_same_path) in & traits_with_same_path {
2361
+ let trait_impls = get_trait_impls ( * trait_with_same_path) ;
2362
+ if trait_impls. is_empty ( ) {
2363
+ continue ;
2364
+ }
2365
+
2366
+ for candidate_def_id in trait_impls {
2367
+ let Some ( impl_trait_header) = self . tcx . impl_trait_header ( candidate_def_id)
2368
+ else {
2369
+ continue ;
2370
+ } ;
2371
+ let candidate_span =
2372
+ self . tcx . def_span ( impl_trait_header. trait_ref . skip_binder ( ) . def_id ) ;
2373
+ span. push_span_label ( candidate_span, "this is the implemented trait" ) ;
2374
+ trait_is_impl = true ;
2375
+ }
2376
+ }
2377
+ if !trait_is_impl {
2378
+ for ( _, def_id) in traits_with_same_path {
2379
+ span. push_span_label (
2380
+ self . tcx . def_span ( def_id) ,
2381
+ "this is the trait that was imported" ,
2382
+ ) ;
2383
+ }
2384
+ }
2385
+ self . note_two_crate_versions ( trait_pred. def_id ( ) , span, err) ;
2470
2386
}
2471
2387
suggested
2472
2388
}
2473
2389
2474
- fn note_two_crate_versions ( & self , did : DefId , err : & mut Diag < ' _ > ) {
2390
+ fn note_two_crate_versions ( & self , did : DefId , sp : impl Into < MultiSpan > , err : & mut Diag < ' _ > ) {
2475
2391
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) ;
2392
+ let crate_msg = format ! (
2393
+ "there are multiple different versions of crate `{crate_name}` in the dependency graph"
2394
+ ) ;
2395
+ err. span_note ( sp, crate_msg) ;
2479
2396
}
2480
2397
2481
2398
fn note_adt_version_mismatch (
@@ -2536,8 +2453,76 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
2536
2453
2537
2454
for ( similar_item, _) in similar_items {
2538
2455
err. span_help ( self . tcx . def_span ( similar_item) , "item with same name found" ) ;
2539
- self . note_two_crate_versions ( similar_item, err) ;
2456
+ self . note_two_crate_versions ( similar_item, MultiSpan :: new ( ) , err) ;
2457
+ }
2458
+ }
2459
+
2460
+ fn check_same_name_different_path (
2461
+ & self ,
2462
+ err : & mut Diag < ' _ > ,
2463
+ obligation : & PredicateObligation < ' tcx > ,
2464
+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
2465
+ ) -> bool {
2466
+ let mut suggested = false ;
2467
+ let trait_def_id = trait_pred. def_id ( ) ;
2468
+ let trait_has_same_params = |other_trait_def_id : DefId | -> bool {
2469
+ let trait_generics = self . tcx . generics_of ( trait_def_id) ;
2470
+ let other_trait_generics = self . tcx . generics_of ( other_trait_def_id) ;
2471
+
2472
+ if trait_generics. count ( ) != other_trait_generics. count ( ) {
2473
+ return false ;
2474
+ }
2475
+ trait_generics. own_params . iter ( ) . zip ( other_trait_generics. own_params . iter ( ) ) . all (
2476
+ |( a, b) | {
2477
+ ( matches ! ( a. kind, ty:: GenericParamDefKind :: Type { .. } )
2478
+ && matches ! ( b. kind, ty:: GenericParamDefKind :: Type { .. } ) )
2479
+ || ( matches ! ( a. kind, ty:: GenericParamDefKind :: Lifetime , )
2480
+ && matches ! ( b. kind, ty:: GenericParamDefKind :: Lifetime ) )
2481
+ || ( matches ! ( a. kind, ty:: GenericParamDefKind :: Const { .. } )
2482
+ && matches ! ( b. kind, ty:: GenericParamDefKind :: Const { .. } ) )
2483
+ } ,
2484
+ )
2485
+ } ;
2486
+ let trait_name = self . tcx . item_name ( trait_def_id) ;
2487
+ if let Some ( other_trait_def_id) = self . tcx . all_traits_including_private ( ) . find ( |def_id| {
2488
+ trait_def_id != * def_id
2489
+ && trait_name == self . tcx . item_name ( def_id)
2490
+ && trait_has_same_params ( * def_id)
2491
+ && self . predicate_must_hold_modulo_regions ( & Obligation :: new (
2492
+ self . tcx ,
2493
+ obligation. cause . clone ( ) ,
2494
+ obligation. param_env ,
2495
+ trait_pred. map_bound ( |tr| ty:: TraitPredicate {
2496
+ trait_ref : ty:: TraitRef :: new ( self . tcx , * def_id, tr. trait_ref . args ) ,
2497
+ ..tr
2498
+ } ) ,
2499
+ ) )
2500
+ } ) {
2501
+ err. note ( format ! (
2502
+ "`{}` implements similarly named `{}`, but not `{}`" ,
2503
+ trait_pred. self_ty( ) ,
2504
+ self . tcx. def_path_str( other_trait_def_id) ,
2505
+ trait_pred. print_modifiers_and_trait_path( )
2506
+ ) ) ;
2507
+ suggested = true ;
2508
+ }
2509
+ suggested
2510
+ }
2511
+
2512
+ /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
2513
+ /// with the same path as `trait_ref`, a help message about a multiple different
2514
+ /// versions of the same crate is added to `err`. Otherwise if it implements another
2515
+ /// trait with the same name, a note message about a similarly named trait is added to `err`.
2516
+ pub fn note_different_trait_with_same_name (
2517
+ & self ,
2518
+ err : & mut Diag < ' _ > ,
2519
+ obligation : & PredicateObligation < ' tcx > ,
2520
+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
2521
+ ) -> bool {
2522
+ if self . check_same_trait_different_version ( err, trait_pred) {
2523
+ return true ;
2540
2524
}
2525
+ self . check_same_name_different_path ( err, obligation, trait_pred)
2541
2526
}
2542
2527
2543
2528
/// Add a `::` prefix when comparing paths so that paths with just one item
0 commit comments