about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/mod.rs12
-rw-r--r--src/librustc_typeck/check/writeback.rs84
2 files changed, 82 insertions, 14 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 6d68824980b..7d7aa80519d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2217,18 +2217,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                adjusted_ty,
                index_ty);
 
-        // First, try built-in indexing.
-        match (adjusted_ty.builtin_index(), &index_ty.sty) {
-            (Some(ty), &ty::TyUint(ast::UintTy::Usize)) |
-            (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
-                debug!("try_index_step: success, using built-in indexing");
-                let adjustments = autoderef.adjust_steps(lvalue_pref);
-                self.apply_adjustments(base_expr, adjustments);
-                return Some((self.tcx.types.usize, ty));
-            }
-            _ => {}
-        }
-
         for &unsize in &[false, true] {
             let mut self_ty = adjusted_ty;
             if unsize {
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 29dc983ab56..7f966cae249 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -12,12 +12,13 @@
 // unresolved type variables and replaces "ty_var" types with their
 // substitutions.
 
-use check::FnCtxt;
+use check::{FnCtxt, LvalueOp};
 use rustc::hir;
 use rustc::hir::def_id::{DefId, DefIndex};
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::infer::InferCtxt;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, LvaluePreference, Ty, TyCtxt};
+use rustc::ty::adjustment::{Adjust, Adjustment};
 use rustc::ty::fold::{TypeFoldable, TypeFolder};
 use rustc::util::nodemap::DefIdSet;
 use syntax::ast;
@@ -159,8 +160,86 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             _ => {}
         }
     }
+
+    // Similar to operators, indexing is always assumed to be overloaded
+    // Here, correct cases where an indexing expression can be simplified
+    // to use builtin indexing because the index type is known to be
+    // usize-ish
+    fn fix_index_builtin_expr(&mut self, e: &hir::Expr) {
+        if let hir::ExprIndex(ref base, ref index) = e.node {
+            let base_ty = self.fcx.node_ty(base.hir_id);
+            let base_ty = self.fcx.resolve_type_vars_if_possible(&base_ty);
+            let index_ty = self.fcx.node_ty(index.hir_id);
+            let index_ty = self.fcx.resolve_type_vars_if_possible(&index_ty);
+
+            if index_ty.is_uint() {
+                // HACK: the *actual* type being indexed is not stored anywhere
+                // so we try to find it again here by derefs
+                let mut autoderef = self.fcx.autoderef(e.span, base_ty);
+                let builtin_ty : Option<_> = {
+                    loop {
+                        // This is essentially a duplicate of the index discovery
+                        // logic in typechecking code
+                        // Find the first type dereffable to which has builtin 
+                        // indexing - this 
+                        if let Some(_) = autoderef.next() {
+                            let current_ty = autoderef.unambiguous_final_ty();
+
+                            if current_ty.builtin_index().is_some() {
+                                // If there is a builtin index, use it
+                                break Some(current_ty);
+                            } else {
+                                // If there's an overloaded index which happens
+                                // to take a uint, stop looking - otherwise we
+                                // might incorrectly deref further
+                                let overloaded_method = 
+                                    self.fcx.try_overloaded_lvalue_op(
+                                        e.span,
+                                        base_ty,
+                                        &[index_ty],
+                                        LvaluePreference::NoPreference,
+                                        LvalueOp::Index
+                                    );
+
+                                if overloaded_method.is_some() {
+                                    break None;
+                                }
+                            }
+                        } else {
+                            break None;
+                        }
+                    }
+                };
+
+                if builtin_ty.is_some() {
+                    let mut tables = self.fcx.tables.borrow_mut();
+                 
+                    // Remove the method call record, which blocks use in
+                    // constant or static cases
+                    tables.type_dependent_defs_mut().remove(e.hir_id);
+                    tables.node_substs_mut().remove(e.hir_id);
+
+                    tables.adjustments_mut().get_mut(base.hir_id).map(|a| {
+                        // Discard the need for a mutable borrow
+                        match a.pop() {
+                            // Extra adjustment made when indexing causes a drop
+                            // of size information - we need to get rid of it
+                            // Since this is "after" the other adjustment to be
+                            // discarded, we do an extra `pop()`
+                            Some(Adjustment { kind: Adjust::Unsize, .. }) => {
+                                // So the borrow discard actually happens here
+                                a.pop();
+                            },
+                            _ => {}
+                        }
+                    });
+                }
+            }
+        }
+    }
 }
 
+
 ///////////////////////////////////////////////////////////////////////////
 // Impl of Visitor for Resolver
 //
@@ -176,6 +255,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
 
     fn visit_expr(&mut self, e: &'gcx hir::Expr) {
         self.fix_scalar_builtin_expr(e);
+        self.fix_index_builtin_expr(e);
 
         self.visit_node_id(e.span, e.hir_id);