@@ -82,54 +82,76 @@ fn impl_substs<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
82
82
substs
83
83
}
84
84
85
+ // Enum used to differentiate the "big" and "little" weights.
86
+ enum Weight {
87
+ Coarse ,
88
+ Precise ,
89
+ }
90
+
85
91
trait AssociatedWeight {
86
- fn get_weight ( & self ) -> usize ;
92
+ fn get_weight ( & self ) -> ( u32 , u32 ) ;
87
93
}
88
94
89
95
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 {
96
+ // Left number is for "global"/"big" weight and right number is for better precision.
97
+ fn get_weight ( & self ) -> ( u32 , u32 ) {
92
98
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 ,
99
+ TypeVariants :: TyBool => ( 1 , 1 ) ,
100
+ TypeVariants :: TyChar => ( 1 , 2 ) ,
101
+ TypeVariants :: TyStr => ( 1 , 3 ) ,
102
+
103
+ TypeVariants :: TyInt ( _) => ( 2 , 1 ) ,
104
+ TypeVariants :: TyUint ( _) => ( 2 , 2 ) ,
105
+ TypeVariants :: TyFloat ( _) => ( 2 , 3 ) ,
106
+ TypeVariants :: TyRawPtr ( _) => ( 2 , 4 ) ,
107
+
108
+ TypeVariants :: TyEnum ( _, _) => ( 3 , 1 ) ,
109
+ TypeVariants :: TyStruct ( _, _) => ( 3 , 2 ) ,
110
+ TypeVariants :: TyBox ( _) => ( 3 , 3 ) ,
111
+ TypeVariants :: TyTuple ( _) => ( 3 , 4 ) ,
112
+
113
+ TypeVariants :: TyArray ( _, _) => ( 4 , 1 ) ,
114
+ TypeVariants :: TySlice ( _) => ( 4 , 2 ) ,
115
+
116
+ TypeVariants :: TyRef ( _, _) => ( 5 , 1 ) ,
117
+ TypeVariants :: TyFnDef ( _, _, _) => ( 5 , 2 ) ,
118
+ TypeVariants :: TyFnPtr ( _) => ( 5 , 3 ) ,
119
+
120
+ TypeVariants :: TyTrait ( _) => ( 6 , 1 ) ,
121
+
122
+ TypeVariants :: TyClosure ( _, _) => ( 7 , 1 ) ,
123
+
124
+ TypeVariants :: TyProjection ( _) => ( 8 , 1 ) ,
125
+ TypeVariants :: TyParam ( _) => ( 8 , 2 ) ,
126
+ TypeVariants :: TyInfer ( _) => ( 8 , 3 ) ,
127
+
128
+ TypeVariants :: TyError => ( 9 , 1 ) ,
115
129
}
116
130
}
117
131
}
118
132
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
-
133
+ // The "closer" the types are, the lesser the weight.
134
+ fn get_weight_diff ( a : & ty:: TypeVariants , b : & TypeVariants , weight : Weight ) -> u32 {
135
+ let ( w1, w2) = match weight {
136
+ Weight :: Coarse => ( a. get_weight ( ) . 0 , b. get_weight ( ) . 0 ) ,
137
+ Weight :: Precise => ( a. get_weight ( ) . 1 , b. get_weight ( ) . 1 ) ,
138
+ } ;
124
139
if w1 < w2 {
125
140
w2 - w1
126
141
} else {
127
142
w1 - w2
128
143
}
129
144
}
130
145
131
- // Once we have "globally matching" types, we need to run another filter on them
132
- fn filter_matching_types < ' tcx > ( weights : & [ ( usize , usize ) ] ,
146
+ // Once we have "globally matching" types, we need to run another filter on them.
147
+ //
148
+ // In the function `get_best_matching_type`, we got the types which might fit the
149
+ // most to the type we're looking for. This second filter now intends to get (if
150
+ // possible) the type which fits the most.
151
+ //
152
+ // For example, the trait expects an `usize` and here you have `u32` and `i32`.
153
+ // Obviously, the "correct" one is `u32`.
154
+ fn filter_matching_types < ' tcx > ( weights : & [ ( usize , u32 ) ] ,
133
155
imps : & [ ( DefId , subst:: Substs < ' tcx > ) ] ,
134
156
trait_types : & [ ty:: Ty < ' tcx > ] )
135
157
-> usize {
@@ -144,14 +166,22 @@ fn filter_matching_types<'tcx>(weights: &[(usize, usize)],
144
166
. get_slice ( ParamSpace :: TypeSpace )
145
167
. iter ( )
146
168
. zip ( trait_types. iter ( ) ) {
147
- weight += get_weight_diff ( & type_to_compare. sty , & original_type. sty , false ) ;
169
+ weight += get_weight_diff ( & type_to_compare. sty , & original_type. sty , Weight :: Precise ) ;
148
170
}
149
171
filtered_weights. push ( ( pos, weight) ) ;
150
172
}
151
173
filtered_weights. sort_by ( |a, b| a. 1 . cmp ( & b. 1 ) ) ;
152
174
filtered_weights[ 0 ] . 0
153
175
}
154
176
177
+ // Here, we run the "big" filter. Little example:
178
+ //
179
+ // We receive a `String`, an `u32` and an `i32`.
180
+ // The trait expected an `usize`.
181
+ // From human point of view, it's easy to determine that `String` doesn't correspond to
182
+ // the expected type at all whereas `u32` and `i32` could.
183
+ //
184
+ // This first filter intends to only keep the types which match the most.
155
185
fn get_best_matching_type < ' tcx > ( imps : & [ ( DefId , subst:: Substs < ' tcx > ) ] ,
156
186
trait_types : & [ ty:: Ty < ' tcx > ] ) -> usize {
157
187
let mut weights = vec ! ( ) ;
@@ -162,7 +192,7 @@ fn get_best_matching_type<'tcx>(imps: &[(DefId, subst::Substs<'tcx>)],
162
192
. get_slice ( ParamSpace :: TypeSpace )
163
193
. iter ( )
164
194
. zip ( trait_types. iter ( ) ) {
165
- weight += get_weight_diff ( & type_to_compare. sty , & original_type. sty , true ) ;
195
+ weight += get_weight_diff ( & type_to_compare. sty , & original_type. sty , Weight :: Coarse ) ;
166
196
}
167
197
weights. push ( ( pos, weight) ) ;
168
198
}
0 commit comments