use rustc::hir;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::infer::{InferCtxt};
-use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
+use rustc::ty::{self, Ty, TyCtxt, MethodCallee};
use rustc::ty::adjustment;
use rustc::ty::fold::{TypeFolder,TypeFoldable};
-use rustc::util::nodemap::{DefIdMap, DefIdSet};
+use rustc::util::nodemap::DefIdSet;
use syntax::ast;
use syntax_pos::Span;
use std::mem;
tables: ty::TypeckTables<'gcx>,
- // Mapping from free regions of the function to the
- // early-bound versions of them, visible from the
- // outside of the function. This is needed by, and
- // only populated if there are any `impl Trait`.
- free_to_bound_regions: DefIdMap<ty::Region<'gcx>>,
-
body: &'gcx hir::Body,
}
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, body: &'gcx hir::Body)
-> WritebackCx<'cx, 'gcx, 'tcx> {
- let mut wbcx = WritebackCx {
+ WritebackCx {
fcx: fcx,
tables: ty::TypeckTables::empty(),
- free_to_bound_regions: DefIdMap(),
body: body
- };
-
- // Only build the reverse mapping if `impl Trait` is used.
- if fcx.anon_types.borrow().is_empty() {
- return wbcx;
- }
-
- let gcx = fcx.tcx.global_tcx();
- let free_substs = fcx.parameter_environment.free_substs;
- for (i, k) in free_substs.iter().enumerate() {
- let r = if let Some(r) = k.as_region() {
- r
- } else {
- continue;
- };
- match *r {
- ty::ReFree(ty::FreeRegion {
- bound_region: ty::BoundRegion::BrNamed(def_id, name), ..
- }) => {
- let bound_region = gcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
- index: i as u32,
- name: name,
- }));
- wbcx.free_to_bound_regions.insert(def_id, bound_region);
- }
- _ => {
- bug!("{:?} is not a free region for an early-bound lifetime", r);
- }
- }
}
-
- wbcx
}
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty);
if inner_ty.is_scalar() {
- self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
+ self.fcx.tables.borrow_mut().method_map.remove(&e.id);
}
}
hir::ExprBinary(ref op, ref lhs, ref rhs) |
let rhs_ty = self.fcx.resolve_type_vars_if_possible(&rhs_ty);
if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
- self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
+ self.fcx.tables.borrow_mut().method_map.remove(&e.id);
// weird but true: the by-ref binops put an
// adjustment on the lhs but not the rhs; the
self.fix_scalar_builtin_expr(e);
self.visit_node_id(e.span, e.id);
- self.visit_method_map_entry(e.span, MethodCall::expr(e.id));
+ self.visit_method_map_entry(e.span, e.id);
if let hir::ExprClosure(_, _, body, _) = e.node {
let body = self.fcx.tcx.hir.body(body);
let inside_ty = self.resolve(&concrete_ty, &node_id);
// Convert the type from the function into a type valid outside
- // the function, by replacing free regions with early-bound ones.
+ // the function, by replacing invalid regions with 'static,
+ // after producing an error for each of them.
let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
match *r {
- // 'static is valid everywhere.
- ty::ReStatic => gcx.types.re_static,
- ty::ReEmpty => gcx.types.re_empty,
-
- // Free regions that come from early-bound regions are valid.
- ty::ReFree(ty::FreeRegion {
- bound_region: ty::BoundRegion::BrNamed(def_id, ..), ..
- }) if self.free_to_bound_regions.contains_key(&def_id) => {
- self.free_to_bound_regions[&def_id]
- }
+ // 'static and early-bound regions are valid.
+ ty::ReStatic |
+ ty::ReEarlyBound(_) |
+ ty::ReEmpty => r,
ty::ReFree(_) |
- ty::ReEarlyBound(_) |
ty::ReLateBound(..) |
ty::ReScope(_) |
ty::ReSkolemized(..) => {
debug!("Node {} has type {:?}", node_id, n_ty);
// Resolve any substitutions
- self.fcx.opt_node_ty_substs(node_id, |item_substs| {
- let item_substs = self.resolve(item_substs, &span);
- if !item_substs.is_noop() {
- debug!("write_substs_to_tcx({}, {:?})", node_id, item_substs);
- assert!(!item_substs.substs.needs_infer());
- self.tables.item_substs.insert(node_id, item_substs);
- }
- });
+ if let Some(&substs) = self.fcx.tables.borrow().node_substs.get(&node_id) {
+ let substs = self.resolve(&substs, &span);
+ debug!("write_substs_to_tcx({}, {:?})", node_id, substs);
+ assert!(!substs.needs_infer());
+ self.tables.node_substs.insert(node_id, substs);
+ }
}
fn visit_adjustments(&mut self, span: Span, node_id: ast::NodeId) {
}
adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => {
- for autoderef in 0..autoderefs {
- let method_call = MethodCall::autoderef(node_id, autoderef as u32);
- self.visit_method_map_entry(span, method_call);
- }
-
adjustment::Adjust::DerefRef {
- autoderefs: autoderefs,
+ autoderefs: autoderefs.iter().map(|overloaded| {
+ overloaded.map(|method| {
+ MethodCallee {
+ def_id: method.def_id,
+ substs: self.resolve(&method.substs, &span),
+ sig: self.resolve(&method.sig, &span),
+ }
+ })
+ }).collect(),
autoref: self.resolve(&autoref, &span),
unsize: unsize,
}
fn visit_method_map_entry(&mut self,
method_span: Span,
- method_call: MethodCall) {
+ node_id: ast::NodeId) {
// Resolve any method map entry
- let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&method_call) {
+ let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&node_id) {
Some(method) => {
- debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
- method_call,
- method);
- let new_method = MethodCallee {
+ Some(MethodCallee {
def_id: method.def_id,
- ty: self.resolve(&method.ty, &method_span),
substs: self.resolve(&method.substs, &method_span),
- };
-
- Some(new_method)
+ sig: self.resolve(&method.sig, &method_span),
+ })
}
None => None
};
//NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE
if let Some(method) = new_method {
- self.tables.method_map.insert(method_call, method);
+ self.tables.method_map.insert(node_id, method);
}
}