12
12
// unresolved type variables and replaces "ty_var" types with their
13
13
// substitutions.
14
14
15
- use check:: FnCtxt ;
15
+ use check:: { FnCtxt , LvalueOp } ;
16
16
use rustc:: hir;
17
17
use rustc:: hir:: def_id:: { DefId , DefIndex } ;
18
18
use rustc:: hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
19
19
use rustc:: infer:: InferCtxt ;
20
- use rustc:: ty:: { self , Ty , TyCtxt } ;
20
+ use rustc:: ty:: { self , LvaluePreference , Ty , TyCtxt } ;
21
+ use rustc:: ty:: adjustment:: { Adjust , Adjustment } ;
21
22
use rustc:: ty:: fold:: { TypeFoldable , TypeFolder } ;
22
23
use rustc:: util:: nodemap:: DefIdSet ;
23
24
use syntax:: ast;
@@ -159,8 +160,86 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
159
160
_ => { }
160
161
}
161
162
}
163
+
164
+ // Similar to operators, indexing is always assumed to be overloaded
165
+ // Here, correct cases where an indexing expression can be simplified
166
+ // to use builtin indexing because the index type is known to be
167
+ // usize-ish
168
+ fn fix_index_builtin_expr ( & mut self , e : & hir:: Expr ) {
169
+ if let hir:: ExprIndex ( ref base, ref index) = e. node {
170
+ let base_ty = self . fcx . node_ty ( base. hir_id ) ;
171
+ let base_ty = self . fcx . resolve_type_vars_if_possible ( & base_ty) ;
172
+ let index_ty = self . fcx . node_ty ( index. hir_id ) ;
173
+ let index_ty = self . fcx . resolve_type_vars_if_possible ( & index_ty) ;
174
+
175
+ if index_ty. is_uint ( ) {
176
+ // HACK: the *actual* type being indexed is not stored anywhere
177
+ // so we try to find it again here by derefs
178
+ let mut autoderef = self . fcx . autoderef ( e. span , base_ty) ;
179
+ let builtin_ty : Option < _ > = {
180
+ loop {
181
+ // This is essentially a duplicate of the index discovery
182
+ // logic in typechecking code
183
+ // Find the first type dereffable to which has builtin
184
+ // indexing - this
185
+ if let Some ( _) = autoderef. next ( ) {
186
+ let current_ty = autoderef. unambiguous_final_ty ( ) ;
187
+
188
+ if current_ty. builtin_index ( ) . is_some ( ) {
189
+ // If there is a builtin index, use it
190
+ break Some ( current_ty) ;
191
+ } else {
192
+ // If there's an overloaded index which happens
193
+ // to take a uint, stop looking - otherwise we
194
+ // might incorrectly deref further
195
+ let overloaded_method =
196
+ self . fcx . try_overloaded_lvalue_op (
197
+ e. span ,
198
+ base_ty,
199
+ & [ index_ty] ,
200
+ LvaluePreference :: NoPreference ,
201
+ LvalueOp :: Index
202
+ ) ;
203
+
204
+ if overloaded_method. is_some ( ) {
205
+ break None ;
206
+ }
207
+ }
208
+ } else {
209
+ break None ;
210
+ }
211
+ }
212
+ } ;
213
+
214
+ if builtin_ty. is_some ( ) {
215
+ let mut tables = self . fcx . tables . borrow_mut ( ) ;
216
+
217
+ // Remove the method call record, which blocks use in
218
+ // constant or static cases
219
+ tables. type_dependent_defs_mut ( ) . remove ( e. hir_id ) ;
220
+ tables. node_substs_mut ( ) . remove ( e. hir_id ) ;
221
+
222
+ tables. adjustments_mut ( ) . get_mut ( base. hir_id ) . map ( |a| {
223
+ // Discard the need for a mutable borrow
224
+ match a. pop ( ) {
225
+ // Extra adjustment made when indexing causes a drop
226
+ // of size information - we need to get rid of it
227
+ // Since this is "after" the other adjustment to be
228
+ // discarded, we do an extra `pop()`
229
+ Some ( Adjustment { kind : Adjust :: Unsize , .. } ) => {
230
+ // So the borrow discard actually happens here
231
+ a. pop ( ) ;
232
+ } ,
233
+ _ => { }
234
+ }
235
+ } ) ;
236
+ }
237
+ }
238
+ }
239
+ }
162
240
}
163
241
242
+
164
243
///////////////////////////////////////////////////////////////////////////
165
244
// Impl of Visitor for Resolver
166
245
//
@@ -176,6 +255,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
176
255
177
256
fn visit_expr ( & mut self , e : & ' gcx hir:: Expr ) {
178
257
self . fix_scalar_builtin_expr ( e) ;
258
+ self . fix_index_builtin_expr ( e) ;
179
259
180
260
self . visit_node_id ( e. span , e. hir_id ) ;
181
261
0 commit comments