@@ -63,8 +63,8 @@ use crate::ty::{self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldabl
6363
6464use errors:: { Applicability , DiagnosticBuilder , DiagnosticStyledString } ;
6565use rustc_error_codes:: * ;
66+ use rustc_target:: spec:: abi;
6667use syntax_pos:: { Pos , Span } ;
67-
6868use std:: { cmp, fmt} ;
6969
7070mod note;
@@ -766,7 +766,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
766766 if len > 0 && i != len - 1 {
767767 value. push_normal ( ", " ) ;
768768 }
769- //self.push_comma(&mut value, &mut other_value, len, i);
770769 }
771770 if len > 0 {
772771 value. push_highlighted ( ">" ) ;
@@ -868,6 +867,120 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
868867 substs. truncate_to ( self . tcx , & generics)
869868 }
870869
870+ /// Given two `fn` signatures highlight only sub-parts that are different.
871+ fn cmp_fn_sig (
872+ & self ,
873+ sig1 : & ty:: PolyFnSig < ' tcx > ,
874+ sig2 : & ty:: PolyFnSig < ' tcx > ,
875+ ) -> ( DiagnosticStyledString , DiagnosticStyledString ) {
876+ let get_lifetimes = |sig| {
877+ use crate :: hir:: def:: Namespace ;
878+ let mut s = String :: new ( ) ;
879+ let ( _, ( sig, reg) ) = ty:: print:: FmtPrinter :: new ( self . tcx , & mut s, Namespace :: TypeNS )
880+ . name_all_regions ( sig)
881+ . unwrap ( ) ;
882+ let lts: Vec < String > = reg. into_iter ( ) . map ( |( _, kind) | kind. to_string ( ) ) . collect ( ) ;
883+ ( if lts. is_empty ( ) {
884+ String :: new ( )
885+ } else {
886+ format ! ( "for<{}> " , lts. join( ", " ) )
887+ } , sig)
888+ } ;
889+
890+ let ( lt1, sig1) = get_lifetimes ( sig1) ;
891+ let ( lt2, sig2) = get_lifetimes ( sig2) ;
892+
893+ // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
894+ let mut values = (
895+ DiagnosticStyledString :: normal ( "" . to_string ( ) ) ,
896+ DiagnosticStyledString :: normal ( "" . to_string ( ) ) ,
897+ ) ;
898+
899+ // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
900+ // ^^^^^^
901+ values. 0 . push ( sig1. unsafety . prefix_str ( ) , sig1. unsafety != sig2. unsafety ) ;
902+ values. 1 . push ( sig2. unsafety . prefix_str ( ) , sig1. unsafety != sig2. unsafety ) ;
903+
904+ // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
905+ // ^^^^^^^^^^
906+ if sig1. abi != abi:: Abi :: Rust {
907+ values. 0 . push ( format ! ( "extern {} " , sig1. abi) , sig1. abi != sig2. abi ) ;
908+ }
909+ if sig2. abi != abi:: Abi :: Rust {
910+ values. 1 . push ( format ! ( "extern {} " , sig2. abi) , sig1. abi != sig2. abi ) ;
911+ }
912+
913+ // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
914+ // ^^^^^^^^
915+ let lifetime_diff = lt1 != lt2;
916+ values. 0 . push ( lt1, lifetime_diff) ;
917+ values. 1 . push ( lt2, lifetime_diff) ;
918+
919+ // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
920+ // ^^^
921+ values. 0 . push_normal ( "fn(" ) ;
922+ values. 1 . push_normal ( "fn(" ) ;
923+
924+ // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
925+ // ^^^^^
926+ let len1 = sig1. inputs ( ) . len ( ) ;
927+ let len2 = sig2. inputs ( ) . len ( ) ;
928+ if len1 == len2 {
929+ for ( i, ( l, r) ) in sig1. inputs ( ) . iter ( ) . zip ( sig2. inputs ( ) . iter ( ) ) . enumerate ( ) {
930+ let ( x1, x2) = self . cmp ( l, r) ;
931+ ( values. 0 ) . 0 . extend ( x1. 0 ) ;
932+ ( values. 1 ) . 0 . extend ( x2. 0 ) ;
933+ self . push_comma ( & mut values. 0 , & mut values. 1 , len1, i) ;
934+ }
935+ } else {
936+ for ( i, l) in sig1. inputs ( ) . iter ( ) . enumerate ( ) {
937+ values. 0 . push_highlighted ( l. to_string ( ) ) ;
938+ if i != len1 - 1 {
939+ values. 0 . push_highlighted ( ", " ) ;
940+ }
941+ }
942+ for ( i, r) in sig2. inputs ( ) . iter ( ) . enumerate ( ) {
943+ values. 1 . push_highlighted ( r. to_string ( ) ) ;
944+ if i != len2 - 1 {
945+ values. 1 . push_highlighted ( ", " ) ;
946+ }
947+ }
948+ }
949+
950+ if sig1. c_variadic {
951+ if len1 > 0 {
952+ values. 0 . push_normal ( ", " ) ;
953+ }
954+ values. 0 . push ( "..." , !sig2. c_variadic ) ;
955+ }
956+ if sig2. c_variadic {
957+ if len2 > 0 {
958+ values. 1 . push_normal ( ", " ) ;
959+ }
960+ values. 1 . push ( "..." , !sig1. c_variadic ) ;
961+ }
962+
963+ // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
964+ // ^
965+ values. 0 . push_normal ( ")" ) ;
966+ values. 1 . push_normal ( ")" ) ;
967+
968+ // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
969+ // ^^^^^^^^
970+ let output1 = sig1. output ( ) ;
971+ let output2 = sig2. output ( ) ;
972+ let ( x1, x2) = self . cmp ( output1, output2) ;
973+ if !output1. is_unit ( ) {
974+ values. 0 . push_normal ( " -> " ) ;
975+ ( values. 0 ) . 0 . extend ( x1. 0 ) ;
976+ }
977+ if !output2. is_unit ( ) {
978+ values. 1 . push_normal ( " -> " ) ;
979+ ( values. 1 ) . 0 . extend ( x2. 0 ) ;
980+ }
981+ values
982+ }
983+
871984 /// Compares two given types, eliding parts that are the same between them and highlighting
872985 /// relevant differences, and return two representation of those types for highlighted printing.
873986 fn cmp ( & self , t1 : Ty < ' tcx > , t2 : Ty < ' tcx > ) -> ( DiagnosticStyledString , DiagnosticStyledString ) {
@@ -968,7 +1081,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
9681081 for ( i, lifetimes) in lifetimes. enumerate ( ) {
9691082 let l1 = lifetime_display ( lifetimes. 0 ) ;
9701083 let l2 = lifetime_display ( lifetimes. 1 ) ;
971- if l1 == l2 {
1084+ if lifetimes . 0 == lifetimes . 1 {
9721085 values. 0 . push_normal ( "'_" ) ;
9731086 values. 1 . push_normal ( "'_" ) ;
9741087 } else {
@@ -1124,6 +1237,64 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11241237 values
11251238 }
11261239
1240+ // When encountering tuples of the same size, highlight only the differing types
1241+ ( & ty:: Tuple ( substs1) , & ty:: Tuple ( substs2) ) if substs1. len ( ) == substs2. len ( ) => {
1242+ let mut values = (
1243+ DiagnosticStyledString :: normal ( "(" ) ,
1244+ DiagnosticStyledString :: normal ( "(" ) ,
1245+ ) ;
1246+ let len = substs1. len ( ) ;
1247+ for ( i, ( left, right) ) in substs1. types ( ) . zip ( substs2. types ( ) ) . enumerate ( ) {
1248+ let ( x1, x2) = self . cmp ( left, right) ;
1249+ ( values. 0 ) . 0 . extend ( x1. 0 ) ;
1250+ ( values. 1 ) . 0 . extend ( x2. 0 ) ;
1251+ self . push_comma ( & mut values. 0 , & mut values. 1 , len, i) ;
1252+ }
1253+ if len == 1 { // Keep the output for single element tuples as `(ty,)`.
1254+ values. 0 . push_normal ( "," ) ;
1255+ values. 1 . push_normal ( "," ) ;
1256+ }
1257+ values. 0 . push_normal ( ")" ) ;
1258+ values. 1 . push_normal ( ")" ) ;
1259+ values
1260+ }
1261+
1262+ ( ty:: FnDef ( did1, substs1) , ty:: FnDef ( did2, substs2) ) => {
1263+ let sig1 = self . tcx . fn_sig ( * did1) . subst ( self . tcx , substs1) ;
1264+ let sig2 = self . tcx . fn_sig ( * did2) . subst ( self . tcx , substs2) ;
1265+ let mut values = self . cmp_fn_sig ( & sig1, & sig2) ;
1266+ let path1 = format ! ( " {{{}}}" , self . tcx. def_path_str_with_substs( * did1, substs1) ) ;
1267+ let path2 = format ! ( " {{{}}}" , self . tcx. def_path_str_with_substs( * did2, substs2) ) ;
1268+ let same_path = path1 == path2;
1269+ values. 0 . push ( path1, !same_path) ;
1270+ values. 1 . push ( path2, !same_path) ;
1271+ values
1272+ }
1273+
1274+ ( ty:: FnDef ( did1, substs1) , ty:: FnPtr ( sig2) ) => {
1275+ let sig1 = self . tcx . fn_sig ( * did1) . subst ( self . tcx , substs1) ;
1276+ let mut values = self . cmp_fn_sig ( & sig1, sig2) ;
1277+ values. 0 . push_normal ( format ! (
1278+ " {{{}}}" ,
1279+ self . tcx. def_path_str_with_substs( * did1, substs1) ) ,
1280+ ) ;
1281+ values
1282+ }
1283+
1284+ ( ty:: FnPtr ( sig1) , ty:: FnDef ( did2, substs2) ) => {
1285+ let sig2 = self . tcx . fn_sig ( * did2) . subst ( self . tcx , substs2) ;
1286+ let mut values = self . cmp_fn_sig ( sig1, & sig2) ;
1287+ values. 1 . push_normal ( format ! (
1288+ " {{{}}}" ,
1289+ self . tcx. def_path_str_with_substs( * did2, substs2) ) ,
1290+ ) ;
1291+ values
1292+ }
1293+
1294+ ( ty:: FnPtr ( sig1) , ty:: FnPtr ( sig2) ) => {
1295+ self . cmp_fn_sig ( sig1, sig2)
1296+ }
1297+
11271298 _ => {
11281299 if t1 == t2 {
11291300 // The two types are the same, elide and don't highlight.
0 commit comments