@@ -555,6 +555,155 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
555555 }
556556 }
557557
558+ fn highlight_outer ( & self ,
559+ value : & mut Vec < ( String , bool ) > ,
560+ other_value : & mut Vec < ( String , bool ) > ,
561+ name : String ,
562+ sub : & ty:: subst:: Substs < ' tcx > ,
563+ pos : usize ,
564+ other_ty : & ty:: Ty < ' tcx > ) {
565+ value. push ( ( name, true ) ) ;
566+ let len = sub. len ( ) ;
567+ if len > 0 {
568+ value. push ( ( "<" . to_string ( ) , true ) ) ;
569+ }
570+
571+ let sts = sub. regions ( ) ;
572+ for ( i, st) in sts. enumerate ( ) {
573+ value. push ( ( format ! ( "{}" , st) , false ) ) ;
574+
575+ if len > 0 && i != len - 1 {
576+ value. push ( ( format ! ( ", " ) , false ) ) ;
577+ }
578+ }
579+
580+ let sts = sub. types ( ) ;
581+ for ( i, st) in sts. enumerate ( ) {
582+ if i == pos {
583+ let ( v, o_v) = self . cmp ( st, other_ty) ;
584+ value. extend ( v) ;
585+ other_value. extend ( o_v) ;
586+ } else {
587+ value. push ( ( format ! ( "{}" , st) , true ) ) ;
588+ }
589+
590+ if len > 0 && i != len - 1 {
591+ value. push ( ( format ! ( ", " ) , true ) ) ;
592+ }
593+ }
594+ if len > 0 {
595+ value. push ( ( ">" . to_string ( ) , true ) ) ;
596+ }
597+ }
598+
599+
600+ fn cmp ( & self , t1 : ty:: Ty < ' tcx > , t2 : ty:: Ty < ' tcx > )
601+ -> ( Vec < ( String , bool ) > , Vec < ( String , bool ) > )
602+ {
603+ match ( & t1. sty , & t2. sty ) {
604+ ( & ty:: TyAdt ( def1, sub1) , & ty:: TyAdt ( def2, sub2) ) => {
605+ let mut values: ( Vec < ( String , bool ) > , Vec < ( String , bool ) > ) = ( vec ! [ ] , vec ! [ ] ) ;
606+ let name1 = self . tcx . item_path_str ( def1. did . clone ( ) ) ;
607+ let name2 = self . tcx . item_path_str ( def2. did . clone ( ) ) ;
608+ if name1 == name2 {
609+ // Easy case, replace same types with `_` to shorten the output
610+ // and highlight only the differing types.
611+ values. 0 . push ( ( name1. to_string ( ) , false ) ) ;
612+ values. 1 . push ( ( name2. to_string ( ) , false ) ) ;
613+
614+ let len = sub1. len ( ) ;
615+ if len > 0 {
616+ values. 0 . push ( ( "<" . to_string ( ) , false ) ) ;
617+ values. 1 . push ( ( "<" . to_string ( ) , false ) ) ;
618+ }
619+
620+ let sts1 = sub1. regions ( ) ;
621+ let sts2 = sub2. regions ( ) ;
622+ let x = sts1. zip ( sts2) ;
623+ for ( i, ( st1, st2) ) in x. enumerate ( ) {
624+ values. 0 . push ( ( format ! ( "{}" , st1) , st1 != st2) ) ;
625+ values. 1 . push ( ( format ! ( "{}" , st2) , st1 != st2) ) ;
626+
627+ if len > 0 && i != len - 1 {
628+ values. 0 . push ( ( format ! ( ", " ) , false ) ) ;
629+ values. 1 . push ( ( format ! ( ", " ) , false ) ) ;
630+ }
631+ }
632+
633+ let sts1 = sub1. types ( ) ;
634+ let sts2 = sub2. types ( ) ;
635+ let x = sts1. zip ( sts2) ;
636+ for ( i, ( st1, st2) ) in x. enumerate ( ) {
637+ if st1 == st2 {
638+ values. 0 . push ( ( "_" . to_string ( ) , false ) ) ;
639+ values. 1 . push ( ( "_" . to_string ( ) , false ) ) ;
640+ } else {
641+ let ( x1, x2) = self . cmp ( st1, st2) ;
642+ values. 0 . extend ( x1) ;
643+ values. 1 . extend ( x2) ;
644+ }
645+ if len > 0 && i != len - 1 {
646+ values. 0 . push ( ( format ! ( ", " ) , false ) ) ;
647+ values. 1 . push ( ( format ! ( ", " ) , false ) ) ;
648+ }
649+ }
650+ if len > 0 {
651+ values. 0 . push ( ( ">" . to_string ( ) , false ) ) ;
652+ values. 1 . push ( ( ">" . to_string ( ) , false ) ) ;
653+ }
654+ values
655+ } else {
656+ // Check for simple composition
657+ for ( i, st) in sub1. types ( ) . enumerate ( ) {
658+ if st == t2 {
659+ self . highlight_outer ( & mut values. 0 , & mut values. 1 , name1, sub1, i, & t2) ;
660+ return values;
661+ }
662+ if let & ty:: TyAdt ( def, _) = & st. sty {
663+ let name = self . tcx . item_path_str ( def. did . clone ( ) ) ;
664+ if name == name2 {
665+ self . highlight_outer ( & mut values. 0 ,
666+ & mut values. 1 ,
667+ name1,
668+ sub1,
669+ i,
670+ & t2) ;
671+ return values;
672+ }
673+ }
674+ }
675+ for ( i, st) in sub2. types ( ) . enumerate ( ) {
676+ if st == t1 {
677+ self . highlight_outer ( & mut values. 1 , & mut values. 0 , name2, sub2, i, & t1) ;
678+ return values;
679+ }
680+ if let & ty:: TyAdt ( def, _) = & st. sty {
681+ let name = self . tcx . item_path_str ( def. did . clone ( ) ) ;
682+ if name == name1 {
683+ self . highlight_outer ( & mut values. 1 ,
684+ & mut values. 0 ,
685+ name2,
686+ sub2,
687+ i,
688+ & t1) ;
689+ return values;
690+ }
691+ }
692+ }
693+
694+ ( vec ! [ ( format!( "{}" , t1) , true ) ] , vec ! [ ( format!( "{}" , t2) , true ) ] )
695+ }
696+ }
697+ _ => {
698+ if t1 == t2 {
699+ ( vec ! [ ( "_" . to_string( ) , false ) ] , vec ! [ ( "_" . to_string( ) , false ) ] )
700+ } else {
701+ ( vec ! [ ( format!( "{}" , t1) , true ) ] , vec ! [ ( format!( "{}" , t2) , true ) ] )
702+ }
703+ }
704+ }
705+ }
706+
558707 pub fn note_type_err ( & self ,
559708 diag : & mut DiagnosticBuilder < ' tcx > ,
560709 cause : & ObligationCause < ' tcx > ,
@@ -665,26 +814,64 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
665814 diag
666815 }
667816
668- /// Returns a string of the form "expected `{}`, found `{}`".
669- fn values_str ( & self , values : & ValuePairs < ' tcx > ) -> Option < ( String , String ) > {
817+ /// Returns two `Vec`s representing portions of a type with a flag on wether it should
818+ /// be highlighted in the output.
819+ ///
820+ /// For given types `X<String, usize>` and `X<usize, usize>`, this method would return
821+ ///
822+ /// ```nocode
823+ /// Some((vec![
824+ /// ("X", false),
825+ /// ("<", false),
826+ /// ("String", true),
827+ /// (",", false),
828+ /// ("_", false),
829+ /// (">", false)
830+ /// ], vec![
831+ /// ("X", false),
832+ /// ("<", false),
833+ /// ("usize", true),
834+ /// (",", false),
835+ /// ("_", false),
836+ /// (">", false)
837+ /// ]))
838+ /// ```
839+ fn values_str ( & self , values : & ValuePairs < ' tcx > )
840+ -> Option < ( Vec < ( String , bool ) > , Vec < ( String , bool ) > ) >
841+ {
670842 match * values {
671- infer:: Types ( ref exp_found) => self . expected_found_str ( exp_found) ,
843+ infer:: Types ( ref exp_found) => self . expected_found_str_ty ( exp_found) ,
672844 infer:: TraitRefs ( ref exp_found) => self . expected_found_str ( exp_found) ,
673845 infer:: PolyTraitRefs ( ref exp_found) => self . expected_found_str ( exp_found) ,
674846 }
675847 }
676848
849+ fn expected_found_str_ty (
850+ & self ,
851+ exp_found : & ty:: error:: ExpectedFound < ty:: Ty < ' tcx > > )
852+ -> Option < ( Vec < ( String , bool ) > , Vec < ( String , bool ) > ) >
853+ {
854+ let exp_found = self . resolve_type_vars_if_possible ( exp_found) ;
855+ if exp_found. references_error ( ) {
856+ return None ;
857+ }
858+
859+ Some ( self . cmp ( exp_found. expected , exp_found. found ) )
860+ }
861+
862+
677863 fn expected_found_str < T : fmt:: Display + TypeFoldable < ' tcx > > (
678864 & self ,
679865 exp_found : & ty:: error:: ExpectedFound < T > )
680- -> Option < ( String , String ) >
866+ -> Option < ( Vec < ( String , bool ) > , Vec < ( String , bool ) > ) >
681867 {
682868 let exp_found = self . resolve_type_vars_if_possible ( exp_found) ;
683869 if exp_found. references_error ( ) {
684870 return None ;
685871 }
686872
687- Some ( ( format ! ( "{}" , exp_found. expected) , format ! ( "{}" , exp_found. found) ) )
873+ Some ( ( vec ! [ ( format!( "{}" , exp_found. expected) , true ) ] ,
874+ vec ! [ ( format!( "{}" , exp_found. found) , true ) ] ) )
688875 }
689876
690877 fn report_generic_bound_failure ( & self ,
@@ -1140,6 +1327,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
11401327 match * origin {
11411328 infer:: Subtype ( ref trace) => {
11421329 if let Some ( ( expected, found) ) = self . values_str ( & trace. values ) {
1330+ let expected = expected. iter ( ) . map ( |x| x. 0 . to_owned ( ) ) . collect :: < String > ( ) ;
1331+ let found = found. iter ( ) . map ( |x| x. 0 . to_owned ( ) ) . collect :: < String > ( ) ;
11431332 // FIXME: do we want a "the" here?
11441333 err. span_note (
11451334 trace. cause . span ,
0 commit comments