1
Fork 0

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.
This commit is contained in:
Isaac van Bakel 2018-01-01 22:47:50 +00:00
parent 6828cf9014
commit 23bc6418e8
2 changed files with 82 additions and 14 deletions

View file

@ -2217,18 +2217,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
adjusted_ty, adjusted_ty,
index_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] { for &unsize in &[false, true] {
let mut self_ty = adjusted_ty; let mut self_ty = adjusted_ty;
if unsize { if unsize {

View file

@ -12,12 +12,13 @@
// unresolved type variables and replaces "ty_var" types with their // unresolved type variables and replaces "ty_var" types with their
// substitutions. // substitutions.
use check::FnCtxt; use check::{FnCtxt, LvalueOp};
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::{DefId, DefIndex}; use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::infer::InferCtxt; 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::ty::fold::{TypeFoldable, TypeFolder};
use rustc::util::nodemap::DefIdSet; use rustc::util::nodemap::DefIdSet;
use syntax::ast; 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 // 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) { fn visit_expr(&mut self, e: &'gcx hir::Expr) {
self.fix_scalar_builtin_expr(e); self.fix_scalar_builtin_expr(e);
self.fix_index_builtin_expr(e);
self.visit_node_id(e.span, e.hir_id); self.visit_node_id(e.span, e.hir_id);