From: Taylor Cramer Date: Mon, 10 Apr 2017 07:00:08 +0000 (-0700) Subject: introduce per-fn RegionMaps X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=73cd9bde373cc134aa2ebb6a8064d532621ca0a6;p=rust.git introduce per-fn RegionMaps Instead of requesting the region maps for the entire crate, request for a given item etc. Several bits of code were modified to take `&RegionMaps` as input (e.g., the `resolve_regions_and_report_errors()` function). I am not totally happy with this setup -- I *think* I'd rather have the region maps be part of typeck tables -- but at least the `RegionMaps` works in a "parallel" way to `FreeRegionMap`, so it's not too bad. Given that I expect a lot of this code to go away with NLL, I didn't want to invest *too* much energy tweaking it. --- diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 7b7c204a0ee..a8ad49c6582 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -15,9 +15,11 @@ use syntax::ptr::P; use hir::{self, PatKind}; +use hir::def_id::DefId; struct CFGBuilder<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, + owner_def_id: DefId, tables: &'a ty::TypeckTables<'tcx>, graph: CFGGraph, fn_exit: CFGIndex, @@ -56,6 +58,7 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut cfg_builder = CFGBuilder { tcx: tcx, + owner_def_id, tables: tables, graph: graph, fn_exit: fn_exit, @@ -585,9 +588,10 @@ fn add_exiting_edge(&mut self, let mut data = CFGEdgeData { exiting_scopes: vec![] }; let mut scope = self.tcx.node_extent(from_expr.id); let target_scope = self.tcx.node_extent(scope_id); + let region_maps = self.tcx.region_maps(self.owner_def_id); while scope != target_scope { data.exiting_scopes.push(scope.node_id()); - scope = self.tcx.region_maps().encl_scope(scope); + scope = region_maps.encl_scope(scope); } self.graph.add_edge(from_index, to_index, data); } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index d05ede07c3f..63a4e6196a2 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -56,7 +56,7 @@ pub enum DepNode { WorkProduct(Arc), // Represents different phases in the compiler. - RegionResolveCrate, + RegionMaps(D), Coherence, Resolve, CoherenceCheckTrait(D), @@ -197,7 +197,6 @@ pub fn map_def(&self, mut op: OP) -> Option> BorrowCheckKrate => Some(BorrowCheckKrate), MirKrate => Some(MirKrate), TypeckBodiesKrate => Some(TypeckBodiesKrate), - RegionResolveCrate => Some(RegionResolveCrate), Coherence => Some(Coherence), Resolve => Some(Resolve), Variance => Some(Variance), @@ -223,6 +222,7 @@ pub fn map_def(&self, mut op: OP) -> Option> def_ids.map(MirShim) } BorrowCheck(ref d) => op(d).map(BorrowCheck), + RegionMaps(ref d) => op(d).map(RegionMaps), RvalueCheck(ref d) => op(d).map(RvalueCheck), TransCrateItem(ref d) => op(d).map(TransCrateItem), TransInlinedItem(ref d) => op(d).map(TransInlinedItem), diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2b0d53b2bc3..3e610dd3c0d 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -39,7 +39,7 @@ use syntax_pos::Span; use hir::*; use hir::def::Def; -use hir::map::Map; +use hir::map::{self, Map}; use super::itemlikevisit::DeepVisitor; use std::cmp; @@ -140,6 +140,23 @@ pub fn inter(self) -> Option<&'this Map<'tcx>> { /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) pub trait Visitor<'v> : Sized { + /// Invokes the suitable visitor method for the given `Node` + /// extracted from the hir map. + fn visit_hir_map_node(&mut self, node: map::Node<'v>) { + match node { + map::NodeItem(a) => self.visit_item(a), + map::NodeForeignItem(a) => self.visit_foreign_item(a), + map::NodeTraitItem(a) => self.visit_trait_item(a), + map::NodeImplItem(a) => self.visit_impl_item(a), + map::NodeExpr(a) => self.visit_expr(a), + map::NodeStmt(a) => self.visit_stmt(a), + map::NodeTy(a) => self.visit_ty(a), + map::NodePat(a) => self.visit_pat(a), + map::NodeBlock(a) => self.visit_block(a), + _ => bug!("Visitor::visit_hir_map_node() not yet impl for node `{:?}`", node) + } + } + /////////////////////////////////////////////////////////////////////////// // Nested items. diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 48b8a819fff..cae5c5011ce 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -572,6 +572,18 @@ pub fn is_argument(&self, id: NodeId) -> bool { } } + /// Check if the node is a non-closure function item + pub fn is_fn(&self, id: NodeId) -> bool { + let entry = if let Some(id) = self.find_entry(id) { id } else { return false }; + + match entry { + EntryItem(_, &Item { node: ItemFn(..), .. }) | + EntryTraitItem(_, &TraitItem { node: TraitItemKind::Method(..), .. }) | + EntryImplItem(_, &ImplItem { node: ImplItemKind::Method(..), .. }) => true, + _ => false, + } + } + /// If there is some error when walking the parents (e.g., a node does not /// have a parent in the map or a node can't be found), then we return the /// last good node id we found. Note that reaching the crate root (id == 0), diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a0451c5fe0b..e91af21c6db 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -20,7 +20,8 @@ use hir::def_id::DefId; use hir; -use middle::free_region::FreeRegionMap; +use middle::free_region::{FreeRegionMap, RegionRelations}; +use middle::region::RegionMaps; use middle::mem_categorization as mc; use middle::mem_categorization::McResult; use middle::lang_items; @@ -1322,9 +1323,14 @@ pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> { } pub fn resolve_regions_and_report_errors(&self, - free_regions: &FreeRegionMap<'tcx>, - subject_node_id: ast::NodeId) { - let errors = self.region_vars.resolve_regions(free_regions, subject_node_id); + region_context: DefId, + region_map: &RegionMaps<'tcx>, + free_regions: &FreeRegionMap<'tcx>) { + let region_rels = RegionRelations::new(self.tcx, + region_context, + region_map, + free_regions); + let errors = self.region_vars.resolve_regions(®ion_rels); if !self.is_tainted_by_errors() { // As a heuristic, just skip reporting region errors // altogether if other errors have been reported while diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index 7de81e14d77..c48b8f610a2 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -18,7 +18,9 @@ /// For clarity, rename the graphviz crate locally to dot. use graphviz as dot; -use ty::{self, TyCtxt}; +use hir::def_id::DefIndex; +use ty; +use middle::free_region::RegionRelations; use middle::region::CodeExtent; use super::Constraint; use infer::SubregionOrigin; @@ -32,7 +34,6 @@ use std::io; use std::io::prelude::*; use std::sync::atomic::{AtomicBool, Ordering}; -use syntax::ast; fn print_help_message() { println!("\ @@ -55,18 +56,18 @@ fn print_help_message() { pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( region_vars: &RegionVarBindings<'a, 'gcx, 'tcx>, - subject_node: ast::NodeId) + region_rels: &RegionRelations<'a, 'gcx, 'tcx>) { - let tcx = region_vars.tcx; + let context = region_rels.context; if !region_vars.tcx.sess.opts.debugging_opts.print_region_graph { return; } let requested_node = env::var("RUST_REGION_GRAPH_NODE") - .ok().and_then(|s| s.parse().map(ast::NodeId::new).ok()); + .ok().and_then(|s| s.parse().map(DefIndex::new).ok()); - if requested_node.is_some() && requested_node != Some(subject_node) { + if requested_node.is_some() && requested_node != Some(context.index) { return; } @@ -98,7 +99,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( let mut new_str = String::new(); for c in output_template.chars() { if c == '%' { - new_str.push_str(&subject_node.to_string()); + new_str.push_str(&context.index.as_usize().to_string()); } else { new_str.push(c); } @@ -110,7 +111,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( }; let constraints = &*region_vars.constraints.borrow(); - match dump_region_constraints_to(tcx, constraints, &output_path) { + match dump_region_constraints_to(region_rels, constraints, &output_path) { Ok(()) => {} Err(e) => { let msg = format!("io error dumping region constraints: {}", e); @@ -120,8 +121,8 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( } struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, graph_name: String, + region_rels: &'a RegionRelations<'a, 'gcx, 'tcx>, map: &'a FxHashMap, SubregionOrigin<'tcx>>, node_ids: FxHashMap, usize>, } @@ -140,8 +141,8 @@ enum Edge<'tcx> { } impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> { - fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - name: String, + fn new(name: String, + region_rels: &'a RegionRelations<'a, 'gcx, 'tcx>, map: &'a ConstraintMap<'tcx>) -> ConstraintGraph<'a, 'gcx, 'tcx> { let mut i = 0; @@ -159,17 +160,17 @@ fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, add_node(n2); } - tcx.region_maps().each_encl_scope(|sub, sup| { + region_rels.region_maps.each_encl_scope(|sub, sup| { add_node(Node::Region(ty::ReScope(sub))); add_node(Node::Region(ty::ReScope(sup))); }); } ConstraintGraph { - tcx: tcx, + map, + node_ids, + region_rels, graph_name: name, - map: map, - node_ids: node_ids, } } } @@ -245,7 +246,7 @@ fn nodes(&self) -> dot::Nodes> { fn edges(&self) -> dot::Edges> { debug!("constraint graph has {} edges", self.map.len()); let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect(); - self.tcx.region_maps().each_encl_scope(|sub, sup| v.push(Edge::EnclScope(sub, sup))); + self.region_rels.region_maps.each_encl_scope(|sub, sup| v.push(Edge::EnclScope(sub, sup))); debug!("region graph has {} edges", v.len()); Cow::Owned(v) } @@ -263,14 +264,14 @@ fn target(&self, edge: &Edge<'tcx>) -> Node<'tcx> { pub type ConstraintMap<'tcx> = FxHashMap, SubregionOrigin<'tcx>>; -fn dump_region_constraints_to<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, +fn dump_region_constraints_to<'a, 'gcx, 'tcx>(region_rels: &RegionRelations<'a, 'gcx, 'tcx>, map: &ConstraintMap<'tcx>, path: &str) -> io::Result<()> { debug!("dump_region_constraints map (len: {}) path: {}", map.len(), path); - let g = ConstraintGraph::new(tcx, format!("region_constraints"), map); + let g = ConstraintGraph::new(format!("region_constraints"), region_rels, map); debug!("dump_region_constraints calling render"); let mut v = Vec::new(); dot::render(&g, &mut v).unwrap(); diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 33754b738a0..fb699bbd2d2 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -22,7 +22,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING}; use rustc_data_structures::unify::{self, UnificationTable}; -use middle::free_region::FreeRegionMap; +use middle::free_region::RegionRelations; use ty::{self, Ty, TyCtxt}; use ty::{Region, RegionVid}; use ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound, ReErased}; @@ -33,7 +33,6 @@ use std::fmt; use std::mem; use std::u32; -use syntax::ast; mod graphviz; @@ -892,18 +891,17 @@ pub fn tainted(&self, /// constraints, assuming such values can be found; if they cannot, /// errors are reported. pub fn resolve_regions(&self, - free_regions: &FreeRegionMap<'tcx>, - subject_node: ast::NodeId) + region_rels: &RegionRelations<'a, 'gcx, 'tcx>) -> Vec> { debug!("RegionVarBindings: resolve_regions()"); let mut errors = vec![]; - let v = self.infer_variable_values(free_regions, &mut errors, subject_node); + let v = self.infer_variable_values(region_rels, &mut errors); *self.values.borrow_mut() = Some(v); errors } fn lub_concrete_regions(&self, - free_regions: &FreeRegionMap<'tcx>, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { @@ -939,7 +937,7 @@ fn lub_concrete_regions(&self, // at least as big as the block fr.scope_id". So, we can // reasonably compare free regions and scopes: if let Some(fr_scope) = fr.scope { - let r_id = self.tcx.region_maps().nearest_common_ancestor(fr_scope, s_id); + let r_id = region_rels.region_maps.nearest_common_ancestor(fr_scope, s_id); if r_id == fr_scope { // if the free region's scope `fr.scope_id` is bigger than // the scope region `s_id`, then the LUB is the free @@ -957,12 +955,12 @@ fn lub_concrete_regions(&self, // The region corresponding to an outer block is a // subtype of the region corresponding to an inner // block. - self.tcx.mk_region(ReScope( - self.tcx.region_maps().nearest_common_ancestor(a_id, b_id))) + let lub = region_rels.region_maps.nearest_common_ancestor(a_id, b_id); + self.tcx.mk_region(ReScope(lub)) } (&ReFree(_), &ReFree(_)) => { - free_regions.lub_free_regions(self.tcx, a, b) + region_rels.lub_free_regions(a, b) } // For these types, we cannot define any additional @@ -996,24 +994,23 @@ struct RegionAndOrigin<'tcx> { impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { fn infer_variable_values(&self, - free_regions: &FreeRegionMap<'tcx>, - errors: &mut Vec>, - subject: ast::NodeId) + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, + errors: &mut Vec>) -> Vec> { let mut var_data = self.construct_var_data(); // Dorky hack to cause `dump_constraints` to only get called // if debug mode is enabled: - debug!("----() End constraint listing (subject={}) {:?}---", - subject, - self.dump_constraints(subject)); - graphviz::maybe_print_constraints_for(self, subject); + debug!("----() End constraint listing (context={:?}) {:?}---", + region_rels.context, + self.dump_constraints(region_rels)); + graphviz::maybe_print_constraints_for(self, region_rels); let graph = self.construct_graph(); self.expand_givens(&graph); - self.expansion(free_regions, &mut var_data); - self.collect_errors(free_regions, &mut var_data, errors); - self.collect_var_errors(free_regions, &var_data, &graph, errors); + self.expansion(region_rels, &mut var_data); + self.collect_errors(region_rels, &mut var_data, errors); + self.collect_var_errors(region_rels, &var_data, &graph, errors); var_data } @@ -1023,9 +1020,9 @@ fn construct_var_data(&self) -> Vec> { .collect() } - fn dump_constraints(&self, subject: ast::NodeId) { - debug!("----() Start constraint listing (subject={}) ()----", - subject); + fn dump_constraints(&self, free_regions: &RegionRelations<'a, 'gcx, 'tcx>) { + debug!("----() Start constraint listing (context={:?}) ()----", + free_regions.context); for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() { debug!("Constraint {} => {:?}", idx, constraint); } @@ -1056,21 +1053,21 @@ fn expand_givens(&self, graph: &RegionGraph) { } } - fn expansion(&self, free_regions: &FreeRegionMap<'tcx>, var_values: &mut [VarValue<'tcx>]) { + fn expansion(&self, region_rels: &RegionRelations<'a, 'gcx, 'tcx>, var_values: &mut [VarValue<'tcx>]) { self.iterate_until_fixed_point("Expansion", |constraint, origin| { debug!("expansion: constraint={:?} origin={:?}", constraint, origin); match *constraint { ConstrainRegSubVar(a_region, b_vid) => { let b_data = &mut var_values[b_vid.index as usize]; - self.expand_node(free_regions, a_region, b_vid, b_data) + self.expand_node(region_rels, a_region, b_vid, b_data) } ConstrainVarSubVar(a_vid, b_vid) => { match var_values[a_vid.index as usize] { ErrorValue => false, Value(a_region) => { let b_node = &mut var_values[b_vid.index as usize]; - self.expand_node(free_regions, a_region, b_vid, b_node) + self.expand_node(region_rels, a_region, b_vid, b_node) } } } @@ -1085,7 +1082,7 @@ fn expansion(&self, free_regions: &FreeRegionMap<'tcx>, var_values: &mut [VarVal } fn expand_node(&self, - free_regions: &FreeRegionMap<'tcx>, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, a_region: Region<'tcx>, b_vid: RegionVid, b_data: &mut VarValue<'tcx>) @@ -1108,7 +1105,7 @@ fn expand_node(&self, match *b_data { Value(cur_region) => { - let lub = self.lub_concrete_regions(free_regions, a_region, cur_region); + let lub = self.lub_concrete_regions(region_rels, a_region, cur_region); if lub == cur_region { return false; } @@ -1132,7 +1129,7 @@ fn expand_node(&self, /// cases where the region cannot grow larger than a fixed point) /// and check that they are satisfied. fn collect_errors(&self, - free_regions: &FreeRegionMap<'tcx>, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, var_data: &mut Vec>, errors: &mut Vec>) { let constraints = self.constraints.borrow(); @@ -1146,7 +1143,7 @@ fn collect_errors(&self, } ConstrainRegSubReg(sub, sup) => { - if free_regions.is_subregion_of(self.tcx, sub, sup) { + if region_rels.is_subregion_of(sub, sup) { continue; } @@ -1174,7 +1171,7 @@ fn collect_errors(&self, // Do not report these errors immediately: // instead, set the variable value to error and // collect them later. - if !free_regions.is_subregion_of(self.tcx, a_region, b_region) { + if !region_rels.is_subregion_of(a_region, b_region) { debug!("collect_errors: region error at {:?}: \ cannot verify that {:?}={:?} <= {:?}", origin, @@ -1190,7 +1187,7 @@ fn collect_errors(&self, for verify in self.verifys.borrow().iter() { debug!("collect_errors: verify={:?}", verify); let sub = normalize(self.tcx, var_data, verify.region); - if verify.bound.is_met(self.tcx, free_regions, var_data, sub) { + if verify.bound.is_met(region_rels, var_data, sub) { continue; } @@ -1209,7 +1206,7 @@ fn collect_errors(&self, /// Go over the variables that were declared to be error variables /// and create a `RegionResolutionError` for each of them. fn collect_var_errors(&self, - free_regions: &FreeRegionMap<'tcx>, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, var_data: &[VarValue<'tcx>], graph: &RegionGraph<'tcx>, errors: &mut Vec>) { @@ -1258,7 +1255,7 @@ fn collect_var_errors(&self, this portion of the code and think hard about it. =) */ let node_vid = RegionVid { index: idx as u32 }; - self.collect_error_for_expanding_node(free_regions, + self.collect_error_for_expanding_node(region_rels, graph, &mut dup_vec, node_vid, @@ -1311,7 +1308,7 @@ fn construct_graph(&self) -> RegionGraph<'tcx> { } fn collect_error_for_expanding_node(&self, - free_regions: &FreeRegionMap<'tcx>, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, graph: &RegionGraph<'tcx>, dup_vec: &mut [u32], node_idx: RegionVid, @@ -1347,7 +1344,7 @@ fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering { for lower_bound in &lower_bounds { for upper_bound in &upper_bounds { - if !free_regions.is_subregion_of(self.tcx, lower_bound.region, upper_bound.region) { + if !region_rels.is_subregion_of(lower_bound.region, upper_bound.region) { let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone(); debug!("region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \ sup: {:?}", @@ -1591,29 +1588,30 @@ pub fn and(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> { } } - fn is_met(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - free_regions: &FreeRegionMap<'tcx>, + fn is_met(&self, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, var_values: &Vec>, min: ty::Region<'tcx>) -> bool { + let tcx = region_rels.tcx; match self { &VerifyBound::AnyRegion(ref rs) => rs.iter() .map(|&r| normalize(tcx, var_values, r)) - .any(|r| free_regions.is_subregion_of(tcx, min, r)), + .any(|r| region_rels.is_subregion_of(min, r)), &VerifyBound::AllRegions(ref rs) => rs.iter() .map(|&r| normalize(tcx, var_values, r)) - .all(|r| free_regions.is_subregion_of(tcx, min, r)), + .all(|r| region_rels.is_subregion_of(min, r)), &VerifyBound::AnyBound(ref bs) => bs.iter() - .any(|b| b.is_met(tcx, free_regions, var_values, min)), + .any(|b| b.is_met(region_rels, var_values, min)), &VerifyBound::AllBounds(ref bs) => bs.iter() - .all(|b| b.is_met(tcx, free_regions, var_values, min)), + .all(|b| b.is_met(region_rels, var_values, min)), } } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 9be05313439..a49f3d3b7a7 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -270,19 +270,24 @@ enum PassArgs { impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), + context: DefId, infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self { - ExprUseVisitor::with_options(delegate, infcx, mc::MemCategorizationOptions::default()) + ExprUseVisitor::with_options(delegate, + infcx, + context, + mc::MemCategorizationOptions::default()) } pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a), infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + context: DefId, options: mc::MemCategorizationOptions) -> Self { ExprUseVisitor { - mc: mc::MemCategorizationContext::with_options(infcx, options), + mc: mc::MemCategorizationContext::with_options(infcx, context, options), delegate: delegate } } diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 1dc633c6d00..2dc7aac04ae 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -15,10 +15,108 @@ //! `TransitiveRelation` type and use that to decide when one free //! region outlives another and so forth. +use hir::def_id::DefId; +use middle::region::RegionMaps; use ty::{self, Lift, TyCtxt, Region}; use ty::wf::ImpliedBound; use rustc_data_structures::transitive_relation::TransitiveRelation; +/// Combines a `RegionMaps` (which governs relationships between +/// scopes) and a `FreeRegionMap` (which governs relationships between +/// free regions) to yield a complete relation between concrete +/// regions. +/// +/// This stuff is a bit convoluted and should be refactored, but as we +/// move to NLL it'll all go away anyhow. +pub struct RegionRelations<'a, 'gcx: 'tcx, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'gcx, 'tcx>, + + /// context used to fetch the region maps + pub context: DefId, + + /// region maps for the given context + pub region_maps: &'a RegionMaps<'tcx>, + + /// free-region relationships + pub free_regions: &'a FreeRegionMap<'tcx>, +} + +impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> { + pub fn new( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + context: DefId, + region_maps: &'a RegionMaps<'tcx>, + free_regions: &'a FreeRegionMap<'tcx>, + ) -> Self { + Self { + tcx, + context, + region_maps, + free_regions, + } + } + + /// Determines whether one region is a subregion of another. This is intended to run *after + /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs. + pub fn is_subregion_of(&self, + sub_region: ty::Region<'tcx>, + super_region: ty::Region<'tcx>) + -> bool { + let result = sub_region == super_region || { + match (sub_region, super_region) { + (&ty::ReEmpty, _) | + (_, &ty::ReStatic) => + true, + + (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) => + self.region_maps.is_subscope_of(sub_scope, super_scope), + + (&ty::ReScope(sub_scope), &ty::ReFree(fr)) => { + // 1. It is safe to unwrap `fr.scope` because we + // should only ever wind up comparing against + // `ReScope` in the context of a method or + // body, where `fr.scope` should be `Some`. + self.region_maps.is_subscope_of(sub_scope, fr.scope.unwrap() /*1*/) || + self.is_static(super_region) + } + + (&ty::ReFree(_), &ty::ReFree(_)) => + self.free_regions.relation.contains(&sub_region, &super_region) || + self.is_static(super_region), + + (&ty::ReStatic, &ty::ReFree(_)) => + self.is_static(super_region), + + _ => + false, + } + }; + debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}", + sub_region, super_region, result); + result + } + + /// Determines whether this free-region is required to be 'static + fn is_static(&self, super_region: ty::Region<'tcx>) -> bool { + debug!("is_static(super_region={:?})", super_region); + match *super_region { + ty::ReStatic => true, + ty::ReFree(_) => { + let re_static = self.tcx.mk_region(ty::ReStatic); + self.free_regions.relation.contains(&re_static, &super_region) + } + _ => bug!("only free regions should be given to `is_static`") + } + } + + pub fn lub_free_regions(&self, + r_a: Region<'tcx>, + r_b: Region<'tcx>) + -> Region<'tcx> { + self.free_regions.lub_free_regions(self.tcx, r_a, r_b) + } +} + #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct FreeRegionMap<'tcx> { // Stores the relation `a < b`, where `a` and `b` are regions. @@ -116,61 +214,6 @@ pub fn lub_free_regions<'a, 'gcx>(&self, debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result); result } - - /// Determines whether one region is a subregion of another. This is intended to run *after - /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs. - pub fn is_subregion_of<'a, 'gcx>(&self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - sub_region: ty::Region<'tcx>, - super_region: ty::Region<'tcx>) - -> bool { - let result = sub_region == super_region || { - match (sub_region, super_region) { - (&ty::ReEmpty, _) | - (_, &ty::ReStatic) => - true, - - (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) => - tcx.region_maps().is_subscope_of(sub_scope, super_scope), - - (&ty::ReScope(sub_scope), &ty::ReFree(fr)) => { - // 1. It is safe to unwrap `fr.scope` because we - // should only ever wind up comparing against - // `ReScope` in the context of a method or - // body, where `fr.scope` should be `Some`. - tcx.region_maps().is_subscope_of(sub_scope, fr.scope.unwrap() /*1*/) || - self.is_static(tcx, super_region) - } - - (&ty::ReFree(_), &ty::ReFree(_)) => - self.relation.contains(&sub_region, &super_region) || - self.is_static(tcx, super_region), - - (&ty::ReStatic, &ty::ReFree(_)) => - self.is_static(tcx, super_region), - - _ => - false, - } - }; - debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}", - sub_region, super_region, result); - result - } - - /// Determines whether this free-region is required to be 'static - fn is_static<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, super_region: ty::Region<'tcx>) - -> bool { - debug!("is_static(super_region={:?})", super_region); - match *super_region { - ty::ReStatic => true, - ty::ReFree(_) => { - let re_static = tcx.mk_region(ty::ReStatic); - self.relation.contains(&re_static, &super_region) - } - _ => bug!("only free regions should be given to `is_static`") - } - } } impl_stable_hash_for!(struct FreeRegionMap<'tcx> { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3b1a9552ece..0e2db746e45 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -70,6 +70,7 @@ use self::Aliasability::*; +use middle::region::RegionMaps; use hir::def_id::DefId; use hir::map as hir_map; use infer::InferCtxt; @@ -286,9 +287,10 @@ fn id(&self) -> ast::NodeId { self.id } fn span(&self) -> Span { self.span } } -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + pub region_maps: Rc>, options: MemCategorizationOptions, } @@ -402,16 +404,21 @@ pub fn to_user_str(&self) -> &'static str { } impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) + /// Context should be the `DefId` we use to fetch region-maps. + pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + context: DefId) -> MemCategorizationContext<'a, 'gcx, 'tcx> { - MemCategorizationContext::with_options(infcx, MemCategorizationOptions::default()) + MemCategorizationContext::with_options(infcx, context, MemCategorizationOptions::default()) } pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + context: DefId, options: MemCategorizationOptions) -> MemCategorizationContext<'a, 'gcx, 'tcx> { + let region_maps = infcx.tcx.region_maps(context); MemCategorizationContext { infcx: infcx, + region_maps: region_maps, options: options, } } @@ -786,7 +793,7 @@ fn env_deref(&self, }; match fn_expr.node { - hir::ExprClosure(.., body_id, _) => body_id.node_id, + hir::ExprClosure(.., body_id, _) => body_id, _ => bug!() } }; @@ -796,7 +803,7 @@ fn env_deref(&self, // The environment of a closure is guaranteed to // outlive any bindings introduced in the body of the // closure itself. - scope: Some(self.tcx().item_extent(fn_body_id)), + scope: Some(self.tcx().item_extent(fn_body_id.node_id)), bound_region: ty::BrEnv })); @@ -845,7 +852,7 @@ fn env_deref(&self, pub fn temporary_scope(&self, id: ast::NodeId) -> (ty::Region<'tcx>, ty::Region<'tcx>) { let (scope, old_scope) = - self.tcx().region_maps().old_and_new_temporary_scope(self.tcx(), id); + self.region_maps.old_and_new_temporary_scope(self.tcx(), id); (self.tcx().mk_region(match scope { Some(scope) => ty::ReScope(scope), None => ty::ReStatic diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 062432e27e5..fb0c3a29def 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -29,8 +29,7 @@ use ty::TyCtxt; use ty::maps::Providers; -use hir; -use hir::def_id::{CrateNum, LOCAL_CRATE}; +use hir; use hir::def_id::DefId; use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; use hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local}; @@ -226,6 +225,9 @@ pub struct RegionMaps<'tcx> { /// which that variable is declared. var_map: NodeMap>, + /// maps from a node-id to the associated destruction scope (if any) + destruction_scopes: NodeMap>, + /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is /// larger than the default. The map goes from the expression id /// to the cleanup scope id. For rvalues not present in this @@ -301,11 +303,22 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> { /// arbitrary amounts of stack space. Terminating scopes end /// up being contained in a DestructionScope that contains the /// destructor's execution. - terminating_scopes: NodeSet + terminating_scopes: NodeSet, } impl<'tcx> RegionMaps<'tcx> { + pub fn new() -> Self { + RegionMaps { + scope_map: FxHashMap(), + destruction_scopes: FxHashMap(), + var_map: NodeMap(), + rvalue_scopes: NodeMap(), + shrunk_rvalue_scopes: NodeMap(), + fn_tree: NodeMap(), + } + } + pub fn each_encl_scope(&self, mut e:E) where E: FnMut(CodeExtent<'tcx>, CodeExtent<'tcx>) { for (&child, &parent) in &self.scope_map { e(child, parent) @@ -317,6 +330,10 @@ pub fn each_var_scope(&self, mut e:E) where E: FnMut(&ast::NodeId, CodeExtent } } + pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option> { + self.destruction_scopes.get(&n).cloned() + } + /// Records that `sub_fn` is defined within `sup_fn`. These ids /// should be the id of the block that is the fn body, which is /// also the root of the region hierarchy for that fn. @@ -1029,18 +1046,18 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, body_id: hir::BodyId, sp: Span, id: ast::NodeId) { + visitor.cx.parent = Some(visitor.new_code_extent( + CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id })); + debug!("region::resolve_fn(id={:?}, \ - span={:?}, \ - body.id={:?}, \ - cx.parent={:?})", + span={:?}, \ + body.id={:?}, \ + cx.parent={:?})", id, visitor.tcx.sess.codemap().span_to_string(sp), body_id, visitor.cx.parent); - visitor.cx.parent = Some(visitor.new_code_extent( - CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id })); - let fn_decl_scope = visitor.new_code_extent( CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id }); @@ -1086,6 +1103,12 @@ pub fn intern_code_extent(&mut self, let prev = self.region_maps.scope_map.insert(code_extent, p); assert!(prev.is_none()); } + + // record the destruction scopes for later so we can query them + if let &CodeExtentData::DestructionScope(n) = code_extent { + self.region_maps.destruction_scopes.insert(n, code_extent); + } + code_extent } @@ -1162,47 +1185,44 @@ fn visit_local(&mut self, l: &'tcx Local) { } } -pub fn resolve_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc> { - tcx.region_resolve_crate(LOCAL_CRATE) -} - -fn region_resolve_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) +fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_id: DefId) -> Rc> { - debug_assert!(crate_num == LOCAL_CRATE); - - let hir_map = &tcx.hir; + let fn_node_id = tcx.hir.as_local_node_id(fn_id) + .expect("fn DefId should be for LOCAL_CRATE"); + let node = tcx.hir.get(fn_node_id); + match node { + hir_map::NodeItem(_) | hir_map::NodeTraitItem(_) | hir_map::NodeImplItem(_) => { } + _ => { + let parent_id = tcx.hir.get_parent(fn_node_id); + let parent_def_id = tcx.hir.local_def_id(parent_id); + return tcx.region_maps(parent_def_id); + } + } - let krate = hir_map.krate(); - - let mut maps = RegionMaps { - scope_map: FxHashMap(), - var_map: NodeMap(), - rvalue_scopes: NodeMap(), - shrunk_rvalue_scopes: NodeMap(), - fn_tree: NodeMap(), - }; + let mut maps = RegionMaps::new(); { let mut visitor = RegionResolutionVisitor { tcx: tcx, region_maps: &mut maps, - map: hir_map, + map: &tcx.hir, cx: Context { root_id: None, parent: None, var_parent: None, }, - terminating_scopes: NodeSet() + terminating_scopes: NodeSet(), }; - krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); + visitor.visit_hir_map_node(node); } + Rc::new(maps) } pub fn provide(providers: &mut Providers) { *providers = Providers { - region_resolve_crate, + region_maps, ..*providers }; } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 5ac79a8e72a..4f7cb2b12a7 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -17,6 +17,7 @@ use hir; use hir::def_id::DefId; +use middle::region::RegionMaps; use middle::free_region::FreeRegionMap; use ty::subst::Substs; use ty::{self, Ty, TyCtxt, TypeFoldable, ToPredicate}; @@ -435,9 +436,10 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx // FIXME: this is gonna need to be removed ... /// Normalizes the parameter environment, reporting errors if they occur. pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - unnormalized_env: ty::ParameterEnvironment<'tcx>, - cause: ObligationCause<'tcx>) - -> ty::ParameterEnvironment<'tcx> + region_context: DefId, + unnormalized_env: ty::ParameterEnvironment<'tcx>, + cause: ObligationCause<'tcx>) + -> ty::ParameterEnvironment<'tcx> { // I'm not wild about reporting errors here; I'd prefer to // have the errors get reported at a defined place (e.g., @@ -455,7 +457,6 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // can be sure that no errors should occur. let span = cause.span; - let body_id = cause.body_id; debug!("normalize_param_env_or_error(unnormalized_env={:?})", unnormalized_env); @@ -492,8 +493,9 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_param_env_or_error: normalized predicates={:?}", predicates); + let region_maps = RegionMaps::new(); let free_regions = FreeRegionMap::new(); - infcx.resolve_regions_and_report_errors(&free_regions, body_id); + infcx.resolve_regions_and_report_errors(region_context, ®ion_maps, &free_regions); let predicates = match infcx.fully_resolve(&predicates) { Ok(predicates) => predicates, Err(fixup_err) => { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3c6f833c4ef..73b76736b24 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -21,7 +21,7 @@ use hir::map::DisambiguatedDefPathData; use middle::free_region::FreeRegionMap; use middle::lang_items; -use middle::region::{CodeExtent, CodeExtentData, RegionMaps}; +use middle::region::{CodeExtent, CodeExtentData}; use middle::resolve_lifetime; use middle::stability; use mir::Mir; @@ -52,7 +52,6 @@ use std::ops::Deref; use std::iter; use std::cmp::Ordering; -use std::rc::Rc; use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; @@ -656,12 +655,6 @@ pub fn node_extent(self, n: ast::NodeId) -> CodeExtent<'gcx> { self.intern_code_extent(CodeExtentData::Misc(n)) } - // TODO this is revealing side-effects of query, bad - pub fn opt_destruction_extent(self, n: ast::NodeId) -> Option> { - let s = CodeExtentData::DestructionScope(n); - self.code_extent_interner.borrow().get(&s).cloned() - } - // Returns the code extent for an item - the destruction scope. pub fn item_extent(self, n: ast::NodeId) -> CodeExtent<'gcx> { self.intern_code_extent(CodeExtentData::DestructionScope(n)) @@ -712,10 +705,6 @@ fn is_global(self) -> bool { local as usize == global as usize } - pub fn region_maps(self) -> Rc> { - self.region_resolve_crate(LOCAL_CRATE) - } - /// Create a type context and call the closure with a `TyCtxt` reference /// to the context. The closure enforces that the type context and any interned /// value (types, substs, etc.) can only be used while `ty::tls` has a valid diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 4a780b9178e..b8edfbf60f2 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -292,12 +292,6 @@ fn describe(_: TyCtxt, _: DefId) -> String { } } -impl<'tcx> QueryDescription for queries::region_resolve_crate<'tcx> { - fn describe(_: TyCtxt, _: CrateNum) -> String { - format!("resolve crate") - } -} - macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -578,7 +572,10 @@ fn default() -> Self { [] reachable_set: reachability_dep_node(CrateNum) -> Rc, - [] region_resolve_crate: region_resolve_crate_dep_node(CrateNum) -> Rc>, + /// Per-function `RegionMaps`. The `DefId` should be the owner-def-id for the fn body; + /// in the case of closures or "inline" expressions, this will be redirected to the enclosing + /// fn item. + [] region_maps: RegionMaps(DefId) -> Rc>, [] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell>, @@ -601,10 +598,6 @@ fn reachability_dep_node(_: CrateNum) -> DepNode { DepNode::Reachability } -fn region_resolve_crate_dep_node(_: CrateNum) -> DepNode { - DepNode::RegionResolveCrate -} - fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode { instance.dep_node() } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e6a8459e001..07aa627e596 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2526,7 +2526,7 @@ pub fn construct_parameter_environment(self, let body_id = free_id_outlive.map(|f| f.node_id()) .unwrap_or(DUMMY_NODE_ID); let cause = traits::ObligationCause::misc(span, body_id); - traits::normalize_param_env_or_error(tcx, unnormalized_env, cause) + traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) } pub fn node_scope_region(self, id: NodeId) -> Region<'tcx> { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 96753d63af2..6e43943bc17 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -199,7 +199,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, all_loans: all_loans, param_env: &infcx.parameter_environment }; - euv::ExprUseVisitor::new(&mut clcx, &infcx).consume_body(body); + euv::ExprUseVisitor::new(&mut clcx, bccx.owner_def_id, &infcx).consume_body(body); } #[derive(PartialEq)] @@ -238,9 +238,8 @@ pub fn each_in_scope_loan(&self, scope: region::CodeExtent<'tcx>, mut op: F) //! Like `each_issued_loan()`, but only considers loans that are //! currently in scope. - let tcx = self.tcx(); self.each_issued_loan(scope.node_id(), |loan| { - if tcx.region_maps().is_subscope_of(scope, loan.kill_scope) { + if self.bccx.region_maps.is_subscope_of(scope, loan.kill_scope) { op(loan) } else { true @@ -379,8 +378,8 @@ pub fn report_error_if_loans_conflict(&self, new_loan); // Should only be called for loans that are in scope at the same time. - assert!(self.tcx().region_maps().scopes_intersect(old_loan.kill_scope, - new_loan.kill_scope)); + assert!(self.bccx.region_maps.scopes_intersect(old_loan.kill_scope, + new_loan.kill_scope)); self.report_error_if_loan_conflicts_with_restriction( old_loan, new_loan, old_loan, new_loan) && diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 9f8ffd86f54..12854d3c979 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -116,7 +116,7 @@ fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> { } Categorization::Local(local_id) => { self.bccx.tcx.mk_region(ty::ReScope( - self.bccx.tcx.region_maps().var_scope(local_id))) + self.bccx.region_maps.var_scope(local_id))) } Categorization::StaticItem | Categorization::Deref(.., mc::UnsafePtr(..)) => { diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 09ed515939d..9a5d1008c40 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -51,7 +51,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, }; let body = glcx.bccx.tcx.hir.body(body); - euv::ExprUseVisitor::new(&mut glcx, &infcx).consume_body(body); + euv::ExprUseVisitor::new(&mut glcx, bccx.owner_def_id, &infcx).consume_body(body); glcx.report_potential_errors(); let GatherLoanCtxt { all_loans, move_data, .. } = glcx; @@ -458,7 +458,7 @@ pub fn compute_gen_scope(&self, //! notably method arguments, the loan may be introduced only //! later, once it comes into scope. - if self.bccx.tcx.region_maps().is_subscope_of(borrow_scope, loan_scope) { + if self.bccx.region_maps.is_subscope_of(borrow_scope, loan_scope) { borrow_scope } else { loan_scope @@ -488,12 +488,11 @@ pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent<'tcx>, lp: &Loan //! with immutable `&` pointers, because borrows of such pointers //! do not require restrictions and hence do not cause a loan. - let lexical_scope = lp.kill_scope(self.bccx.tcx); - let rm = &self.bccx.tcx.region_maps(); - if rm.is_subscope_of(lexical_scope, loan_scope) { + let lexical_scope = lp.kill_scope(self.bccx); + if self.bccx.region_maps.is_subscope_of(lexical_scope, loan_scope) { lexical_scope } else { - assert!(self.bccx.tcx.region_maps().is_subscope_of(loan_scope, lexical_scope)); + assert!(self.bccx.region_maps.is_subscope_of(loan_scope, lexical_scope)); loan_scope } } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 1a7c700e239..e5e5045bc29 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -34,7 +34,8 @@ use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::mem_categorization::ImmutabilityBlame; -use rustc::middle::region; +use rustc::middle::region::{self, RegionMaps}; +use rustc::middle::free_region::RegionRelations; use rustc::ty::{self, TyCtxt}; use rustc::ty::maps::Providers; @@ -88,11 +89,8 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { let body_id = tcx.hir.body_owned_by(owner_id); let attributes = tcx.get_attrs(owner_def_id); let tables = tcx.typeck_tables_of(owner_def_id); - - let mut bccx = &mut BorrowckCtxt { - tcx: tcx, - tables: tables, - }; + let region_maps = tcx.region_maps(owner_def_id); + let mut bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id }; let body = bccx.tcx.hir.body(body_id); @@ -149,7 +147,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, loan_dfcx.propagate(cfg, body); let flowed_moves = move_data::FlowedMoveData::new(move_data, - this.tcx, + this, cfg, id_range, body); @@ -170,11 +168,8 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( let owner_id = tcx.hir.body_owner(body_id); let owner_def_id = tcx.hir.local_def_id(owner_id); let tables = tcx.typeck_tables_of(owner_def_id); - - let mut bccx = BorrowckCtxt { - tcx: tcx, - tables: tables, - }; + let region_maps = tcx.region_maps(owner_def_id); + let mut bccx = BorrowckCtxt { tcx, tables, region_maps, owner_def_id }; let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id); (bccx, dataflow_data) @@ -189,6 +184,10 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { // tables for the current thing we are checking; set to // Some in `borrowck_fn` and cleared later tables: &'a ty::TypeckTables<'tcx>, + + region_maps: Rc>, + + owner_def_id: DefId, } /////////////////////////////////////////////////////////////////////////// @@ -312,15 +311,15 @@ pub fn closure_to_block(closure_id: ast::NodeId, } impl<'a, 'tcx> LoanPath<'tcx> { - pub fn kill_scope(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> region::CodeExtent<'tcx> { + pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::CodeExtent<'tcx> { match self.kind { - LpVar(local_id) => tcx.region_maps().var_scope(local_id), + LpVar(local_id) => bccx.region_maps.var_scope(local_id), LpUpvar(upvar_id) => { - let block_id = closure_to_block(upvar_id.closure_expr_id, tcx); - tcx.node_extent(block_id) + let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx); + bccx.tcx.node_extent(block_id) } LpDowncast(ref base, _) | - LpExtend(ref base, ..) => base.kill_scope(tcx), + LpExtend(ref base, ..) => base.kill_scope(bccx), } } @@ -479,7 +478,11 @@ pub fn is_subregion_of(&self, r_sup: ty::Region<'tcx>) -> bool { - self.tables.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup) + let region_rels = RegionRelations::new(self.tcx, + self.owner_def_id, + &self.region_maps, + &self.tables.free_region_map); + region_rels.is_subregion_of(r_sub, r_sup) } pub fn report(&self, err: BckError<'tcx>) { diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 3d7df7f0372..3e23086ec7b 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -523,7 +523,8 @@ fn fixup_fragment_sets(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { /// Moves are generated by moves and killed by assignments and /// scoping. Assignments are generated by assignment to variables and /// killed by scoping. See `README.md` for more details. - fn add_gen_kills(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn add_gen_kills(&self, + bccx: &BorrowckCtxt<'a, 'tcx>, dfcx_moves: &mut MoveDataFlow, dfcx_assign: &mut AssignDataFlow) { for (i, the_move) in self.moves.borrow().iter().enumerate() { @@ -546,7 +547,7 @@ fn add_gen_kills(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, for path in self.paths.borrow().iter() { match path.loan_path.kind { LpVar(..) | LpUpvar(..) | LpDowncast(..) => { - let kill_scope = path.loan_path.kill_scope(tcx); + let kill_scope = path.loan_path.kill_scope(bccx); let path = *self.path_map.borrow().get(&path.loan_path).unwrap(); self.kill_moves(path, kill_scope.node_id(), KillFrom::ScopeEnd, dfcx_moves); @@ -561,7 +562,7 @@ fn add_gen_kills(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, let lp = self.path_loan_path(assignment.path); match lp.kind { LpVar(..) | LpUpvar(..) | LpDowncast(..) => { - let kill_scope = lp.kill_scope(tcx); + let kill_scope = lp.kill_scope(bccx); dfcx_assign.add_kill(KillFrom::ScopeEnd, kill_scope.node_id(), assignment_index); @@ -652,11 +653,13 @@ fn kill_moves(&self, impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { pub fn new(move_data: MoveData<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, + bccx: &BorrowckCtxt<'a, 'tcx>, cfg: &cfg::CFG, id_range: IdRange, body: &hir::Body) -> FlowedMoveData<'a, 'tcx> { + let tcx = bccx.tcx; + let mut dfcx_moves = DataFlowContext::new(tcx, "flowed_move_data_moves", @@ -676,7 +679,7 @@ pub fn new(move_data: MoveData<'tcx>, move_data.fixup_fragment_sets(tcx); - move_data.add_gen_kills(tcx, + move_data.add_gen_kills(bccx, &mut dfcx_moves, &mut dfcx_assign); diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 5a2fc9adc2f..106b5a26d95 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -14,6 +14,7 @@ use pattern::{Pattern, PatternContext, PatternError, PatternKind}; +use rustc::hir::def_id::DefId; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; use rustc::middle::expr_use_visitor as euv; @@ -45,9 +46,12 @@ fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl, b: hir::BodyId, s: Span, id: ast::NodeId) { intravisit::walk_fn(self, fk, fd, b, s, id); + let region_context = self.tcx.hir.local_def_id(id); + MatchVisitor { tcx: self.tcx, tables: self.tcx.body_tables(b), + region_context: region_context, param_env: &ty::ParameterEnvironment::for_item(self.tcx, id) }.visit_body(self.tcx.hir.body(b)); } @@ -64,6 +68,7 @@ fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> Diagn struct MatchVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, + region_context: DefId, tables: &'a ty::TypeckTables<'tcx>, param_env: &'a ty::ParameterEnvironment<'tcx> } @@ -517,7 +522,7 @@ fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) { let mut checker = MutationChecker { cx: cx, }; - ExprUseVisitor::new(&mut checker, &infcx).walk_expr(guard); + ExprUseVisitor::new(&mut checker, cx.region_context, &infcx).walk_expr(guard); }); } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bb3bda68277..aa33d4b5539 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -924,10 +924,6 @@ macro_rules! try_with_f { "load_dep_graph", || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map)); - time(time_passes, - "region resolution", - || middle::region::resolve_crate(tcx)); - time(time_passes, "stability index", || { tcx.stability.borrow_mut().build(tcx) }); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 38f98548571..1036b96d7f5 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -155,7 +155,8 @@ fn test_env(source_string: &str, body(Env { infcx: &infcx }); let free_regions = FreeRegionMap::new(); - infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID); + let def_id = tcx.hir.map.local_def_id(ast::CRATE_NODE_ID); + infcx.resolve_regions_and_report_errors(def_id, ®ion_map, &free_regions); assert_eq!(tcx.sess.err_count(), expected_err_count); }); }); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 7c12c9ef5fa..2505e2f8211 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -202,7 +202,7 @@ pub fn storage_live_binding(&mut self, block: BasicBlock, var: NodeId, span: Spa pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span) { let local_id = self.var_indices[&var]; let var_ty = self.local_decls[local_id].ty; - let extent = self.hir.tcx().region_maps().var_scope(var); + let extent = self.hir.region_maps.var_scope(var); self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty); } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 6c01e4315f3..b8f1b754b48 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -134,7 +134,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let tcx = hir.tcx(); let span = tcx.hir.span(fn_id); - let mut builder = Builder::new(hir, span, arguments.len(), return_ty); + let mut builder = Builder::new(hir.clone(), span, arguments.len(), return_ty); let call_site_extent = tcx.intern_code_extent( @@ -202,11 +202,10 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, let ty = hir.tables().expr_ty_adjusted(ast_expr); let owner_id = tcx.hir.body_owner(body_id); let span = tcx.hir.span(owner_id); - let mut builder = Builder::new(hir, span, 0, ty); + let mut builder = Builder::new(hir.clone(), span, 0, ty); - let region_maps = tcx.region_maps(); - let extent = region_maps.temporary_scope(tcx, ast_expr.id) - .unwrap_or(tcx.item_extent(owner_id)); + let extent = hir.region_maps.temporary_scope(tcx, ast_expr.id) + .unwrap_or(tcx.item_extent(owner_id)); let mut block = START_BLOCK; let _ = builder.in_scope(extent, block, |builder| { let expr = builder.hir.mirror(ast_expr); diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 15c2df55cf3..2ec4a8a07df 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -84,7 +84,7 @@ pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, block: &'tcx hir::Block) -> ExprRef<'tcx> { let block_ty = cx.tables().node_id_to_type(block.id); - let (temp_lifetime, was_shrunk) = cx.tcx.region_maps().temporary_scope2(cx.tcx, block.id); + let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, block.id); let expr = Expr { ty: block_ty, temp_lifetime: temp_lifetime, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index e37df8822c8..6a1817aba09 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -26,7 +26,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { type Output = Expr<'tcx>; fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> { - let (temp_lifetime, was_shrunk) = cx.tcx.region_maps().temporary_scope2(cx.tcx, self.id); + let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, self.id); let expr_extent = cx.tcx.node_extent(self.id); debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); @@ -216,7 +216,7 @@ fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> { }; // Finally, create a destruction scope, if any. - if let Some(extent) = cx.tcx.opt_destruction_extent(self.id) { + if let Some(extent) = cx.region_maps.opt_destruction_extent(self.id) { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -238,7 +238,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr) -> Expr<'tcx> { let expr_ty = cx.tables().expr_ty(expr); - let (temp_lifetime, was_shrunk) = cx.tcx.region_maps().temporary_scope2(cx.tcx, expr.id); + let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id); let kind = match expr.node { // Here comes the interesting stuff: @@ -707,7 +707,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, method_call: ty::MethodCall) -> Expr<'tcx> { let callee = cx.tables().method_map[&method_call]; - let (temp_lifetime, was_shrunk) = cx.tcx.region_maps().temporary_scope2(cx.tcx, expr.id); + let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id); Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -791,7 +791,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, def: Def) -> ExprKind<'tcx> { - let (temp_lifetime, was_shrunk) = cx.tcx.region_maps().temporary_scope2(cx.tcx, expr.id); + let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id); match def { Def::Local(def_id) => { @@ -979,7 +979,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, PassArgs::ByRef => { let region = cx.tcx.node_scope_region(expr.id); let (temp_lifetime, was_shrunk) = - cx.tcx.region_maps().temporary_scope2(cx.tcx, expr.id); + cx.region_maps.temporary_scope2(cx.tcx, expr.id); argrefs.extend(args.iter() .map(|arg| { let arg_ty = cx.tables().expr_ty_adjusted(arg); @@ -1031,7 +1031,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type - let (temp_lifetime, was_shrunk) = cx.tcx.region_maps().temporary_scope2(cx.tcx, expr.id); + let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id); let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args); let ref_expr = Expr { temp_lifetime: temp_lifetime, @@ -1056,7 +1056,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, closure_expr_id: closure_expr.id, }; let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap(); - let (temp_lifetime, was_shrunk) = cx.tcx.region_maps().temporary_scope2(cx.tcx, closure_expr.id); + let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, closure_expr.id); let var_ty = cx.tables().node_id_to_type(id_var); let captured_var = Expr { temp_lifetime: temp_lifetime, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index e73eaafc4b9..3e9bcb3e186 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -22,17 +22,20 @@ use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::DefId; use rustc::hir::map::blocks::FnLikeNode; +use rustc::middle::region::RegionMaps; use rustc::infer::InferCtxt; use rustc::ty::subst::Subst; use rustc::ty::{self, Ty, TyCtxt}; use syntax::symbol::{Symbol, InternedString}; use rustc::hir; use rustc_const_math::{ConstInt, ConstUsize}; +use std::rc::Rc; -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + pub region_maps: Rc>, constness: hir::Constness, /// True if this constant/function needs overflow checks. @@ -51,7 +54,13 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, src: MirSource) -> Cx<'a, 'gcx, MirSource::Promoted(..) => bug!(), }; - let attrs = infcx.tcx.hir.attrs(src.item_id()); + let tcx = infcx.tcx; + let src_id = src.item_id(); + let src_def_id = tcx.hir.local_def_id(src_id); + + let region_maps = tcx.region_maps(src_def_id); + + let attrs = tcx.hir.attrs(src_id); // Some functions always have overflow checks enabled, // however, they may not get codegen'd, depending on @@ -60,17 +69,12 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, src: MirSource) -> Cx<'a, 'gcx, .any(|item| item.check_name("rustc_inherit_overflow_checks")); // Respect -C overflow-checks. - check_overflow |= infcx.tcx.sess.overflow_checks(); + check_overflow |= tcx.sess.overflow_checks(); // Constants and const fn's always need overflow checks. check_overflow |= constness == hir::Constness::Const; - Cx { - tcx: infcx.tcx, - infcx: infcx, - constness: constness, - check_overflow: check_overflow, - } + Cx { tcx, infcx, region_maps, constness, check_overflow } } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index cb0625ceccf..cd2d9165c6a 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -130,7 +130,8 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) { }; let outer_tables = self.tables; - self.tables = self.tcx.typeck_tables_of(self.tcx.hir.local_def_id(item_id)); + let item_def_id = self.tcx.hir.local_def_id(item_id); + self.tables = self.tcx.typeck_tables_of(item_def_id); let body = self.tcx.hir.body(body_id); if !self.in_fn { @@ -140,7 +141,7 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) { let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { let param_env = infcx.parameter_environment.clone(); let outer_penv = mem::replace(&mut self.param_env, param_env); - euv::ExprUseVisitor::new(self, &infcx).consume_body(body); + euv::ExprUseVisitor::new(self, item_def_id, &infcx).consume_body(body); outer_penv }); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2e84aff4985..80330afaad8 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -11,13 +11,13 @@ use rustc::hir::{self, ImplItemKind, TraitItemKind}; use rustc::infer::{self, InferOk}; use rustc::middle::free_region::FreeRegionMap; +use rustc::middle::region::RegionMaps; use rustc::ty::{self, TyCtxt}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{Subst, Substs}; use rustc::util::common::ErrorReported; -use syntax::ast; use syntax_pos::Span; use super::{Inherited, FnCtxt}; @@ -30,14 +30,12 @@ /// /// - impl_m: type of the method we are checking /// - impl_m_span: span to use for reporting errors -/// - impl_m_body_id: id of the method body /// - trait_m: the method in the trait /// - impl_trait_ref: the TraitRef corresponding to the trait implementation pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_m: &ty::AssociatedItem, impl_m_span: Span, - impl_m_body_id: ast::NodeId, trait_m: &ty::AssociatedItem, impl_trait_ref: ty::TraitRef<'tcx>, trait_item_span: Option, @@ -72,7 +70,6 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Err(ErrorReported) = compare_predicate_entailment(tcx, impl_m, impl_m_span, - impl_m_body_id, trait_m, impl_trait_ref, old_broken_mode) { @@ -83,21 +80,25 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_m: &ty::AssociatedItem, impl_m_span: Span, - impl_m_body_id: ast::NodeId, trait_m: &ty::AssociatedItem, impl_trait_ref: ty::TraitRef<'tcx>, old_broken_mode: bool) -> Result<(), ErrorReported> { let trait_to_impl_substs = impl_trait_ref.substs; + // This node-id should be used for the `body_id` field on each + // `ObligationCause` (and the `FnCtxt`). This is what + // `regionck_item` expects. + let impl_m_node_id = tcx.hir.as_local_node_id(impl_m.def_id).unwrap(); + let cause = ObligationCause { span: impl_m_span, - body_id: impl_m_body_id, + body_id: impl_m_node_id, code: ObligationCauseCode::CompareImplMethodObligation { item_name: impl_m.name, impl_item_def_id: impl_m.def_id, trait_item_def_id: trait_m.def_id, - lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None }, + lint_id: if !old_broken_mode { Some(impl_m_node_id) } else { None }, }, }; @@ -166,7 +167,6 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Create a parameter environment that represents the implementation's // method. - let impl_m_node_id = tcx.hir.as_local_node_id(impl_m.def_id).unwrap(); let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_m_node_id); // Create mapping from impl to skolemized. @@ -217,9 +217,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Construct trait parameter environment and then shift it into the skolemized viewpoint. // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. - let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id); + let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id); let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates); let trait_param_env = traits::normalize_param_env_or_error(tcx, + impl_m.def_id, trait_param_env, normalize_cause.clone()); @@ -275,7 +276,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_sig.subst(tcx, impl_to_skol_substs); let impl_sig = inh.normalize_associated_types_in(impl_m_span, - impl_m_body_id, + impl_m_node_id, &impl_sig); let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); @@ -287,7 +288,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_sig.subst(tcx, trait_to_skol_substs); let trait_sig = inh.normalize_associated_types_in(impl_m_span, - impl_m_body_id, + impl_m_node_id, &trait_sig); let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig)); @@ -349,13 +350,14 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // region obligations that get overlooked. The right // thing to do is the code below. But we keep this old // pass around temporarily. + let region_maps = RegionMaps::new(); let mut free_regions = FreeRegionMap::new(); free_regions.relate_free_regions_from_predicates( &infcx.parameter_environment.caller_bounds); - infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); + infcx.resolve_regions_and_report_errors(impl_m.def_id, ®ion_maps, &free_regions); } else { - let fcx = FnCtxt::new(&inh, impl_m_body_id); - fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); + let fcx = FnCtxt::new(&inh, impl_m_node_id); + fcx.regionck_item(impl_m_node_id, impl_m_span, &[]); } Ok(()) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index e4408413ee6..c20777a403a 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -13,7 +13,7 @@ use hir::def_id::DefId; use middle::free_region::FreeRegionMap; use rustc::infer::{self, InferOk}; -use middle::region; +use rustc::middle::region::{self, RegionMaps}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::{self, ObligationCause, Reveal}; @@ -116,8 +116,9 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( return Err(ErrorReported); } + let region_maps = RegionMaps::new(); let free_regions = FreeRegionMap::new(); - infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id); + infcx.resolve_regions_and_report_errors(drop_impl_did, ®ion_maps, &free_regions); Ok(()) }) } @@ -278,7 +279,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( ty, scope); - let parent_scope = match rcx.tcx.region_maps().opt_encl_scope(scope) { + let parent_scope = match rcx.region_maps.opt_encl_scope(scope) { Some(parent_scope) => parent_scope, // If no enclosing scope, then it must be the root scope // which cannot be outlived. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 729d25aaef5..7705041fc92 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1237,14 +1237,13 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, err.emit() } } - hir::ImplItemKind::Method(_, body_id) => { + hir::ImplItemKind::Method(..) => { let trait_span = tcx.hir.span_if_local(ty_trait_item.def_id); if ty_trait_item.kind == ty::AssociatedKind::Method { let err_count = tcx.sess.err_count(); compare_impl_method(tcx, &ty_impl_item, impl_item.span, - body_id.node_id, &ty_trait_item, impl_trait_ref, trait_span, @@ -1254,7 +1253,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, compare_impl_method(tcx, &ty_impl_item, impl_item.span, - body_id.node_id, &ty_trait_item, impl_trait_ref, trait_span, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 9a978934dda..b241f52f62e 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -87,7 +87,8 @@ use middle::free_region::FreeRegionMap; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; -use middle::region::{self, CodeExtent}; +use middle::region::{self, CodeExtent, RegionMaps}; +use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, MethodCall, TypeFoldable}; @@ -97,6 +98,7 @@ use std::mem; use std::ops::Deref; +use std::rc::Rc; use syntax::ast; use syntax_pos::Span; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -112,8 +114,9 @@ macro_rules! ignore_err { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn regionck_expr(&self, body: &'gcx hir::Body) { + let subject = self.tcx.hir.body_owner_def_id(body.id()); let id = body.value.id; - let mut rcx = RegionCtxt::new(self, RepeatingScope(id), id, Subject(id)); + let mut rcx = RegionCtxt::new(self, RepeatingScope(id), id, Subject(subject)); if self.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_body(body); @@ -132,7 +135,8 @@ pub fn regionck_item(&self, span: Span, wf_tys: &[Ty<'tcx>]) { debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys); - let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(item_id)); + let subject = self.tcx.hir.local_def_id(item_id); + let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(subject)); rcx.free_region_map.relate_free_regions_from_predicates( &self.parameter_environment.caller_bounds); rcx.relate_free_regions(wf_tys, item_id, span); @@ -144,8 +148,9 @@ pub fn regionck_fn(&self, fn_id: ast::NodeId, body: &'gcx hir::Body) { debug!("regionck_fn(id={})", fn_id); + let subject = self.tcx.hir.body_owner_def_id(body.id()); let node_id = body.value.id; - let mut rcx = RegionCtxt::new(self, RepeatingScope(node_id), node_id, Subject(fn_id)); + let mut rcx = RegionCtxt::new(self, RepeatingScope(node_id), node_id, Subject(subject)); if self.err_count_since_creation() == 0 { // regionck assumes typeck succeeded @@ -173,6 +178,8 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, + pub region_maps: Rc>, + free_region_map: FreeRegionMap<'tcx>, // id of innermost fn body id @@ -185,7 +192,7 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { repeating_scope: ast::NodeId, // id of AST node being analyzed (the subject of the analysis). - subject: ast::NodeId, + subject_def_id: DefId, } @@ -197,19 +204,21 @@ fn deref(&self) -> &Self::Target { } pub struct RepeatingScope(ast::NodeId); -pub struct Subject(ast::NodeId); +pub struct Subject(DefId); impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { pub fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, RepeatingScope(initial_repeating_scope): RepeatingScope, initial_body_id: ast::NodeId, Subject(subject): Subject) -> RegionCtxt<'a, 'gcx, 'tcx> { + let region_maps = fcx.tcx.region_maps(subject); RegionCtxt { fcx: fcx, + region_maps: region_maps, repeating_scope: initial_repeating_scope, body_id: initial_body_id, call_site_scope: None, - subject: subject, + subject_def_id: subject, region_bound_pairs: Vec::new(), free_region_map: FreeRegionMap::new(), } @@ -418,14 +427,12 @@ fn relate_free_regions(&mut self, } fn resolve_regions_and_report_errors(&self) { - let subject_node_id = self.subject; - - self.fcx.resolve_regions_and_report_errors(&self.free_region_map, - subject_node_id); + self.fcx.resolve_regions_and_report_errors(self.subject_def_id, + &self.region_maps, + &self.free_region_map); } fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) { - let tcx = self.tcx; debug!("regionck::visit_pat(pat={:?})", pat); pat.each_binding(|_, id, span, _| { // If we have a variable that contains region'd data, that @@ -451,7 +458,7 @@ fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) { // that the lifetime of any regions that appear in a // variable's type enclose at least the variable's scope. - let var_scope = tcx.region_maps().var_scope(id); + let var_scope = self.region_maps.var_scope(id); let var_region = self.tcx.mk_region(ty::ReScope(var_scope)); let origin = infer::BindingTypeIsNotValidAtDecl(span); @@ -570,7 +577,7 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) { // If necessary, constrain destructors in the unadjusted form of this // expression. let cmt_result = { - let mc = mc::MemCategorizationContext::new(self); + let mc = mc::MemCategorizationContext::new(self, self.subject_def_id); mc.cat_expr_unadjusted(expr) }; match cmt_result { @@ -587,7 +594,7 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) { // If necessary, constrain destructors in this expression. This will be // the adjusted form if there is an adjustment. let cmt_result = { - let mc = mc::MemCategorizationContext::new(self); + let mc = mc::MemCategorizationContext::new(self, self.subject_def_id); mc.cat_expr(expr) }; match cmt_result { @@ -949,7 +956,7 @@ fn constrain_autoderefs(&mut self, r, m); { - let mc = mc::MemCategorizationContext::new(self); + let mc = mc::MemCategorizationContext::new(self, self.subject_def_id); let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); debug!("constrain_autoderefs: self_cmt={:?}", self_cmt); @@ -1061,7 +1068,7 @@ fn link_addr_of(&mut self, expr: &hir::Expr, debug!("link_addr_of(expr={:?}, base={:?})", expr, base); let cmt = { - let mc = mc::MemCategorizationContext::new(self); + let mc = mc::MemCategorizationContext::new(self, self.subject_def_id); ignore_err!(mc.cat_expr(base)) }; @@ -1079,7 +1086,7 @@ fn link_local(&self, local: &hir::Local) { None => { return; } Some(ref expr) => &**expr, }; - let mc = mc::MemCategorizationContext::new(self); + let mc = &mc::MemCategorizationContext::new(self, self.subject_def_id); let discr_cmt = ignore_err!(mc.cat_expr(init_expr)); self.link_pattern(mc, discr_cmt, &local.pat); } @@ -1089,7 +1096,7 @@ fn link_local(&self, local: &hir::Local) { /// linked to the lifetime of its guarantor (if any). fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) { debug!("regionck::for_match()"); - let mc = mc::MemCategorizationContext::new(self); + let mc = &mc::MemCategorizationContext::new(self, self.subject_def_id); let discr_cmt = ignore_err!(mc.cat_expr(discr)); debug!("discr_cmt={:?}", discr_cmt); for arm in arms { @@ -1104,7 +1111,7 @@ fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) { /// linked to the lifetime of its guarantor (if any). fn link_fn_args(&self, body_scope: CodeExtent<'tcx>, args: &[hir::Arg]) { debug!("regionck::link_fn_args(body_scope={:?})", body_scope); - let mc = mc::MemCategorizationContext::new(self); + let mc = &mc::MemCategorizationContext::new(self, self.subject_def_id); for arg in args { let arg_ty = self.node_ty(arg.id); let re_scope = self.tcx.mk_region(ty::ReScope(body_scope)); @@ -1121,13 +1128,13 @@ fn link_fn_args(&self, body_scope: CodeExtent<'tcx>, args: &[hir::Arg]) { /// Link lifetimes of any ref bindings in `root_pat` to the pointers found /// in the discriminant, if needed. fn link_pattern<'t>(&self, - mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>, + mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>, discr_cmt: mc::cmt<'tcx>, root_pat: &hir::Pat) { debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat); - let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| { + let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| { match sub_pat.node { // `ref x` pattern PatKind::Binding(hir::BindByRef(mutbl), ..) => { @@ -1147,7 +1154,7 @@ fn link_autoref(&self, autoref: &adjustment::AutoBorrow<'tcx>) { debug!("link_autoref(autoderefs={}, autoref={:?})", autoderefs, autoref); - let mc = mc::MemCategorizationContext::new(self); + let mc = mc::MemCategorizationContext::new(self, self.subject_def_id); let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); debug!("expr_cmt={:?}", expr_cmt); @@ -1171,7 +1178,7 @@ fn link_by_ref(&self, callee_scope: CodeExtent<'tcx>) { debug!("link_by_ref(expr={:?}, callee_scope={:?})", expr, callee_scope); - let mc = mc::MemCategorizationContext::new(self); + let mc = mc::MemCategorizationContext::new(self, self.subject_def_id); let expr_cmt = ignore_err!(mc.cat_expr(expr)); let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope)); self.link_region(expr.span, borrow_region, ty::ImmBorrow, expr_cmt); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index a2c9b7876aa..227f06436ee 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -164,9 +164,11 @@ fn analyze_closure(&mut self, debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id()); { + let body_owner_def_id = self.fcx.tcx.hir.body_owner_def_id(body.id()); let mut euv = euv::ExprUseVisitor::with_options(self, self.fcx, + body_owner_def_id, mc::MemCategorizationOptions { during_closure_kind_inference: true }); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 57193b3584d..49785d8850f 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -12,6 +12,7 @@ //! up data structures required by type-checking/translation. use rustc::middle::free_region::FreeRegionMap; +use rustc::middle::region::RegionMaps; use rustc::middle::lang_items::UnsizeTraitLangItem; use rustc::traits::{self, ObligationCause, Reveal}; @@ -342,10 +343,11 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Finally, resolve all regions. + let region_maps = RegionMaps::new(); let mut free_regions = FreeRegionMap::new(); free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment .caller_bounds); - infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id); + infcx.resolve_regions_and_report_errors(impl_did, ®ion_maps, &free_regions); CoerceUnsizedInfo { custom_kind: kind diff --git a/src/test/run-pass/kindck-implicit-close-over-mut-var.rs b/src/test/run-pass/kindck-implicit-close-over-mut-var.rs index d1f957bf6b9..a81c0846a27 100644 --- a/src/test/run-pass/kindck-implicit-close-over-mut-var.rs +++ b/src/test/run-pass/kindck-implicit-close-over-mut-var.rs @@ -1,4 +1,4 @@ -s// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. //