Skip to content

Commit 23bc641

Browse files
committed
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.
1 parent 6828cf9 commit 23bc641

File tree

2 files changed

+82
-14
lines changed

2 files changed

+82
-14
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,18 +2217,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
22172217
adjusted_ty,
22182218
index_ty);
22192219

2220-
// First, try built-in indexing.
2221-
match (adjusted_ty.builtin_index(), &index_ty.sty) {
2222-
(Some(ty), &ty::TyUint(ast::UintTy::Usize)) |
2223-
(Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
2224-
debug!("try_index_step: success, using built-in indexing");
2225-
let adjustments = autoderef.adjust_steps(lvalue_pref);
2226-
self.apply_adjustments(base_expr, adjustments);
2227-
return Some((self.tcx.types.usize, ty));
2228-
}
2229-
_ => {}
2230-
}
2231-
22322220
for &unsize in &[false, true] {
22332221
let mut self_ty = adjusted_ty;
22342222
if unsize {

src/librustc_typeck/check/writeback.rs

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
// unresolved type variables and replaces "ty_var" types with their
1313
// substitutions.
1414

15-
use check::FnCtxt;
15+
use check::{FnCtxt, LvalueOp};
1616
use rustc::hir;
1717
use rustc::hir::def_id::{DefId, DefIndex};
1818
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
1919
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};
2122
use rustc::ty::fold::{TypeFoldable, TypeFolder};
2223
use rustc::util::nodemap::DefIdSet;
2324
use syntax::ast;
@@ -159,8 +160,86 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
159160
_ => {}
160161
}
161162
}
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+
}
162240
}
163241

242+
164243
///////////////////////////////////////////////////////////////////////////
165244
// Impl of Visitor for Resolver
166245
//
@@ -176,6 +255,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
176255

177256
fn visit_expr(&mut self, e: &'gcx hir::Expr) {
178257
self.fix_scalar_builtin_expr(e);
258+
self.fix_index_builtin_expr(e);
179259

180260
self.visit_node_id(e.span, e.hir_id);
181261

0 commit comments

Comments
 (0)