@@ -1654,47 +1654,156 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16541654 ) ,
16551655 Mismatch :: Fixed ( s) => ( s. into ( ) , s. into ( ) , None ) ,
16561656 } ;
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
16661732 }
1733+ _ => None ,
16671734 }
1668- false
16691735 } ;
16701736
16711737 match terr {
16721738 // 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+ } ;
16791760
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 ) ;
16811767
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 ( ) ;
16851770
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+ }
16961795 } ;
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+ }
16981807 }
16991808 }
17001809 TypeError :: Sorts ( values) => {
0 commit comments