diff options
| author | Taylor Cramer <cramertaylorj@gmail.com> | 2017-04-10 00:00:08 -0700 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2017-04-30 17:03:30 -0400 |
| commit | 73cd9bde373cc134aa2ebb6a8064d532621ca0a6 (patch) | |
| tree | c27699bff217136b907b85b1cd76d6eba7089f18 /src/librustc/middle | |
| parent | c7dc39dbf095f04839b57a1e34afc6ab29d905d3 (diff) | |
| download | rust-73cd9bde373cc134aa2ebb6a8064d532621ca0a6.tar.gz rust-73cd9bde373cc134aa2ebb6a8064d532621ca0a6.zip | |
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.
Diffstat (limited to 'src/librustc/middle')
| -rw-r--r-- | src/librustc/middle/expr_use_visitor.rs | 9 | ||||
| -rw-r--r-- | src/librustc/middle/free_region.rs | 153 | ||||
| -rw-r--r-- | src/librustc/middle/mem_categorization.rs | 19 | ||||
| -rw-r--r-- | src/librustc/middle/region.rs | 80 |
4 files changed, 168 insertions, 93 deletions
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 @@ impl<'tcx> FreeRegionMap<'tcx> { 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 @@ pub use self::Note::*; 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 @@ impl ast_node for hir::Pat { 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<RegionMaps<'tcx>>, options: MemCategorizationOptions, } @@ -402,16 +404,21 @@ impl MutabilityCategory { } 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 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; match fn_expr.node { - hir::ExprClosure(.., body_id, _) => body_id.node_id, + hir::ExprClosure(.., body_id, _) => body_id, _ => bug!() } }; @@ -796,7 +803,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // 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 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { 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 syntax_pos::Span; 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<CodeExtent<'tcx>>, + /// maps from a node-id to the associated destruction scope (if any) + destruction_scopes: NodeMap<CodeExtent<'tcx>>, + /// `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<E>(&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 @@ impl<'tcx> RegionMaps<'tcx> { } } + pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent<'tcx>> { + 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 @@ impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> { } } -pub fn resolve_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc<RegionMaps<'tcx>> { - 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<RegionMaps<'tcx>> { - 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 }; } |
