@@ -18,10 +18,12 @@ use core::ops::ControlFlow;
18
18
use rustc_data_structures:: fx:: FxHashMap ;
19
19
use rustc_data_structures:: unord:: UnordSet ;
20
20
use rustc_errors:: codes:: * ;
21
- use rustc_errors:: { pluralize, struct_span_code_err, Applicability , StringPart } ;
22
- use rustc_errors:: { Diag , ErrorGuaranteed , StashKey } ;
21
+ use rustc_errors:: {
22
+ pluralize, struct_span_code_err, Applicability , Diag , ErrorGuaranteed , MultiSpan , StashKey ,
23
+ StringPart ,
24
+ } ;
23
25
use rustc_hir:: def:: Namespace ;
24
- use rustc_hir:: def_id:: { DefId , LocalDefId } ;
26
+ use rustc_hir:: def_id:: { DefId , LocalDefId , LOCAL_CRATE } ;
25
27
use rustc_hir:: intravisit:: Visitor ;
26
28
use rustc_hir:: Node ;
27
29
use rustc_hir:: { self as hir, LangItem } ;
@@ -1624,9 +1626,131 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1624
1626
other : bool ,
1625
1627
param_env : ty:: ParamEnv < ' tcx > ,
1626
1628
) -> bool {
1627
- // If we have a single implementation, try to unify it with the trait ref
1628
- // that failed. This should uncover a better hint for what *is* implemented.
1629
+ let alternative_candidates = |def_id : DefId | {
1630
+ let mut impl_candidates: Vec < _ > = self
1631
+ . tcx
1632
+ . all_impls ( def_id)
1633
+ // ignore `do_not_recommend` items
1634
+ . filter ( |def_id| {
1635
+ !self
1636
+ . tcx
1637
+ . has_attrs_with_path ( * def_id, & [ sym:: diagnostic, sym:: do_not_recommend] )
1638
+ } )
1639
+ // Ignore automatically derived impls and `!Trait` impls.
1640
+ . filter_map ( |def_id| self . tcx . impl_trait_header ( def_id) )
1641
+ . filter_map ( |header| {
1642
+ ( header. polarity != ty:: ImplPolarity :: Negative
1643
+ || self . tcx . is_automatically_derived ( def_id) )
1644
+ . then ( || header. trait_ref . instantiate_identity ( ) )
1645
+ } )
1646
+ . filter ( |trait_ref| {
1647
+ let self_ty = trait_ref. self_ty ( ) ;
1648
+ // Avoid mentioning type parameters.
1649
+ if let ty:: Param ( _) = self_ty. kind ( ) {
1650
+ false
1651
+ }
1652
+ // Avoid mentioning types that are private to another crate
1653
+ else if let ty:: Adt ( def, _) = self_ty. peel_refs ( ) . kind ( ) {
1654
+ // FIXME(compiler-errors): This could be generalized, both to
1655
+ // be more granular, and probably look past other `#[fundamental]`
1656
+ // types, too.
1657
+ self . tcx . visibility ( def. did ( ) ) . is_accessible_from ( body_def_id, self . tcx )
1658
+ } else {
1659
+ true
1660
+ }
1661
+ } )
1662
+ . collect ( ) ;
1663
+
1664
+ impl_candidates. sort_by_key ( |tr| tr. to_string ( ) ) ;
1665
+ impl_candidates. dedup ( ) ;
1666
+ impl_candidates
1667
+ } ;
1668
+
1669
+ // We'll check for the case where the reason for the mismatch is that the trait comes from
1670
+ // one crate version and the type comes from another crate version, even though they both
1671
+ // are from the same crate.
1672
+ let trait_def_id = trait_ref. def_id ( ) ;
1673
+ if let ty:: Adt ( def, _) = trait_ref. self_ty ( ) . skip_binder ( ) . peel_refs ( ) . kind ( )
1674
+ && let found_type = def. did ( )
1675
+ && trait_def_id. krate != found_type. krate
1676
+ && self . tcx . crate_name ( trait_def_id. krate ) == self . tcx . crate_name ( found_type. krate )
1677
+ {
1678
+ let name = self . tcx . crate_name ( trait_def_id. krate ) ;
1679
+ let spans: Vec < _ > = [ trait_def_id, found_type]
1680
+ . into_iter ( )
1681
+ . filter_map ( |def_id| self . tcx . extern_crate ( def_id) )
1682
+ . map ( |data| {
1683
+ let dependency = if data. dependency_of == LOCAL_CRATE {
1684
+ "direct dependency of the current crate" . to_string ( )
1685
+ } else {
1686
+ let dep = self . tcx . crate_name ( data. dependency_of ) ;
1687
+ format ! ( "dependency of crate `{dep}`" )
1688
+ } ;
1689
+ (
1690
+ data. span ,
1691
+ format ! ( "one version of crate `{name}` is used here, as a {dependency}" ) ,
1692
+ )
1693
+ } )
1694
+ . collect ( ) ;
1695
+ let mut span: MultiSpan = spans. iter ( ) . map ( |( sp, _) | * sp) . collect :: < Vec < Span > > ( ) . into ( ) ;
1696
+ for ( sp, label) in spans. into_iter ( ) {
1697
+ span. push_span_label ( sp, label) ;
1698
+ }
1699
+ err. highlighted_span_help (
1700
+ span,
1701
+ vec ! [
1702
+ StringPart :: normal( "you have " . to_string( ) ) ,
1703
+ StringPart :: highlighted( "multiple different versions" . to_string( ) ) ,
1704
+ StringPart :: normal( " of crate `" . to_string( ) ) ,
1705
+ StringPart :: highlighted( format!( "{name}" ) ) ,
1706
+ StringPart :: normal( "` in your dependency graph" . to_string( ) ) ,
1707
+ ] ,
1708
+ ) ;
1709
+ let candidates = if impl_candidates. is_empty ( ) {
1710
+ alternative_candidates ( trait_def_id)
1711
+ } else {
1712
+ impl_candidates. into_iter ( ) . map ( |cand| cand. trait_ref ) . collect ( )
1713
+ } ;
1714
+ if let Some ( ( sp_candidate, sp_found) ) = candidates. iter ( ) . find_map ( |trait_ref| {
1715
+ if let ty:: Adt ( def, _) = trait_ref. self_ty ( ) . peel_refs ( ) . kind ( )
1716
+ && let candidate_def_id = def. did ( )
1717
+ && let Some ( name) = self . tcx . opt_item_name ( candidate_def_id)
1718
+ && let Some ( found) = self . tcx . opt_item_name ( found_type)
1719
+ && name == found
1720
+ && candidate_def_id. krate != found_type. krate
1721
+ && self . tcx . crate_name ( candidate_def_id. krate )
1722
+ == self . tcx . crate_name ( found_type. krate )
1723
+ {
1724
+ // A candidate was found of an item with the same name, from two separate
1725
+ // versions of the same crate, let's clarify.
1726
+ Some ( ( self . tcx . def_span ( candidate_def_id) , self . tcx . def_span ( found_type) ) )
1727
+ } else {
1728
+ None
1729
+ }
1730
+ } ) {
1731
+ let mut span: MultiSpan = vec ! [ sp_candidate, sp_found] . into ( ) ;
1732
+ span. push_span_label ( self . tcx . def_span ( trait_def_id) , "this is the required trait" ) ;
1733
+ span. push_span_label ( sp_candidate, "this type implements the required trait" ) ;
1734
+ span. push_span_label ( sp_found, "this type doesn't implement the required trait" ) ;
1735
+ err. highlighted_span_note (
1736
+ span,
1737
+ vec ! [
1738
+ StringPart :: normal(
1739
+ "two types coming from two different versions of the same crate are \
1740
+ different types "
1741
+ . to_string( ) ,
1742
+ ) ,
1743
+ StringPart :: highlighted( "even if they look the same" . to_string( ) ) ,
1744
+ ] ,
1745
+ ) ;
1746
+ }
1747
+ err. help ( "you can use `cargo tree` to explore your dependency tree" ) ;
1748
+ return true ;
1749
+ }
1750
+
1629
1751
if let [ single] = & impl_candidates {
1752
+ // If we have a single implementation, try to unify it with the trait ref
1753
+ // that failed. This should uncover a better hint for what *is* implemented.
1630
1754
if self . probe ( |_| {
1631
1755
let ocx = ObligationCtxt :: new ( self ) ;
1632
1756
@@ -1798,43 +1922,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
1798
1922
// Mentioning implementers of `Copy`, `Debug` and friends is not useful.
1799
1923
return false ;
1800
1924
}
1801
- let mut impl_candidates: Vec < _ > = self
1802
- . tcx
1803
- . all_impls ( def_id)
1804
- // ignore `do_not_recommend` items
1805
- . filter ( |def_id| {
1806
- !self
1807
- . tcx
1808
- . has_attrs_with_path ( * def_id, & [ sym:: diagnostic, sym:: do_not_recommend] )
1809
- } )
1810
- // Ignore automatically derived impls and `!Trait` impls.
1811
- . filter_map ( |def_id| self . tcx . impl_trait_header ( def_id) )
1812
- . filter_map ( |header| {
1813
- ( header. polarity != ty:: ImplPolarity :: Negative
1814
- || self . tcx . is_automatically_derived ( def_id) )
1815
- . then ( || header. trait_ref . instantiate_identity ( ) )
1816
- } )
1817
- . filter ( |trait_ref| {
1818
- let self_ty = trait_ref. self_ty ( ) ;
1819
- // Avoid mentioning type parameters.
1820
- if let ty:: Param ( _) = self_ty. kind ( ) {
1821
- false
1822
- }
1823
- // Avoid mentioning types that are private to another crate
1824
- else if let ty:: Adt ( def, _) = self_ty. peel_refs ( ) . kind ( ) {
1825
- // FIXME(compiler-errors): This could be generalized, both to
1826
- // be more granular, and probably look past other `#[fundamental]`
1827
- // types, too.
1828
- self . tcx . visibility ( def. did ( ) ) . is_accessible_from ( body_def_id, self . tcx )
1829
- } else {
1830
- true
1831
- }
1832
- } )
1833
- . collect ( ) ;
1834
-
1835
- impl_candidates. sort_by_key ( |tr| tr. to_string ( ) ) ;
1836
- impl_candidates. dedup ( ) ;
1837
- return report ( impl_candidates, err) ;
1925
+ return report ( alternative_candidates ( def_id) , err) ;
1838
1926
}
1839
1927
1840
1928
// Sort impl candidates so that ordering is consistent for UI tests.
0 commit comments