@@ -82,54 +82,76 @@ fn impl_substs<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
8282 substs
8383}
8484
85+ // Enum used to differentiate the "big" and "little" weights.
86+ enum Weight {
87+ Coarse ,
88+ Precise ,
89+ }
90+
8591trait AssociatedWeight {
86- fn get_weight ( & self ) -> usize ;
92+ fn get_weight ( & self ) -> ( u32 , u32 ) ;
8793}
8894
8995impl < ' 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 ) {
9298 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 ) ,
115129 }
116130 }
117131}
118132
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+ } ;
124139 if w1 < w2 {
125140 w2 - w1
126141 } else {
127142 w1 - w2
128143 }
129144}
130145
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 ) ] ,
133155 imps : & [ ( DefId , subst:: Substs < ' tcx > ) ] ,
134156 trait_types : & [ ty:: Ty < ' tcx > ] )
135157 -> usize {
@@ -144,14 +166,22 @@ fn filter_matching_types<'tcx>(weights: &[(usize, usize)],
144166 . get_slice ( ParamSpace :: TypeSpace )
145167 . iter ( )
146168 . 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 ) ;
148170 }
149171 filtered_weights. push ( ( pos, weight) ) ;
150172 }
151173 filtered_weights. sort_by ( |a, b| a. 1 . cmp ( & b. 1 ) ) ;
152174 filtered_weights[ 0 ] . 0
153175}
154176
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.
155185fn get_best_matching_type < ' tcx > ( imps : & [ ( DefId , subst:: Substs < ' tcx > ) ] ,
156186 trait_types : & [ ty:: Ty < ' tcx > ] ) -> usize {
157187 let mut weights = vec ! ( ) ;
@@ -162,7 +192,7 @@ fn get_best_matching_type<'tcx>(imps: &[(DefId, subst::Substs<'tcx>)],
162192 . get_slice ( ParamSpace :: TypeSpace )
163193 . iter ( )
164194 . 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 ) ;
166196 }
167197 weights. push ( ( pos, weight) ) ;
168198 }
0 commit comments