@@ -51,6 +51,7 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
51
51
52
52
use crate :: infer;
53
53
use crate :: infer:: error_reporting:: nice_region_error:: find_anon_type:: find_anon_type;
54
+ use crate :: infer:: ExpectedFound ;
54
55
use crate :: traits:: error_reporting:: report_object_safety_error;
55
56
use crate :: traits:: {
56
57
IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
@@ -1653,8 +1654,114 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1653
1654
) ,
1654
1655
Mismatch :: Fixed ( s) => ( s. into ( ) , s. into ( ) , None ) ,
1655
1656
} ;
1656
- match ( & terr, expected == found) {
1657
- ( TypeError :: Sorts ( values) , extra) => {
1657
+
1658
+ enum Similar < ' tcx > {
1659
+ Adts { expected : ty:: AdtDef < ' tcx > , found : ty:: AdtDef < ' tcx > } ,
1660
+ PrimitiveFound { expected : ty:: AdtDef < ' tcx > , found : Ty < ' tcx > } ,
1661
+ PrimitiveExpected { expected : Ty < ' tcx > , found : ty:: AdtDef < ' tcx > } ,
1662
+ }
1663
+
1664
+ let similarity = |ExpectedFound { expected, found } : ExpectedFound < Ty < ' tcx > > | {
1665
+ if let ty:: Adt ( expected, _) = expected. kind ( ) && let Some ( primitive) = found. primitive_symbol ( ) {
1666
+ let path = self . tcx . def_path ( expected. did ( ) ) . data ;
1667
+ let name = path. last ( ) . unwrap ( ) . data . get_opt_name ( ) ;
1668
+ if name == Some ( primitive) {
1669
+ return Some ( Similar :: PrimitiveFound { expected : * expected, found } ) ;
1670
+ }
1671
+ } else if let Some ( primitive) = expected. primitive_symbol ( ) && let ty:: Adt ( found, _) = found. kind ( ) {
1672
+ let path = self . tcx . def_path ( found. did ( ) ) . data ;
1673
+ let name = path. last ( ) . unwrap ( ) . data . get_opt_name ( ) ;
1674
+ if name == Some ( primitive) {
1675
+ return Some ( Similar :: PrimitiveExpected { expected, found : * found } ) ;
1676
+ }
1677
+ } else if let ty:: Adt ( expected, _) = expected. kind ( ) && let ty:: Adt ( found, _) = found. kind ( ) {
1678
+ if !expected. did ( ) . is_local ( ) && expected. did ( ) . krate == found. did ( ) . krate {
1679
+ // Most likely types from different versions of the same crate
1680
+ // are in play, in which case this message isn't so helpful.
1681
+ // A "perhaps two different versions..." error is already emitted for that.
1682
+ return None ;
1683
+ }
1684
+ let f_path = self . tcx . def_path ( found. did ( ) ) . data ;
1685
+ let e_path = self . tcx . def_path ( expected. did ( ) ) . data ;
1686
+
1687
+ if let ( Some ( e_last) , Some ( f_last) ) = ( e_path. last ( ) , f_path. last ( ) ) && e_last == f_last {
1688
+ return Some ( Similar :: Adts { expected : * expected, found : * found} ) ;
1689
+ }
1690
+ }
1691
+ None
1692
+ } ;
1693
+
1694
+ match terr {
1695
+ // If two types mismatch but have similar names, mention that specifically.
1696
+ TypeError :: Sorts ( values) if let Some ( s) = similarity ( values) => {
1697
+ let diagnose_primitive =
1698
+ |prim : Ty < ' tcx > ,
1699
+ shadow : Ty < ' tcx > ,
1700
+ defid : DefId ,
1701
+ diagnostic : & mut Diagnostic | {
1702
+ let name = shadow. sort_string ( self . tcx ) ;
1703
+ diagnostic. note ( format ! (
1704
+ "{prim} and {name} have similar names, but are actually distinct types"
1705
+ ) ) ;
1706
+ diagnostic
1707
+ . note ( format ! ( "{prim} is a primitive defined by the language" ) ) ;
1708
+ let def_span = self . tcx . def_span ( defid) ;
1709
+ let msg = if defid. is_local ( ) {
1710
+ format ! ( "{name} is defined in the current crate" )
1711
+ } else {
1712
+ let crate_name = self . tcx . crate_name ( defid. krate ) ;
1713
+ format ! ( "{name} is defined in crate `{crate_name}" )
1714
+ } ;
1715
+ diagnostic. span_note ( def_span, msg) ;
1716
+ } ;
1717
+
1718
+ let diagnose_adts =
1719
+ |expected_adt : ty:: AdtDef < ' tcx > ,
1720
+ found_adt : ty:: AdtDef < ' tcx > ,
1721
+ diagnostic : & mut Diagnostic | {
1722
+ let found_name = values. found . sort_string ( self . tcx ) ;
1723
+ let expected_name = values. expected . sort_string ( self . tcx ) ;
1724
+
1725
+ let found_defid = found_adt. did ( ) ;
1726
+ let expected_defid = expected_adt. did ( ) ;
1727
+
1728
+ diagnostic. note ( format ! ( "{found_name} and {expected_name} have similar names, but are actually distinct types" ) ) ;
1729
+ for ( defid, name) in
1730
+ [ ( found_defid, found_name) , ( expected_defid, expected_name) ]
1731
+ {
1732
+ let def_span = self . tcx . def_span ( defid) ;
1733
+
1734
+ let msg = if found_defid. is_local ( ) && expected_defid. is_local ( ) {
1735
+ let module = self
1736
+ . tcx
1737
+ . parent_module_from_def_id ( defid. expect_local ( ) )
1738
+ . to_def_id ( ) ;
1739
+ let module_name = self . tcx . def_path ( module) . to_string_no_crate_verbose ( ) ;
1740
+ format ! ( "{name} is defined in module `crate{module_name}` of the current crate" )
1741
+ } else if defid. is_local ( ) {
1742
+ format ! ( "{name} is defined in the current crate" )
1743
+ } else {
1744
+ let crate_name = self . tcx . crate_name ( defid. krate ) ;
1745
+ format ! ( "{name} is defined in crate `{crate_name}`" )
1746
+ } ;
1747
+ diagnostic. span_note ( def_span, msg) ;
1748
+ }
1749
+ } ;
1750
+
1751
+ match s {
1752
+ Similar :: Adts { expected, found} => {
1753
+ diagnose_adts ( expected, found, diag)
1754
+ }
1755
+ Similar :: PrimitiveFound { expected, found : prim} => {
1756
+ diagnose_primitive ( prim, values. expected , expected. did ( ) , diag)
1757
+ }
1758
+ Similar :: PrimitiveExpected { expected : prim, found} => {
1759
+ diagnose_primitive ( prim, values. found , found. did ( ) , diag)
1760
+ }
1761
+ }
1762
+ }
1763
+ TypeError :: Sorts ( values) => {
1764
+ let extra = expected == found;
1658
1765
let sort_string = |ty : Ty < ' tcx > | match ( extra, ty. kind ( ) ) {
1659
1766
( true , ty:: Opaque ( def_id, _) ) => {
1660
1767
let sm = self . tcx . sess . source_map ( ) ;
@@ -1707,10 +1814,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1707
1814
) ;
1708
1815
}
1709
1816
}
1710
- ( TypeError :: ObjectUnsafeCoercion ( _ ) , _) => {
1817
+ TypeError :: ObjectUnsafeCoercion ( _) => {
1711
1818
diag. note_unsuccessful_coercion ( found, expected) ;
1712
1819
}
1713
- ( _ , _ ) => {
1820
+ _ => {
1714
1821
debug ! (
1715
1822
"note_type_err: exp_found={:?}, expected={:?} found={:?}" ,
1716
1823
exp_found, expected, found
0 commit comments