@@ -27,10 +27,10 @@ use super::{
27
27
use fmt_macros:: { Parser , Piece , Position } ;
28
28
use hir:: def_id:: DefId ;
29
29
use 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 } ;
31
31
use ty:: fast_reject;
32
32
use ty:: fold:: TypeFolder ;
33
- use ty:: subst:: { self , Subst } ;
33
+ use ty:: subst:: { self , ParamSpace , Subst } ;
34
34
use util:: nodemap:: { FnvHashMap , FnvHashSet } ;
35
35
36
36
use std:: cmp;
@@ -63,9 +63,9 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
63
63
}
64
64
65
65
fn 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 > {
69
69
let tcx = fcx. tcx ;
70
70
71
71
let ity = tcx. lookup_item_type ( did) ;
@@ -82,44 +82,109 @@ fn impl_substs<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
82
82
substs
83
83
}
84
84
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 ,
105
115
}
106
116
}
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
+ }
109
176
110
177
fn get_current_failing_impl < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
111
178
trait_ref : & TraitRef < ' tcx > ,
112
179
obligation : & PredicateObligation < ' tcx > )
113
180
-> Option < ( DefId , subst:: Substs < ' tcx > ) > {
114
- println ! ( "1" ) ;
115
181
let simp = fast_reject:: simplify_type ( infcx. tcx ,
116
182
trait_ref. self_ty ( ) ,
117
183
true ) ;
118
184
let trait_def = infcx. tcx . lookup_trait_def ( trait_ref. def_id ) ;
119
185
120
186
match simp {
121
187
Some ( _) => {
122
- println ! ( "2" ) ;
123
188
let mut matching_impls = Vec :: new ( ) ;
124
189
trait_def. for_each_impl ( infcx. tcx , |def_id| {
125
190
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>,
130
195
TypeOrigin :: Misc ( obligation. cause . span ) ,
131
196
trait_ref. self_ty ( ) ,
132
197
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 ( ) ) ) ;
136
199
}
137
- println ! ( "=> {:?} /// {:?}" , def_id, imp. substs) ;
138
200
} ) ;
139
201
if matching_impls. len ( ) == 0 {
140
- println ! ( "3" ) ;
141
202
None
142
203
} else if matching_impls. len ( ) == 1 {
143
- println ! ( "4" ) ;
144
204
Some ( matching_impls[ 0 ] . clone ( ) )
145
205
} else {
146
- println ! ( "5" ) ;
206
+ let end = trait_ref . input_types ( ) . len ( ) - 1 ;
147
207
// 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 ( ) )
152
211
}
153
212
} ,
154
213
None => None ,
@@ -171,7 +230,6 @@ fn on_unimplemented_note<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
171
230
trait_ref : ty:: PolyTraitRef < ' tcx > ,
172
231
obligation : & PredicateObligation < ' tcx > ) -> Option < String > {
173
232
let trait_ref = trait_ref. skip_binder ( ) ;
174
- //let def_id = trait_ref.def_id;
175
233
let mut report = None ;
176
234
let def_id = match get_current_failing_impl ( infcx, trait_ref, obligation) {
177
235
Some ( ( def_id, _) ) => {
@@ -603,8 +661,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
603
661
// Try to report a help message
604
662
605
663
if !trait_ref. has_infer_types ( ) &&
606
- predicate_can_apply ( infcx, trait_ref)
607
- {
664
+ predicate_can_apply ( infcx, trait_ref) {
608
665
// If a where-clause may be useful, remind the
609
666
// user that they can add it.
610
667
//
@@ -662,18 +719,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
662
719
// similar impls.
663
720
664
721
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) ;
665
728
}
666
729
err
667
730
}
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) ;
677
732
err. emit ( ) ;
678
733
}
679
734
0 commit comments