@@ -12,7 +12,7 @@ use rustc_errors::{
1212 Applicability , Diag , ErrorGuaranteed , Level , MultiSpan , StashKey , StringPart , Suggestions ,
1313 pluralize, struct_span_code_err,
1414} ;
15- use rustc_hir:: def_id:: { DefId , LOCAL_CRATE , LocalDefId } ;
15+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
1616use rustc_hir:: intravisit:: Visitor ;
1717use rustc_hir:: { self as hir, LangItem , Node } ;
1818use rustc_infer:: infer:: { InferOk , TypeTrace } ;
@@ -467,7 +467,7 @@ 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_different_trait_with_same_name ( & mut err, & obligation , leaf_trait_predicate) ;
471471 self . suggest_remove_await ( & obligation, & mut err) ;
472472 self . suggest_derive ( & obligation, & mut err, leaf_trait_predicate) ;
473473
@@ -1948,115 +1948,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19481948 impl_candidates
19491949 } ;
19501950
1951- // We'll check for the case where the reason for the mismatch is that the trait comes from
1952- // one crate version and the type comes from another crate version, even though they both
1953- // are from the same crate.
1954- let trait_def_id = trait_pred. def_id ( ) ;
1955- let trait_name = self . tcx . item_name ( trait_def_id) ;
1956- let crate_name = self . tcx . crate_name ( trait_def_id. krate ) ;
1957- if let Some ( other_trait_def_id) = self . tcx . all_traits_including_private ( ) . find ( |def_id| {
1958- trait_name == self . tcx . item_name ( trait_def_id)
1959- && trait_def_id. krate != def_id. krate
1960- && crate_name == self . tcx . crate_name ( def_id. krate )
1961- } ) {
1962- // We've found two different traits with the same name, same crate name, but
1963- // different crate `DefId`. We highlight the traits.
1964-
1965- let found_type =
1966- if let ty:: Adt ( def, _) = trait_pred. self_ty ( ) . skip_binder ( ) . peel_refs ( ) . kind ( ) {
1967- Some ( def. did ( ) )
1968- } else {
1969- None
1970- } ;
1971- let candidates = if impl_candidates. is_empty ( ) {
1972- alternative_candidates ( trait_def_id)
1973- } else {
1974- impl_candidates. into_iter ( ) . map ( |cand| cand. trait_ref ) . collect ( )
1975- } ;
1976- let mut span: MultiSpan = self . tcx . def_span ( trait_def_id) . into ( ) ;
1977- span. push_span_label ( self . tcx . def_span ( trait_def_id) , "this is the required trait" ) ;
1978- for ( sp, label) in [ trait_def_id, other_trait_def_id]
1979- . iter ( )
1980- // The current crate-version might depend on another version of the same crate
1981- // (Think "semver-trick"). Do not call `extern_crate` in that case for the local
1982- // crate as that doesn't make sense and ICEs (#133563).
1983- . filter ( |def_id| !def_id. is_local ( ) )
1984- . filter_map ( |def_id| self . tcx . extern_crate ( def_id. krate ) )
1985- . map ( |data| {
1986- let dependency = if data. dependency_of == LOCAL_CRATE {
1987- "direct dependency of the current crate" . to_string ( )
1988- } else {
1989- let dep = self . tcx . crate_name ( data. dependency_of ) ;
1990- format ! ( "dependency of crate `{dep}`" )
1991- } ;
1992- (
1993- data. span ,
1994- format ! ( "one version of crate `{crate_name}` used here, as a {dependency}" ) ,
1995- )
1996- } )
1997- {
1998- span. push_span_label ( sp, label) ;
1999- }
2000- let mut points_at_type = false ;
2001- if let Some ( found_type) = found_type {
2002- span. push_span_label (
2003- self . tcx . def_span ( found_type) ,
2004- "this type doesn't implement the required trait" ,
2005- ) ;
2006- for trait_ref in candidates {
2007- if let ty:: Adt ( def, _) = trait_ref. self_ty ( ) . peel_refs ( ) . kind ( )
2008- && let candidate_def_id = def. did ( )
2009- && let Some ( name) = self . tcx . opt_item_name ( candidate_def_id)
2010- && let Some ( found) = self . tcx . opt_item_name ( found_type)
2011- && name == found
2012- && candidate_def_id. krate != found_type. krate
2013- && self . tcx . crate_name ( candidate_def_id. krate )
2014- == self . tcx . crate_name ( found_type. krate )
2015- {
2016- // A candidate was found of an item with the same name, from two separate
2017- // versions of the same crate, let's clarify.
2018- let candidate_span = self . tcx . def_span ( candidate_def_id) ;
2019- span. push_span_label (
2020- candidate_span,
2021- "this type implements the required trait" ,
2022- ) ;
2023- points_at_type = true ;
2024- }
2025- }
2026- }
2027- span. push_span_label ( self . tcx . def_span ( other_trait_def_id) , "this is the found trait" ) ;
2028- err. highlighted_span_note (
2029- span,
2030- vec ! [
2031- StringPart :: normal( "there are " . to_string( ) ) ,
2032- StringPart :: highlighted( "multiple different versions" . to_string( ) ) ,
2033- StringPart :: normal( " of crate `" . to_string( ) ) ,
2034- StringPart :: highlighted( format!( "{crate_name}" ) ) ,
2035- StringPart :: normal( "` in the dependency graph" . to_string( ) ) ,
2036- ] ,
2037- ) ;
2038- if points_at_type {
2039- // We only clarify that the same type from different crate versions are not the
2040- // same when we *find* the same type coming from different crate versions, otherwise
2041- // it could be that it was a type provided by a different crate than the one that
2042- // provides the trait, and mentioning this adds verbosity without clarification.
2043- err. highlighted_note ( vec ! [
2044- StringPart :: normal(
2045- "two types coming from two different versions of the same crate are \
2046- different types "
2047- . to_string( ) ,
2048- ) ,
2049- StringPart :: highlighted( "even if they look the same" . to_string( ) ) ,
2050- ] ) ;
2051- }
2052- err. highlighted_help ( vec ! [
2053- StringPart :: normal( "you can use `" . to_string( ) ) ,
2054- StringPart :: highlighted( "cargo tree" . to_string( ) ) ,
2055- StringPart :: normal( "` to explore your dependency tree" . to_string( ) ) ,
2056- ] ) ;
2057- return true ;
2058- }
2059-
20601951 if let [ single] = & impl_candidates {
20611952 // If we have a single implementation, try to unify it with the trait ref
20621953 // that failed. This should uncover a better hint for what *is* implemented.
@@ -2421,10 +2312,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
24212312 }
24222313 }
24232314
2424- /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
2425- /// with the same path as `trait_ref`, a help message about
2426- /// a probable version mismatch is added to `err`
2427- fn note_version_mismatch (
2315+ fn check_same_trait_different_version (
24282316 & self ,
24292317 err : & mut Diag < ' _ > ,
24302318 trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
@@ -2441,38 +2329,134 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
24412329 trait_impls
24422330 } ;
24432331
2332+ let krate = self . tcx . crate_name ( trait_pred. def_id ( ) . krate ) ;
2333+ let name = self . tcx . item_name ( trait_pred. def_id ( ) ) ;
24442334 let required_trait_path = self . tcx . def_path_str ( trait_pred. def_id ( ) ) ;
24452335 let traits_with_same_path: UnordSet < _ > = self
24462336 . tcx
24472337 . visible_traits ( )
2448- . filter ( |trait_def_id| * trait_def_id != trait_pred. def_id ( ) )
2338+ . filter ( |trait_def_id| {
2339+ trait_def_id. krate != trait_pred. def_id ( ) . krate
2340+ && ( self . tcx . def_path_str ( trait_def_id) == required_trait_path
2341+ || self . tcx . crate_name ( trait_def_id. krate ) == krate
2342+ && self . tcx . item_name ( trait_def_id) == name)
2343+ } )
24492344 . map ( |trait_def_id| ( self . tcx . def_path_str ( trait_def_id) , trait_def_id) )
2450- . filter ( |( p, _) | * p == required_trait_path)
24512345 . collect ( ) ;
24522346
24532347 let traits_with_same_path =
24542348 traits_with_same_path. into_items ( ) . into_sorted_stable_ord_by_key ( |( p, _) | p) ;
24552349 let mut suggested = false ;
2456- for ( _, trait_with_same_path) in traits_with_same_path {
2457- let trait_impls = get_trait_impls ( trait_with_same_path) ;
2458- if trait_impls. is_empty ( ) {
2459- continue ;
2460- }
2461- let impl_spans: Vec < _ > =
2462- trait_impls. iter ( ) . map ( |impl_def_id| self . tcx . def_span ( * impl_def_id) ) . collect ( ) ;
2463- err. span_help (
2464- impl_spans,
2465- format ! ( "trait impl{} with same name found" , pluralize!( trait_impls. len( ) ) ) ,
2350+ let mut trait_is_impl = false ;
2351+
2352+ if !traits_with_same_path. is_empty ( ) {
2353+ let msg = format ! (
2354+ "there are multiple different versions of crate `{krate}` in the dependency graph"
24662355 ) ;
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) ;
2356+ let mut span: MultiSpan = self . tcx . def_span ( trait_pred. def_id ( ) ) . into ( ) ;
2357+ span. push_span_label (
2358+ self . tcx . def_span ( trait_pred. def_id ( ) ) ,
2359+ "this is the required trait" ,
2360+ ) ;
2361+ suggested = true ;
2362+ for ( _, trait_with_same_path) in & traits_with_same_path {
2363+ let trait_impls = get_trait_impls ( * trait_with_same_path) ;
2364+ if trait_impls. is_empty ( ) {
2365+ continue ;
2366+ }
2367+
2368+ for candidate_def_id in trait_impls {
2369+ let Some ( impl_trait_header) = self . tcx . impl_trait_header ( candidate_def_id)
2370+ else {
2371+ continue ;
2372+ } ;
2373+ let candidate_span =
2374+ self . tcx . def_span ( impl_trait_header. trait_ref . skip_binder ( ) . def_id ) ;
2375+ span. push_span_label ( candidate_span, "this is the implemented trait" ) ;
2376+ trait_is_impl = true ;
2377+ }
2378+ }
2379+ if !trait_is_impl {
2380+ for ( _, def_id) in traits_with_same_path {
2381+ span. push_span_label (
2382+ self . tcx . def_span ( def_id) ,
2383+ "this is the trait that was imported" ,
2384+ ) ;
2385+ }
2386+ }
2387+ err. span_note ( span, msg) ;
2388+ }
2389+ suggested
2390+ }
2391+
2392+ fn check_same_name_different_path (
2393+ & self ,
2394+ err : & mut Diag < ' _ > ,
2395+ obligation : & PredicateObligation < ' tcx > ,
2396+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
2397+ ) -> bool {
2398+ let mut suggested = false ;
2399+ let trait_def_id = trait_pred. def_id ( ) ;
2400+ let trait_has_same_params = |other_trait_def_id : DefId | -> bool {
2401+ let trait_generics = self . tcx . generics_of ( trait_def_id) ;
2402+ let other_trait_generics = self . tcx . generics_of ( other_trait_def_id) ;
2403+
2404+ if trait_generics. count ( ) != other_trait_generics. count ( ) {
2405+ return false ;
2406+ }
2407+ trait_generics. own_params . iter ( ) . zip ( other_trait_generics. own_params . iter ( ) ) . all (
2408+ |( a, b) | {
2409+ ( matches ! ( a. kind, ty:: GenericParamDefKind :: Type { .. } )
2410+ && matches ! ( b. kind, ty:: GenericParamDefKind :: Type { .. } ) )
2411+ || ( matches ! ( a. kind, ty:: GenericParamDefKind :: Lifetime , )
2412+ && matches ! ( b. kind, ty:: GenericParamDefKind :: Lifetime ) )
2413+ || ( matches ! ( a. kind, ty:: GenericParamDefKind :: Const { .. } )
2414+ && matches ! ( b. kind, ty:: GenericParamDefKind :: Const { .. } ) )
2415+ } ,
2416+ )
2417+ } ;
2418+ let trait_name = self . tcx . item_name ( trait_def_id) ;
2419+ if let Some ( other_trait_def_id) = self . tcx . all_traits_including_private ( ) . find ( |def_id| {
2420+ trait_def_id != * def_id
2421+ && trait_name == self . tcx . item_name ( def_id)
2422+ && trait_has_same_params ( * def_id)
2423+ && self . predicate_must_hold_modulo_regions ( & Obligation :: new (
2424+ self . tcx ,
2425+ obligation. cause . clone ( ) ,
2426+ obligation. param_env ,
2427+ trait_pred. map_bound ( |tr| ty:: TraitPredicate {
2428+ trait_ref : ty:: TraitRef :: new ( self . tcx , * def_id, tr. trait_ref . args ) ,
2429+ ..tr
2430+ } ) ,
2431+ ) )
2432+ } ) {
2433+ err. note ( format ! (
2434+ "`{}` implements similarly named `{}`, but not `{}`" ,
2435+ trait_pred. self_ty( ) ,
2436+ self . tcx. def_path_str( other_trait_def_id) ,
2437+ trait_pred. print_modifiers_and_trait_path( )
2438+ ) ) ;
24712439 suggested = true ;
24722440 }
24732441 suggested
24742442 }
24752443
2444+ /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
2445+ /// with the same path as `trait_ref`, a help message about a multiple differents
2446+ /// versions of the same crate is added to `err`. Otherwise if it implements another
2447+ /// trait with the same name, a note message about a similarly named trait is added to `err`.
2448+ pub fn note_different_trait_with_same_name (
2449+ & self ,
2450+ err : & mut Diag < ' _ > ,
2451+ obligation : & PredicateObligation < ' tcx > ,
2452+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
2453+ ) -> bool {
2454+ if self . check_same_trait_different_version ( err, trait_pred) {
2455+ return true ;
2456+ }
2457+ self . check_same_name_different_path ( err, obligation, trait_pred)
2458+ }
2459+
24762460 /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
24772461 /// `trait_ref`.
24782462 ///
0 commit comments