about summary refs log tree commit diff
diff options
context:
space:
mode:
authorIsaac van Bakel <ivb@vanbakel.io>2018-01-01 22:47:50 +0000
committerIsaac van Bakel <ivb@vanbakel.io>2018-01-07 01:30:20 +0000
commit23bc6418e844cbb9170ecf37f87df20742fcf7a2 (patch)
tree342df4d0cf76446e92a22befbeadc436bcef3d0a
parent6828cf90146c7fefc4ba4f16dffe75f763f2d910 (diff)
Moved builtin indexing checks to writeback stage
Use of builtin indexing is now only checked after types are fully
resolved.
Types are not correctly checked in case of autoderefs.
-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);