@@ -60,13 +60,13 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
60
60
use super :: region_constraints:: GenericKind ;
61
61
use super :: lexical_region_resolve:: RegionResolutionError ;
62
62
63
- use std:: fmt;
63
+ use std:: { cmp , fmt} ;
64
64
use hir;
65
65
use hir:: map as hir_map;
66
66
use hir:: def_id:: DefId ;
67
67
use middle:: region;
68
68
use traits:: { ObligationCause , ObligationCauseCode } ;
69
- use ty:: { self , Region , Ty , TyCtxt , TypeFoldable , TypeVariants } ;
69
+ use ty:: { self , subst :: Subst , Region , Ty , TyCtxt , TypeFoldable , TypeVariants } ;
70
70
use ty:: error:: TypeError ;
71
71
use syntax:: ast:: DUMMY_NODE_ID ;
72
72
use syntax_pos:: { Pos , Span } ;
@@ -672,6 +672,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
672
672
}
673
673
}
674
674
675
+ /// For generic types with parameters with defaults, remove the parameters corresponding to
676
+ /// the defaults. This repeats a lot of the logic found in `PrintContext::parameterized`.
677
+ fn strip_generic_default_params (
678
+ & self ,
679
+ def_id : DefId ,
680
+ substs : & ty:: subst:: Substs < ' tcx >
681
+ ) -> & ' tcx ty:: subst:: Substs < ' tcx > {
682
+ let generics = self . tcx . generics_of ( def_id) ;
683
+ let mut num_supplied_defaults = 0 ;
684
+ let mut type_params = generics. params . iter ( ) . rev ( ) . filter_map ( |param| match param. kind {
685
+ ty:: GenericParamDefKind :: Lifetime => None ,
686
+ ty:: GenericParamDefKind :: Type { has_default, .. } => {
687
+ Some ( ( param. def_id , has_default) )
688
+ }
689
+ } ) . peekable ( ) ;
690
+ let has_default = {
691
+ let has_default = type_params. peek ( ) . map ( |( _, has_default) | has_default) ;
692
+ * has_default. unwrap_or ( & false )
693
+ } ;
694
+ if has_default {
695
+ let types = substs. types ( ) . rev ( ) ;
696
+ for ( ( def_id, has_default) , actual) in type_params. zip ( types) {
697
+ if !has_default {
698
+ break ;
699
+ }
700
+ if self . tcx . type_of ( def_id) . subst ( self . tcx , substs) != actual {
701
+ break ;
702
+ }
703
+ num_supplied_defaults += 1 ;
704
+ }
705
+ }
706
+ let len = generics. params . len ( ) ;
707
+ let mut generics = generics. clone ( ) ;
708
+ generics. params . truncate ( len - num_supplied_defaults) ;
709
+ substs. truncate_to ( self . tcx , & generics)
710
+ }
711
+
675
712
/// Compare two given types, eliding parts that are the same between them and highlighting
676
713
/// relevant differences, and return two representation of those types for highlighted printing.
677
714
fn cmp ( & self , t1 : Ty < ' tcx > , t2 : Ty < ' tcx > ) -> ( DiagnosticStyledString , DiagnosticStyledString ) {
@@ -713,6 +750,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
713
750
714
751
match ( & t1. sty , & t2. sty ) {
715
752
( & ty:: TyAdt ( def1, sub1) , & ty:: TyAdt ( def2, sub2) ) => {
753
+ let sub_no_defaults_1 = self . strip_generic_default_params ( def1. did , sub1) ;
754
+ let sub_no_defaults_2 = self . strip_generic_default_params ( def2. did , sub2) ;
716
755
let mut values = ( DiagnosticStyledString :: new ( ) , DiagnosticStyledString :: new ( ) ) ;
717
756
let path1 = self . tcx . item_path_str ( def1. did . clone ( ) ) ;
718
757
let path2 = self . tcx . item_path_str ( def2. did . clone ( ) ) ;
@@ -728,8 +767,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
728
767
values. 0 . push_normal ( path1) ;
729
768
values. 1 . push_normal ( path2) ;
730
769
770
+ // Avoid printing out default generic parameters that are common to both
771
+ // types.
772
+ let len1 = sub_no_defaults_1. len ( ) ;
773
+ let len2 = sub_no_defaults_2. len ( ) ;
774
+ let common_len = cmp:: min ( len1, len2) ;
775
+ let remainder1: Vec < _ > = sub1. types ( ) . skip ( common_len) . collect ( ) ;
776
+ let remainder2: Vec < _ > = sub2. types ( ) . skip ( common_len) . collect ( ) ;
777
+ let common_default_params =
778
+ remainder1. iter ( ) . rev ( ) . zip ( remainder2. iter ( ) . rev ( ) )
779
+ . filter ( |( a, b) | a == b) . count ( ) ;
780
+ let len = sub1. len ( ) - common_default_params;
781
+
731
782
// Only draw `<...>` if there're lifetime/type arguments.
732
- let len = sub1. len ( ) ;
733
783
if len > 0 {
734
784
values. 0 . push_normal ( "<" ) ;
735
785
values. 1 . push_normal ( "<" ) ;
@@ -774,7 +824,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
774
824
// ^ elided type as this type argument was the same in both sides
775
825
let type_arguments = sub1. types ( ) . zip ( sub2. types ( ) ) ;
776
826
let regions_len = sub1. regions ( ) . collect :: < Vec < _ > > ( ) . len ( ) ;
777
- for ( i, ( ta1, ta2) ) in type_arguments. enumerate ( ) {
827
+ for ( i, ( ta1, ta2) ) in type_arguments. take ( len ) . enumerate ( ) {
778
828
let i = i + regions_len;
779
829
if ta1 == ta2 {
780
830
values. 0 . push_normal ( "_" ) ;
@@ -804,7 +854,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
804
854
& mut values. 0 ,
805
855
& mut values. 1 ,
806
856
path1. clone ( ) ,
807
- sub1 ,
857
+ sub_no_defaults_1 ,
808
858
path2. clone ( ) ,
809
859
& t2,
810
860
) . is_some ( )
@@ -816,8 +866,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
816
866
// Bar<Qux>
817
867
// Foo<Bar<Qux>>
818
868
// ------- this type argument is exactly the same as the other type
819
- if self . cmp_type_arg ( & mut values. 1 , & mut values. 0 , path2, sub2, path1, & t1)
820
- . is_some ( )
869
+ if self . cmp_type_arg (
870
+ & mut values. 1 ,
871
+ & mut values. 0 ,
872
+ path2,
873
+ sub_no_defaults_2,
874
+ path1,
875
+ & t1,
876
+ ) . is_some ( )
821
877
{
822
878
return values;
823
879
}
0 commit comments