1+ // ignore-tidy-filelength
12use core:: ops:: ControlFlow ;
23use std:: borrow:: Cow ;
34use std:: path:: PathBuf ;
@@ -467,7 +468,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
467468 span,
468469 leaf_trait_predicate,
469470 ) ;
470- self . note_trait_version_mismatch ( & mut err, leaf_trait_predicate) ;
471+ self . note_different_trait_with_same_name ( & mut err, & obligation , leaf_trait_predicate) ;
471472 self . note_adt_version_mismatch ( & mut err, leaf_trait_predicate) ;
472473 self . suggest_remove_await ( & obligation, & mut err) ;
473474 self . suggest_derive ( & obligation, & mut err, leaf_trait_predicate) ;
@@ -1949,115 +1950,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19491950 impl_candidates
19501951 } ;
19511952
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-
20611953 if let [ single] = & impl_candidates {
20621954 // If we have a single implementation, try to unify it with the trait ref
20631955 // that failed. This should uncover a better hint for what *is* implemented.
@@ -2422,10 +2314,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
24222314 }
24232315 }
24242316
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 (
2317+ fn get_extern_crate_renamed_symbol ( & self , trait_def_id : DefId ) -> Option < Symbol > {
2318+ if !trait_def_id. is_local ( )
2319+ && let Some ( data) = self . tcx . extern_crate ( trait_def_id. krate )
2320+ && let rustc_session:: cstore:: ExternCrateSource :: Extern ( def_id) = data. src
2321+ {
2322+ self . tcx . opt_item_name ( def_id)
2323+ } else {
2324+ None
2325+ }
2326+ }
2327+
2328+ fn check_same_trait_different_version (
24292329 & self ,
24302330 err : & mut Diag < ' _ > ,
24312331 trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
@@ -2442,40 +2342,72 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
24422342 trait_impls
24432343 } ;
24442344
2445- let required_trait_path = self . tcx . def_path_str ( trait_pred. def_id ( ) ) ;
2345+ let krate = self . tcx . crate_name ( trait_pred. def_id ( ) . krate ) ;
2346+ let name = self . tcx . item_name ( trait_pred. def_id ( ) ) ;
2347+ let locally_renamed_krate = self
2348+ . get_extern_crate_renamed_symbol ( trait_pred. def_id ( ) )
2349+ . map_or ( None , |s| if s != krate { Some ( s) } else { None } ) ;
24462350 let traits_with_same_path: UnordSet < _ > = self
24472351 . tcx
24482352 . visible_traits ( )
2449- . filter ( |trait_def_id| * trait_def_id != trait_pred. def_id ( ) )
2353+ . filter ( |trait_def_id| {
2354+ trait_def_id. krate != trait_pred. def_id ( ) . krate
2355+ && ( locally_renamed_krate
2356+ == self . get_extern_crate_renamed_symbol ( * trait_def_id)
2357+ || self . tcx . crate_name ( trait_def_id. krate ) == krate)
2358+ && self . tcx . item_name ( trait_def_id) == name
2359+ } )
24502360 . map ( |trait_def_id| ( self . tcx . def_path_str ( trait_def_id) , trait_def_id) )
2451- . filter ( |( p, _) | * p == required_trait_path)
24522361 . collect ( ) ;
24532362
24542363 let traits_with_same_path =
24552364 traits_with_same_path. into_items ( ) . into_sorted_stable_ord_by_key ( |( p, _) | p) ;
24562365 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( ) ) ) ,
2366+ let mut trait_is_impl = false ;
2367+
2368+ if !traits_with_same_path. is_empty ( ) {
2369+ let mut span: MultiSpan = self . tcx . def_span ( trait_pred. def_id ( ) ) . into ( ) ;
2370+ span. push_span_label (
2371+ self . tcx . def_span ( trait_pred. def_id ( ) ) ,
2372+ "this is the required trait" ,
24672373 ) ;
2468- self . note_two_crate_versions ( trait_with_same_path, err) ;
24692374 suggested = true ;
2375+ for ( _, trait_with_same_path) in & traits_with_same_path {
2376+ let trait_impls = get_trait_impls ( * trait_with_same_path) ;
2377+ if trait_impls. is_empty ( ) {
2378+ continue ;
2379+ }
2380+
2381+ for candidate_def_id in trait_impls {
2382+ let Some ( impl_trait_header) = self . tcx . impl_trait_header ( candidate_def_id)
2383+ else {
2384+ continue ;
2385+ } ;
2386+ let candidate_span =
2387+ self . tcx . def_span ( impl_trait_header. trait_ref . skip_binder ( ) . def_id ) ;
2388+ span. push_span_label ( candidate_span, "this is the implemented trait" ) ;
2389+ trait_is_impl = true ;
2390+ }
2391+ }
2392+ if !trait_is_impl {
2393+ for ( _, def_id) in traits_with_same_path {
2394+ span. push_span_label (
2395+ self . tcx . def_span ( def_id) ,
2396+ "this is the trait that was imported" ,
2397+ ) ;
2398+ }
2399+ }
2400+ self . note_two_crate_versions ( trait_pred. def_id ( ) , span, err) ;
24702401 }
24712402 suggested
24722403 }
24732404
2474- fn note_two_crate_versions ( & self , did : DefId , err : & mut Diag < ' _ > ) {
2405+ fn note_two_crate_versions ( & self , did : DefId , sp : impl Into < MultiSpan > , err : & mut Diag < ' _ > ) {
24752406 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) ;
2407+ let crate_msg = format ! (
2408+ "there are multiple different versions of crate `{crate_name}` in the dependency graph"
2409+ ) ;
2410+ err. span_note ( sp, crate_msg) ;
24792411 }
24802412
24812413 fn note_adt_version_mismatch (
@@ -2536,8 +2468,76 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
25362468
25372469 for ( similar_item, _) in similar_items {
25382470 err. span_help ( self . tcx . def_span ( similar_item) , "item with same name found" ) ;
2539- self . note_two_crate_versions ( similar_item, err) ;
2471+ self . note_two_crate_versions ( similar_item, MultiSpan :: new ( ) , err) ;
2472+ }
2473+ }
2474+
2475+ fn check_same_name_different_path (
2476+ & self ,
2477+ err : & mut Diag < ' _ > ,
2478+ obligation : & PredicateObligation < ' tcx > ,
2479+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
2480+ ) -> bool {
2481+ let mut suggested = false ;
2482+ let trait_def_id = trait_pred. def_id ( ) ;
2483+ let trait_has_same_params = |other_trait_def_id : DefId | -> bool {
2484+ let trait_generics = self . tcx . generics_of ( trait_def_id) ;
2485+ let other_trait_generics = self . tcx . generics_of ( other_trait_def_id) ;
2486+
2487+ if trait_generics. count ( ) != other_trait_generics. count ( ) {
2488+ return false ;
2489+ }
2490+ trait_generics. own_params . iter ( ) . zip ( other_trait_generics. own_params . iter ( ) ) . all (
2491+ |( a, b) | {
2492+ ( matches ! ( a. kind, ty:: GenericParamDefKind :: Type { .. } )
2493+ && matches ! ( b. kind, ty:: GenericParamDefKind :: Type { .. } ) )
2494+ || ( matches ! ( a. kind, ty:: GenericParamDefKind :: Lifetime , )
2495+ && matches ! ( b. kind, ty:: GenericParamDefKind :: Lifetime ) )
2496+ || ( matches ! ( a. kind, ty:: GenericParamDefKind :: Const { .. } )
2497+ && matches ! ( b. kind, ty:: GenericParamDefKind :: Const { .. } ) )
2498+ } ,
2499+ )
2500+ } ;
2501+ let trait_name = self . tcx . item_name ( trait_def_id) ;
2502+ if let Some ( other_trait_def_id) = self . tcx . all_traits_including_private ( ) . find ( |def_id| {
2503+ trait_def_id != * def_id
2504+ && trait_name == self . tcx . item_name ( def_id)
2505+ && trait_has_same_params ( * def_id)
2506+ && self . predicate_must_hold_modulo_regions ( & Obligation :: new (
2507+ self . tcx ,
2508+ obligation. cause . clone ( ) ,
2509+ obligation. param_env ,
2510+ trait_pred. map_bound ( |tr| ty:: TraitPredicate {
2511+ trait_ref : ty:: TraitRef :: new ( self . tcx , * def_id, tr. trait_ref . args ) ,
2512+ ..tr
2513+ } ) ,
2514+ ) )
2515+ } ) {
2516+ err. note ( format ! (
2517+ "`{}` implements similarly named `{}`, but not `{}`" ,
2518+ trait_pred. self_ty( ) ,
2519+ self . tcx. def_path_str( other_trait_def_id) ,
2520+ trait_pred. print_modifiers_and_trait_path( )
2521+ ) ) ;
2522+ suggested = true ;
2523+ }
2524+ suggested
2525+ }
2526+
2527+ /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
2528+ /// with the same path as `trait_ref`, a help message about a multiple different
2529+ /// versions of the same crate is added to `err`. Otherwise if it implements another
2530+ /// trait with the same name, a note message about a similarly named trait is added to `err`.
2531+ pub fn note_different_trait_with_same_name (
2532+ & self ,
2533+ err : & mut Diag < ' _ > ,
2534+ obligation : & PredicateObligation < ' tcx > ,
2535+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
2536+ ) -> bool {
2537+ if self . check_same_trait_different_version ( err, trait_pred) {
2538+ return true ;
25402539 }
2540+ self . check_same_name_different_path ( err, obligation, trait_pred)
25412541 }
25422542
25432543 /// Add a `::` prefix when comparing paths so that paths with just one item
0 commit comments