@@ -51,6 +51,7 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
5151
5252use crate :: infer;
5353use crate :: infer:: error_reporting:: nice_region_error:: find_anon_type:: find_anon_type;
54+ use crate :: infer:: ExpectedFound ;
5455use crate :: traits:: error_reporting:: report_object_safety_error;
5556use crate :: traits:: {
5657 IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
@@ -1653,8 +1654,114 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16531654 ) ,
16541655 Mismatch :: Fixed ( s) => ( s. into ( ) , s. into ( ) , None ) ,
16551656 } ;
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;
16581765 let sort_string = |ty : Ty < ' tcx > | match ( extra, ty. kind ( ) ) {
16591766 ( true , ty:: Opaque ( def_id, _) ) => {
16601767 let sm = self . tcx . sess . source_map ( ) ;
@@ -1707,10 +1814,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17071814 ) ;
17081815 }
17091816 }
1710- ( TypeError :: ObjectUnsafeCoercion ( _ ) , _) => {
1817+ TypeError :: ObjectUnsafeCoercion ( _) => {
17111818 diag. note_unsuccessful_coercion ( found, expected) ;
17121819 }
1713- ( _ , _ ) => {
1820+ _ => {
17141821 debug ! (
17151822 "note_type_err: exp_found={:?}, expected={:?} found={:?}" ,
17161823 exp_found, expected, found
0 commit comments