@@ -27,10 +27,10 @@ use super::{
2727use fmt_macros:: { Parser , Piece , Position } ;
2828use hir:: def_id:: DefId ;
2929use infer:: { self , InferCtxt , TypeOrigin } ;
30- use ty:: { self , ToPredicate , ToPolyTraitRef , TraitRef , Ty , TyCtxt , TypeFoldable } ;
30+ use ty:: { self , ToPredicate , ToPolyTraitRef , TraitRef , Ty , TyCtxt , TypeFoldable , TypeVariants } ;
3131use ty:: fast_reject;
3232use ty:: fold:: TypeFolder ;
33- use ty:: subst:: { self , Subst } ;
33+ use ty:: subst:: { self , ParamSpace , Subst } ;
3434use util:: nodemap:: { FnvHashMap , FnvHashSet } ;
3535
3636use std:: cmp;
@@ -63,9 +63,9 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
6363}
6464
6565fn impl_substs < ' a , ' tcx > ( fcx : & InferCtxt < ' a , ' tcx > ,
66- did : DefId ,
67- obligation : PredicateObligation < ' tcx > )
68- -> subst:: Substs < ' tcx > {
66+ did : DefId ,
67+ obligation : PredicateObligation < ' tcx > )
68+ -> subst:: Substs < ' tcx > {
6969 let tcx = fcx. tcx ;
7070
7171 let ity = tcx. lookup_item_type ( did) ;
@@ -82,44 +82,109 @@ fn impl_substs<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
8282 substs
8383}
8484
85- /*fn check_type_parameters<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
86- trait_substs: &subst::Substs<'tcx>,
87- impl_substs: &subst::Substs<'tcx>,
88- obligation: &PredicateObligation<'tcx>) -> bool {
89- let trait_types = trait_substs.types.as_slice();
90- let impl_types = impl_substs.types.as_slice();
91-
92- let mut failed = 0;
93- for index_to_ignore in 0..trait_types.len() {
94- for (index, (trait_type, impl_type)) in trait_types.iter()
95- .zip(impl_types.iter())
96- .enumerate() {
97- if index_to_ignore != index &&
98- infer::mk_eqty(infcx, true,
99- TypeOrigin::Misc(obligation.cause.span),
100- trait_type,
101- impl_type).is_err() {
102- failed += 1;
103- break;
104- }
85+ trait AssociatedWeight {
86+ fn get_weight ( & self ) -> usize ;
87+ }
88+
89+ impl < ' a > AssociatedWeight for TypeVariants < ' a > {
90+ // First number is for "global" weight and second number is for bigger precision
91+ fn get_weight ( & self ) -> usize {
92+ match * self {
93+ TypeVariants :: TyBool => 11 ,
94+ TypeVariants :: TyChar => 12 ,
95+ TypeVariants :: TyStr => 13 ,
96+ TypeVariants :: TyInt ( _) => 21 ,
97+ TypeVariants :: TyUint ( _) => 22 ,
98+ TypeVariants :: TyFloat ( _) => 23 ,
99+ TypeVariants :: TyRawPtr ( _) => 24 ,
100+ TypeVariants :: TyEnum ( _, _) => 31 ,
101+ TypeVariants :: TyStruct ( _, _) => 32 ,
102+ TypeVariants :: TyBox ( _) => 33 ,
103+ TypeVariants :: TyTuple ( _) => 34 ,
104+ TypeVariants :: TyArray ( _, _) => 41 ,
105+ TypeVariants :: TySlice ( _) => 42 ,
106+ TypeVariants :: TyRef ( _, _) => 51 ,
107+ TypeVariants :: TyFnDef ( _, _, _) => 52 ,
108+ TypeVariants :: TyFnPtr ( _) => 53 ,
109+ TypeVariants :: TyTrait ( _) => 61 ,
110+ TypeVariants :: TyClosure ( _, _) => 71 ,
111+ TypeVariants :: TyProjection ( _) => 81 ,
112+ TypeVariants :: TyParam ( _) => 82 ,
113+ TypeVariants :: TyInfer ( _) => 83 ,
114+ TypeVariants :: TyError => 91 ,
105115 }
106116 }
107- failed == trait_types.len() - 1
108- }*/
117+ }
118+
119+ // The "closer" the types are, the lesser the weight
120+ fn get_weight_diff ( a : & ty:: TypeVariants , b : & TypeVariants , big_weight : bool ) -> usize {
121+ let w1 = if big_weight { a. get_weight ( ) / 10 } else { a. get_weight ( ) % 10 } ;
122+ let w2 = if big_weight { b. get_weight ( ) / 10 } else { b. get_weight ( ) % 10 } ;
123+
124+ if w1 < w2 {
125+ w2 - w1
126+ } else {
127+ w1 - w2
128+ }
129+ }
130+
131+ // Once we have "globally matching" types, we need to run another filter on them
132+ fn filter_matching_types < ' tcx > ( weights : & [ ( usize , usize ) ] ,
133+ imps : & [ ( DefId , subst:: Substs < ' tcx > ) ] ,
134+ trait_types : & [ ty:: Ty < ' tcx > ] )
135+ -> usize {
136+ let matching_weight = weights[ 0 ] . 1 ;
137+ let iter = weights. iter ( ) . filter ( |& & ( _, weight) | weight == matching_weight) ;
138+ let mut filtered_weights = vec ! ( ) ;
139+
140+ for & ( pos, _) in iter {
141+ let mut weight = 0 ;
142+ for ( type_to_compare, original_type) in imps[ pos] . 1
143+ . types
144+ . get_slice ( ParamSpace :: TypeSpace )
145+ . iter ( )
146+ . zip ( trait_types. iter ( ) ) {
147+ weight += get_weight_diff ( & type_to_compare. sty , & original_type. sty , false ) ;
148+ }
149+ filtered_weights. push ( ( pos, weight) ) ;
150+ }
151+ filtered_weights. sort_by ( |a, b| a. 1 . cmp ( & b. 1 ) ) ;
152+ filtered_weights[ 0 ] . 0
153+ }
154+
155+ fn get_best_matching_type < ' tcx > ( imps : & [ ( DefId , subst:: Substs < ' tcx > ) ] ,
156+ trait_types : & [ ty:: Ty < ' tcx > ] ) -> usize {
157+ let mut weights = vec ! ( ) ;
158+ for ( pos, imp) in imps. iter ( ) . enumerate ( ) {
159+ let mut weight = 0 ;
160+ for ( type_to_compare, original_type) in imp. 1
161+ . types
162+ . get_slice ( ParamSpace :: TypeSpace )
163+ . iter ( )
164+ . zip ( trait_types. iter ( ) ) {
165+ weight += get_weight_diff ( & type_to_compare. sty , & original_type. sty , true ) ;
166+ }
167+ weights. push ( ( pos, weight) ) ;
168+ }
169+ weights. sort_by ( |a, b| a. 1 . cmp ( & b. 1 ) ) ;
170+ if weights[ 0 ] . 1 == weights[ 1 ] . 1 {
171+ filter_matching_types ( & weights, & imps, trait_types)
172+ } else {
173+ weights[ 0 ] . 0
174+ }
175+ }
109176
110177fn get_current_failing_impl < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
111178 trait_ref : & TraitRef < ' tcx > ,
112179 obligation : & PredicateObligation < ' tcx > )
113180 -> Option < ( DefId , subst:: Substs < ' tcx > ) > {
114- println ! ( "1" ) ;
115181 let simp = fast_reject:: simplify_type ( infcx. tcx ,
116182 trait_ref. self_ty ( ) ,
117183 true ) ;
118184 let trait_def = infcx. tcx . lookup_trait_def ( trait_ref. def_id ) ;
119185
120186 match simp {
121187 Some ( _) => {
122- println ! ( "2" ) ;
123188 let mut matching_impls = Vec :: new ( ) ;
124189 trait_def. for_each_impl ( infcx. tcx , |def_id| {
125190 let imp = infcx. tcx . impl_trait_ref ( def_id) . unwrap ( ) ;
@@ -130,25 +195,19 @@ fn get_current_failing_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
130195 TypeOrigin :: Misc ( obligation. cause . span ) ,
131196 trait_ref. self_ty ( ) ,
132197 imp. self_ty ( ) ) . is_ok ( ) {
133- //if check_type_parameters(infcx, &trait_ref.substs, &imp.substs, obligation) {
134- matching_impls. push ( ( def_id, imp. substs . clone ( ) ) ) ;
135- //}
198+ matching_impls. push ( ( def_id, imp. substs . clone ( ) ) ) ;
136199 }
137- println ! ( "=> {:?} /// {:?}" , def_id, imp. substs) ;
138200 } ) ;
139201 if matching_impls. len ( ) == 0 {
140- println ! ( "3" ) ;
141202 None
142203 } else if matching_impls. len ( ) == 1 {
143- println ! ( "4" ) ;
144204 Some ( matching_impls[ 0 ] . clone ( ) )
145205 } else {
146- println ! ( "5" ) ;
206+ let end = trait_ref . input_types ( ) . len ( ) - 1 ;
147207 // we need to determine which type is the good one!
148- for & ( ref m, ref n) in matching_impls. iter ( ) {
149- println ! ( "=> {:?} /// {:?}" , m, n) ;
150- }
151- Some ( matching_impls[ 0 ] . clone ( ) )
208+ Some ( matching_impls[ get_best_matching_type ( & matching_impls,
209+ & trait_ref. input_types ( ) [ 0 ..end] ) ]
210+ . clone ( ) )
152211 }
153212 } ,
154213 None => None ,
@@ -171,7 +230,6 @@ fn on_unimplemented_note<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
171230 trait_ref : ty:: PolyTraitRef < ' tcx > ,
172231 obligation : & PredicateObligation < ' tcx > ) -> Option < String > {
173232 let trait_ref = trait_ref. skip_binder ( ) ;
174- //let def_id = trait_ref.def_id;
175233 let mut report = None ;
176234 let def_id = match get_current_failing_impl ( infcx, trait_ref, obligation) {
177235 Some ( ( def_id, _) ) => {
@@ -603,8 +661,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
603661 // Try to report a help message
604662
605663 if !trait_ref. has_infer_types ( ) &&
606- predicate_can_apply ( infcx, trait_ref)
607- {
664+ predicate_can_apply ( infcx, trait_ref) {
608665 // If a where-clause may be useful, remind the
609666 // user that they can add it.
610667 //
@@ -662,18 +719,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
662719 // similar impls.
663720
664721 self . report_similar_impl_candidates ( trait_ref, & mut err) ;
722+ // If we can't show anything useful, try to find
723+ // similar impls.
724+ let impl_candidates =
725+ find_similar_impl_candidates ( infcx, trait_ref) ;
726+ if impl_candidates. len ( ) > 0 {
727+ self . report_similar_impl_candidates ( trait_ref, & mut err) ;
665728 }
666729 err
667730 }
668- // Check if it has a custom "#[rustc_on_unimplemented]"
669- // error message, report with that message if it does
670- /*let custom_note = report_on_unimplemented(infcx, &trait_ref.0,
671- obligation);
672- if let Some(s) = custom_note {
673- err.fileline_note(obligation.cause.span, &s);
674- } else {
675- note_obligation_cause(infcx, &mut err, obligation);
676- }*/
731+ note_obligation_cause ( infcx, & mut err, obligation) ;
677732 err. emit ( ) ;
678733 }
679734
0 commit comments