@@ -60,13 +60,13 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
6060use super :: region_constraints:: GenericKind ;
6161use super :: lexical_region_resolve:: RegionResolutionError ;
6262
63- use std:: fmt;
63+ use std:: { cmp , fmt} ;
6464use hir;
6565use hir:: map as hir_map;
6666use hir:: def_id:: DefId ;
6767use middle:: region;
6868use traits:: { ObligationCause , ObligationCauseCode } ;
69- use ty:: { self , Region , Ty , TyCtxt , TypeFoldable , TypeVariants } ;
69+ use ty:: { self , subst :: Subst , Region , Ty , TyCtxt , TypeFoldable , TypeVariants } ;
7070use ty:: error:: TypeError ;
7171use syntax:: ast:: DUMMY_NODE_ID ;
7272use syntax_pos:: { Pos , Span } ;
@@ -672,6 +672,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
672672 }
673673 }
674674
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+
675712 /// Compare two given types, eliding parts that are the same between them and highlighting
676713 /// relevant differences, and return two representation of those types for highlighted printing.
677714 fn cmp ( & self , t1 : Ty < ' tcx > , t2 : Ty < ' tcx > ) -> ( DiagnosticStyledString , DiagnosticStyledString ) {
@@ -713,6 +750,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
713750
714751 match ( & t1. sty , & t2. sty ) {
715752 ( & 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) ;
716755 let mut values = ( DiagnosticStyledString :: new ( ) , DiagnosticStyledString :: new ( ) ) ;
717756 let path1 = self . tcx . item_path_str ( def1. did . clone ( ) ) ;
718757 let path2 = self . tcx . item_path_str ( def2. did . clone ( ) ) ;
@@ -728,8 +767,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
728767 values. 0 . push_normal ( path1) ;
729768 values. 1 . push_normal ( path2) ;
730769
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+
731782 // Only draw `<...>` if there're lifetime/type arguments.
732- let len = sub1. len ( ) ;
733783 if len > 0 {
734784 values. 0 . push_normal ( "<" ) ;
735785 values. 1 . push_normal ( "<" ) ;
@@ -774,7 +824,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
774824 // ^ elided type as this type argument was the same in both sides
775825 let type_arguments = sub1. types ( ) . zip ( sub2. types ( ) ) ;
776826 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 ( ) {
778828 let i = i + regions_len;
779829 if ta1 == ta2 {
780830 values. 0 . push_normal ( "_" ) ;
@@ -804,7 +854,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
804854 & mut values. 0 ,
805855 & mut values. 1 ,
806856 path1. clone ( ) ,
807- sub1 ,
857+ sub_no_defaults_1 ,
808858 path2. clone ( ) ,
809859 & t2,
810860 ) . is_some ( )
@@ -816,8 +866,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
816866 // Bar<Qux>
817867 // Foo<Bar<Qux>>
818868 // ------- 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 ( )
821877 {
822878 return values;
823879 }
0 commit comments