about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-01-10 12:29:05 +0000
committerbors <bors@rust-lang.org>2018-01-10 12:29:05 +0000
commitf62f774035735a06c880c48c0b9017fcc0577e33 (patch)
treef9951a684aed69cbec2e1f5876f25bba59789945
parent27ede55414e01f13c6869a8763da207e544cc6ad (diff)
parent6132806d361dce863a220e278c568f83b72a3c8a (diff)
downloadrust-f62f774035735a06c880c48c0b9017fcc0577e33.tar.gz
rust-f62f774035735a06c880c48c0b9017fcc0577e33.zip
Auto merge of #47167 - ivanbakel:builtin_indexing, r=nikomatsakis
Fix built-in indexing not being used where index type wasn't "obviously" usize

Fixes #33903
Fixes #46095

This PR was made possible thanks to the generous help of @eddyb

Following the example of binary operators, builtin checking for indexing has been moved from the typecheck stage to a writeback stage, after type constraints have been resolved.
-rw-r--r--src/librustc_typeck/check/mod.rs12
-rw-r--r--src/librustc_typeck/check/writeback.rs46
-rw-r--r--src/test/run-pass/issue-33903.rs19
-rw-r--r--src/test/run-pass/issue-46095.rs39
4 files changed, 104 insertions, 12 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 57598f99bd1..69236d77ed3 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..5e102c7a445 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -18,6 +18,7 @@ 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::adjustment::{Adjust, Adjustment};
 use rustc::ty::fold::{TypeFoldable, TypeFolder};
 use rustc::util::nodemap::DefIdSet;
 use syntax::ast;
@@ -159,8 +160,52 @@ 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 mut tables = self.fcx.tables.borrow_mut();
+
+            match tables.expr_ty_adjusted(&base).sty {
+                // All valid indexing looks like this
+                ty::TyRef(_, ty::TypeAndMut { ty: ref base_ty, .. }) => {
+                    let index_ty = tables.expr_ty_adjusted(&index);
+                    let index_ty = self.fcx.resolve_type_vars_if_possible(&index_ty);
+
+                    if base_ty.builtin_index().is_some()
+                        && index_ty == self.fcx.tcx.types.usize {
+                        // Remove the method call record
+                        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();
+                                },
+                                _ => {}
+                            }
+                        });
+                    }
+                },
+                // Might encounter non-valid indexes at this point, so there
+                // has to be a fall-through
+                _ => {},
+            }
+        }
+    }
 }
 
+
 ///////////////////////////////////////////////////////////////////////////
 // Impl of Visitor for Resolver
 //
@@ -176,6 +221,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);
 
diff --git a/src/test/run-pass/issue-33903.rs b/src/test/run-pass/issue-33903.rs
new file mode 100644
index 00000000000..ab368537e21
--- /dev/null
+++ b/src/test/run-pass/issue-33903.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue 33903:
+// Built-in indexing should be used even when the index is not
+// trivially an integer
+// Only built-in indexing can be used in constant expresssions
+
+const FOO: i32 = [12, 34][0 + 1];
+
+fn main() {}
+
diff --git a/src/test/run-pass/issue-46095.rs b/src/test/run-pass/issue-46095.rs
new file mode 100644
index 00000000000..35e51ebe70b
--- /dev/null
+++ b/src/test/run-pass/issue-46095.rs
@@ -0,0 +1,39 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct A;
+
+impl A {
+    fn take_mutably(&mut self) {}
+}
+
+fn identity<T>(t: T) -> T {
+    t
+}
+
+// Issue 46095
+// Built-in indexing should be used even when the index is not
+// trivially an integer
+// Overloaded indexing would cause wrapped to be borrowed mutably
+
+fn main() {
+    let mut a1 = A;
+    let mut a2 = A;
+
+    let wrapped = [&mut a1, &mut a2];
+
+    {
+        wrapped[0 + 1 - 1].take_mutably();
+    }
+
+    {
+        wrapped[identity(0)].take_mutably();
+    }
+}