@@ -1654,47 +1654,156 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1654
1654
) ,
1655
1655
Mismatch :: Fixed ( s) => ( s. into ( ) , s. into ( ) , None ) ,
1656
1656
} ;
1657
- let looks_similar = |e : ExpectedFound < Ty < ' _ > > | {
1658
- // We're only interested in adts
1659
- if let ( Some ( e) , Some ( f) ) = ( e. expected . ty_adt_def ( ) , e. found . ty_adt_def ( ) ) {
1660
- // Only compare the last parts of the path.
1661
- // `whatever::Foo` is pretty similar to `blah::Foo`
1662
- let e_path = self . tcx . def_path ( e. did ( ) ) . data ;
1663
- let f_path = self . tcx . def_path ( f. did ( ) ) . data ;
1664
- if let ( Some ( e) , Some ( f) ) = ( e_path. last ( ) , f_path. last ( ) ) {
1665
- return e. data == f. data ;
1657
+
1658
+ enum Similar < ' tcx > {
1659
+ Adts ( ty:: AdtDef < ' tcx > , ty:: AdtDef < ' tcx > ) ,
1660
+ PrimitiveFound ( Ty < ' tcx > , ty:: AdtDef < ' tcx > ) ,
1661
+ PrimitiveExpected ( ty:: AdtDef < ' tcx > , Ty < ' tcx > ) ,
1662
+ }
1663
+
1664
+ let primitive_sym = |kind : & _ | match kind {
1665
+ ty:: Bool => Some ( sym:: bool) ,
1666
+ ty:: Char => Some ( sym:: char) ,
1667
+ ty:: Float ( f) => match f {
1668
+ ty:: FloatTy :: F32 => Some ( sym:: f32) ,
1669
+ ty:: FloatTy :: F64 => Some ( sym:: f64) ,
1670
+ } ,
1671
+ ty:: Int ( f) => match f {
1672
+ ty:: IntTy :: Isize => Some ( sym:: isize) ,
1673
+ ty:: IntTy :: I8 => Some ( sym:: i8) ,
1674
+ ty:: IntTy :: I16 => Some ( sym:: i16) ,
1675
+ ty:: IntTy :: I32 => Some ( sym:: i32) ,
1676
+ ty:: IntTy :: I64 => Some ( sym:: i64) ,
1677
+ ty:: IntTy :: I128 => Some ( sym:: i128) ,
1678
+ } ,
1679
+ ty:: Uint ( f) => match f {
1680
+ ty:: UintTy :: Usize => Some ( sym:: usize) ,
1681
+ ty:: UintTy :: U8 => Some ( sym:: u8) ,
1682
+ ty:: UintTy :: U16 => Some ( sym:: u16) ,
1683
+ ty:: UintTy :: U32 => Some ( sym:: u32) ,
1684
+ ty:: UintTy :: U64 => Some ( sym:: u64) ,
1685
+ ty:: UintTy :: U128 => Some ( sym:: u128) ,
1686
+ } ,
1687
+ _ => None ,
1688
+ } ;
1689
+
1690
+ let similarity = |e : ExpectedFound < Ty < ' tcx > > | {
1691
+ let ( fk, ek) = ( e. found . kind ( ) , e. expected . kind ( ) ) ;
1692
+ match ( fk, ek) {
1693
+ (
1694
+ ty:: Adt ( adt, _) ,
1695
+ ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) ,
1696
+ ) => {
1697
+ let path = self . tcx . def_path ( adt. did ( ) ) . data ;
1698
+ let name = path. last ( ) . unwrap ( ) . data . get_opt_name ( ) ;
1699
+ let prim_sym = primitive_sym ( ek) ;
1700
+
1701
+ if name == prim_sym {
1702
+ return Some ( Similar :: PrimitiveExpected ( * adt, e. expected ) ) ;
1703
+ }
1704
+ None
1705
+ }
1706
+ (
1707
+ ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) ,
1708
+ ty:: Adt ( adt, _) ,
1709
+ ) => {
1710
+ let path = self . tcx . def_path ( adt. did ( ) ) . data ;
1711
+ let name = path. last ( ) . unwrap ( ) . data . get_opt_name ( ) ;
1712
+ let prim_sym = primitive_sym ( fk) ;
1713
+
1714
+ if name == prim_sym {
1715
+ return Some ( Similar :: PrimitiveFound ( e. expected , * adt) ) ;
1716
+ }
1717
+ None
1718
+ }
1719
+ ( ty:: Adt ( f, _) , ty:: Adt ( e, _) ) => {
1720
+ if !f. did ( ) . is_local ( ) && f. did ( ) . krate == e. did ( ) . krate {
1721
+ // Most likely types from different versions of the same crate
1722
+ // are in play, in which case this message isn't so helpful.
1723
+ // A "perhaps two different versions..." error is already emitted for that.
1724
+ return None ;
1725
+ }
1726
+ let e_path = self . tcx . def_path ( e. did ( ) ) . data ;
1727
+ let f_path = self . tcx . def_path ( f. did ( ) ) . data ;
1728
+ if let ( Some ( e_last) , Some ( f_last) ) = ( e_path. last ( ) , f_path. last ( ) ) && e_last == f_last {
1729
+ return Some ( Similar :: Adts ( * f, * e) ) ;
1730
+ }
1731
+ None
1666
1732
}
1733
+ _ => None ,
1667
1734
}
1668
- false
1669
1735
} ;
1670
1736
1671
1737
match terr {
1672
1738
// If two types mismatch but have similar names, mention that specifically.
1673
- TypeError :: Sorts ( values) if looks_similar ( values) => {
1674
- let found_adt = values. found . ty_adt_def ( ) . unwrap ( ) ;
1675
- let expected_adt = values. expected . ty_adt_def ( ) . unwrap ( ) ;
1676
-
1677
- let found_name = values. found . sort_string ( self . tcx ) ;
1678
- let expected_name = values. expected . sort_string ( self . tcx ) ;
1739
+ TypeError :: Sorts ( values) if let Some ( s) = similarity ( values) => {
1740
+ let diagnose_primitive =
1741
+ |prim : Ty < ' tcx > ,
1742
+ shadow : Ty < ' tcx > ,
1743
+ defid : DefId ,
1744
+ diagnostic : & mut Diagnostic | {
1745
+ let name = shadow. sort_string ( self . tcx ) ;
1746
+ diagnostic. note ( format ! (
1747
+ "{prim} and {name} have similar names, but are actually distinct types"
1748
+ ) ) ;
1749
+ diagnostic
1750
+ . note ( format ! ( "{prim} is a primitive defined by the language" ) ) ;
1751
+ let def_span = self . tcx . def_span ( defid) ;
1752
+ let msg = if defid. is_local ( ) {
1753
+ format ! ( "{name} is defined in the current crate" )
1754
+ } else {
1755
+ let crate_name = self . tcx . crate_name ( defid. krate ) ;
1756
+ format ! ( "{name} is defined in crate `{crate_name}" )
1757
+ } ;
1758
+ diagnostic. span_note ( def_span, msg) ;
1759
+ } ;
1679
1760
1680
- diag. note ( format ! ( "{found_name} and {expected_name} have similar names, but are actually distinct types" ) ) ;
1761
+ let diagnose_adts =
1762
+ |found_adt : ty:: AdtDef < ' tcx > ,
1763
+ expected_adt : ty:: AdtDef < ' tcx > ,
1764
+ diagnostic : & mut Diagnostic | {
1765
+ let found_name = values. found . sort_string ( self . tcx ) ;
1766
+ let expected_name = values. expected . sort_string ( self . tcx ) ;
1681
1767
1682
- for ( adt, name) in [ ( found_adt, found_name) , ( expected_adt, expected_name) ] {
1683
- let defid = adt. did ( ) ;
1684
- let def_span = self . tcx . def_span ( defid) ;
1768
+ let found_defid = found_adt. did ( ) ;
1769
+ let expected_defid = expected_adt. did ( ) ;
1685
1770
1686
- let msg = if defid. is_local ( ) {
1687
- format ! ( "{name} is defined in the current crate." )
1688
- } else if self . tcx . all_diagnostic_items ( ( ) ) . id_to_name . get ( & defid) . is_some ( )
1689
- {
1690
- // if it's a diagnostic item, it's definitely defined in std/core/alloc
1691
- // otherwise might be, might not be.
1692
- format ! ( "{name} is defined in the standard library." )
1693
- } else {
1694
- let crate_name = self . tcx . crate_name ( defid. krate ) ;
1695
- format ! ( "{name} is defined in crate `{crate_name}`." )
1771
+ diagnostic. note ( format ! ( "{found_name} and {expected_name} have similar names, but are actually distinct types" ) ) ;
1772
+ for ( defid, name) in
1773
+ [ ( found_defid, found_name) , ( expected_defid, expected_name) ]
1774
+ {
1775
+ let def_span = self . tcx . def_span ( defid) ;
1776
+
1777
+ let msg = if found_defid. is_local ( ) && expected_defid. is_local ( ) {
1778
+ let module = self
1779
+ . tcx
1780
+ . parent_module_from_def_id ( defid. expect_local ( ) )
1781
+ . to_def_id ( ) ;
1782
+ let module_name =
1783
+ self . tcx . def_path ( module) . to_string_no_crate_verbose ( ) ;
1784
+ format ! (
1785
+ "{name} is defined in module {module_name} of the current crate"
1786
+ )
1787
+ } else if defid. is_local ( ) {
1788
+ format ! ( "{name} is defined in the current crate" )
1789
+ } else {
1790
+ let crate_name = self . tcx . crate_name ( defid. krate ) ;
1791
+ format ! ( "{name} is defined in crate `{crate_name}`" )
1792
+ } ;
1793
+ diagnostic. span_note ( def_span, msg) ;
1794
+ }
1696
1795
} ;
1697
- diag. span_note ( def_span, msg) ;
1796
+
1797
+ match s {
1798
+ Similar :: Adts ( found_adt, expected_adt) => {
1799
+ diagnose_adts ( found_adt, expected_adt, diag)
1800
+ }
1801
+ Similar :: PrimitiveFound ( prim, e) => {
1802
+ diagnose_primitive ( prim, values. expected , e. did ( ) , diag)
1803
+ }
1804
+ Similar :: PrimitiveExpected ( f, prim) => {
1805
+ diagnose_primitive ( prim, values. found , f. did ( ) , diag)
1806
+ }
1698
1807
}
1699
1808
}
1700
1809
TypeError :: Sorts ( values) => {
0 commit comments