From 316510f5e216340d9ec1a2734e2f5ada87504689 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 18 Aug 2015 23:21:29 +0300 Subject: [PATCH 1/7] split ReInfer into ReVar and ReSkolemized this should reduce the size of ty::Region to 24 bytes (from 32), and they are treated differently in most cases anyway. --- src/librustc/metadata/tyencode.rs | 2 +- src/librustc/middle/astencode.rs | 2 +- src/librustc/middle/infer/combine.rs | 4 +- src/librustc/middle/infer/error_reporting.rs | 9 ++-- src/librustc/middle/infer/freshen.rs | 3 +- .../middle/infer/higher_ranked/mod.rs | 8 ++-- src/librustc/middle/infer/mod.rs | 2 +- .../middle/infer/region_inference/mod.rs | 42 ++++++++--------- src/librustc/middle/infer/resolve.rs | 2 +- src/librustc/middle/ty.rs | 45 ++++++------------- src/librustc/util/ppaux.rs | 10 ++--- .../borrowck/gather_loans/mod.rs | 3 +- src/librustc_typeck/check/regionck.rs | 2 +- src/librustc_typeck/variance.rs | 4 +- src/librustdoc/clean/mod.rs | 3 +- 15 files changed, 65 insertions(+), 76 deletions(-) diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 65bb04309d075..5be19bd5ba7ea 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -271,7 +271,7 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) { ty::ReEmpty => { mywrite!(w, "e"); } - ty::ReInfer(_) => { + ty::ReVar(_) | ty::ReSkolemized(..) => { // these should not crop up after typeck cx.diag.handler().bug("cannot encode region variables"); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index d7fe8e95ae7b3..5fd1fea41aebb 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -498,7 +498,7 @@ impl tr for ty::Region { ty::ReScope(scope) => { ty::ReScope(scope.tr(dcx)) } - ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) => { + ty::ReEmpty | ty::ReStatic | ty::ReVar(..) | ty::ReSkolemized(..) => { *self } ty::ReFree(ref fr) => { diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 94c76e2399947..cfeec1c4f73e3 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -340,14 +340,14 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { // Always make a fresh region variable for skolemized regions; // the higher-ranked decision procedures rely on this. - ty::ReInfer(ty::ReSkolemized(..)) => { } + ty::ReSkolemized(..) => { } // For anything else, we make a region variable, unless we // are *equating*, in which case it's just wasteful. ty::ReEmpty | ty::ReStatic | ty::ReScope(..) | - ty::ReInfer(ty::ReVar(..)) | + ty::ReVar(..) | ty::ReFree(..) => { if !self.make_region_vars { return r; diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 44eceb1f213af..dca480b39c825 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -196,9 +196,12 @@ impl<'tcx> ty::ctxt<'tcx> { ty::ReEarlyBound(ref data) => (data.name.to_string(), None), - // I believe these cases should not occur (except when debugging, - // perhaps) - ty::ReInfer(_) | ty::ReLateBound(..) => { + // FIXME(#13998) ReSkolemized should probably print like + // ReFree rather than dumping Debug output on the user. + // + // We shouldn't really be having unification failures with ReVar + // and ReLateBound through. + ty::ReSkolemized(..) | ty::ReVar(_) | ty::ReLateBound(..) => { (format!("lifetime {:?}", region), None) } }; diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index d65c4061f11eb..c72a4fc0db309 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -95,7 +95,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { ty::ReStatic | ty::ReFree(_) | ty::ReScope(_) | - ty::ReInfer(_) | + ty::ReVar(_) | + ty::ReSkolemized(..) | ty::ReEmpty => { // replace all free regions with 'static ty::ReStatic diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 5f2f4df2f1601..fb8da9b65daee 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -335,7 +335,7 @@ fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>, -> Vec { map.iter() .map(|(_, r)| match *r { - ty::ReInfer(ty::ReVar(r)) => { r } + ty::ReVar(r) => { r } r => { fields.tcx().sess.span_bug( fields.trace.origin.span(), @@ -347,7 +347,7 @@ fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>, fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { match r { - ty::ReInfer(ty::ReVar(ref v)) => new_vars.iter().any(|x| x == v), + ty::ReVar(ref v) => new_vars.iter().any(|x| x == v), _ => false } } @@ -443,7 +443,7 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { } region_vars.retain(|®ion_vid| { - let r = ty::ReInfer(ty::ReVar(region_vid)); + let r = ty::ReVar(region_vid); !escaping_region_vars.contains(&r) }); @@ -561,7 +561,7 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, // Each skolemized should only be relatable to itself // or new variables: match tainted_region { - ty::ReInfer(ty::ReVar(vid)) => { + ty::ReVar(vid) => { if new_vars.iter().any(|&x| x == vid) { continue; } } _ => { diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 4d558ed5663d8..4e8ed01c6b9e0 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1059,7 +1059,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region { - ty::ReInfer(ty::ReVar(self.region_vars.new_region_var(origin))) + ty::ReVar(self.region_vars.new_region_var(origin)) } pub fn region_vars_for_defs(&self, diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index e04f2955ddc18..d9265f78ccae0 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -25,7 +25,7 @@ use middle::free_region::FreeRegionMap; use middle::region; use middle::ty::{self, Ty, TypeError}; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; -use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; +use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; use middle::ty_relate::RelateResult; use util::common::indenter; @@ -373,7 +373,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { let sc = self.skolemization_count.get(); self.skolemization_count.set(sc + 1); - ReInfer(ReSkolemized(sc, br)) + ReSkolemized(sc, br) } pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region { @@ -510,13 +510,13 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { (_, ReStatic) => { // all regions are subregions of static, so we can ignore this } - (ReInfer(ReVar(sub_id)), ReInfer(ReVar(sup_id))) => { + (ReVar(sub_id), ReVar(sup_id)) => { self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); } - (r, ReInfer(ReVar(sup_id))) => { + (r, ReVar(sup_id)) => { self.add_constraint(ConstrainRegSubVar(r, sup_id), origin); } - (ReInfer(ReVar(sub_id)), r) => { + (ReVar(sub_id), r) => { self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); } _ => { @@ -621,7 +621,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { let vars = TwoRegions { a: a, b: b }; match self.combine_map(t).borrow().get(&vars) { Some(&c) => { - return ReInfer(ReVar(c)); + return ReVar(c); } None => {} } @@ -630,10 +630,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { if self.in_snapshot() { self.undo_log.borrow_mut().push(AddCombination(t, vars)); } - relate(self, a, ReInfer(ReVar(c))); - relate(self, b, ReInfer(ReVar(c))); + relate(self, a, ReVar(c)); + relate(self, b, ReVar(c)); debug!("combine_vars() c={:?}", c); - ReInfer(ReVar(c)) + ReVar(c) } pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) @@ -672,22 +672,22 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { &AddConstraint(ConstrainVarSubVar(a, b)) => { consider_adding_bidirectional_edges( &mut result_set, r, - ReInfer(ReVar(a)), ReInfer(ReVar(b))); + ReVar(a), ReVar(b)); } &AddConstraint(ConstrainRegSubVar(a, b)) => { consider_adding_bidirectional_edges( &mut result_set, r, - a, ReInfer(ReVar(b))); + a, ReVar(b)); } &AddConstraint(ConstrainVarSubReg(a, b)) => { consider_adding_bidirectional_edges( &mut result_set, r, - ReInfer(ReVar(a)), b); + ReVar(a), b); } &AddGiven(a, b) => { consider_adding_bidirectional_edges( &mut result_set, r, - ReFree(a), ReInfer(ReVar(b))); + ReFree(a), ReVar(b)); } &AddVerify(i) => { match (*self.verifys.borrow())[i] { @@ -775,7 +775,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { r // everything lives longer than empty } - (ReInfer(ReVar(v_id)), _) | (_, ReInfer(ReVar(v_id))) => { + (ReVar(v_id), _) | (_, ReVar(v_id)) => { self.tcx.sess.span_bug( (*self.var_origins.borrow())[v_id.index as usize].span(), &format!("lub_concrete_regions invoked with \ @@ -818,8 +818,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // For these types, we cannot define any additional // relationship: - (ReInfer(ReSkolemized(..)), _) | - (_, ReInfer(ReSkolemized(..))) => { + (ReSkolemized(..), _) | + (_, ReSkolemized(..)) => { if a == b {a} else {ReStatic} } } @@ -853,8 +853,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { Ok(ReEmpty) } - (ReInfer(ReVar(v_id)), _) | - (_, ReInfer(ReVar(v_id))) => { + (ReVar(v_id), _) | + (_, ReVar(v_id)) => { self.tcx.sess.span_bug( (*self.var_origins.borrow())[v_id.index as usize].span(), &format!("glb_concrete_regions invoked with \ @@ -890,8 +890,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // For these types, we cannot define any additional // relationship: - (ReInfer(ReSkolemized(..)), _) | - (_, ReInfer(ReSkolemized(..))) => { + (ReSkolemized(..), _) | + (_, ReSkolemized(..)) => { if a == b { Ok(a) } else { @@ -1632,7 +1632,7 @@ impl<'tcx> fmt::Debug for Verify<'tcx> { fn normalize(values: &Vec, r: ty::Region) -> ty::Region { match r { - ty::ReInfer(ReVar(rid)) => lookup(values, rid), + ty::ReVar(rid) => lookup(values, rid), _ => r } } diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index 39807002b58a1..9cc9f148ce183 100644 --- a/src/librustc/middle/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -106,7 +106,7 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region) -> ty::Region { match r { - ty::ReInfer(ty::ReVar(rid)) => self.infcx.region_vars.resolve_var(rid), + ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid), _ => r, } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 7418d81ed3dce..52d76d277792e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -12,7 +12,6 @@ #![allow(non_camel_case_types)] pub use self::InferTy::*; -pub use self::InferRegion::*; pub use self::ImplOrTraitItemId::*; pub use self::ClosureKind::*; pub use self::Variance::*; @@ -1529,7 +1528,11 @@ pub enum Region { ReStatic, /// A region variable. Should not exist after typeck. - ReInfer(InferRegion), + ReVar(RegionVid), + + /// A skolemized region - basically the higher-ranked version of ReFree. + /// Should not exist after typeck. + ReSkolemized(u32, BoundRegion), /// Empty lifetime is for data that is never accessed. /// Bottom in the region lattice. We treat ReEmpty somewhat @@ -1648,7 +1651,7 @@ impl Region { pub fn needs_infer(&self) -> bool { match *self { - ty::ReInfer(..) => true, + ty::ReVar(..) | ty::ReSkolemized(..) => true, _ => false } } @@ -2187,29 +2190,6 @@ pub enum UnconstrainedNumeric { } -#[derive(Clone, RustcEncodable, RustcDecodable, Eq, Hash, Debug, Copy)] -pub enum InferRegion { - ReVar(RegionVid), - ReSkolemized(u32, BoundRegion) -} - -impl cmp::PartialEq for InferRegion { - fn eq(&self, other: &InferRegion) -> bool { - match ((*self), *other) { - (ReVar(rva), ReVar(rvb)) => { - rva == rvb - } - (ReSkolemized(rva, _), ReSkolemized(rvb, _)) => { - rva == rvb - } - _ => false - } - } - fn ne(&self, other: &InferRegion) -> bool { - !((*self) == (*other)) - } -} - impl fmt::Debug for TyVid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "_#{}t", self.index) @@ -3722,7 +3702,8 @@ impl FlagComputation { fn add_region(&mut self, r: Region) { match r { - ty::ReInfer(_) => { self.add_flags(TypeFlags::HAS_RE_INFER); } + ty::ReVar(..) | + ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); } ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); } ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); } ty::ReStatic => {} @@ -5728,7 +5709,7 @@ impl<'tcx> ctxt<'tcx> { self.note_and_explain_region("concrete lifetime that was found is ", conc_region, ""); } - RegionsOverlyPolymorphic(_, ty::ReInfer(ty::ReVar(_))) => { + RegionsOverlyPolymorphic(_, ty::ReVar(_)) => { // don't bother to print out the message below for // inference variables, it's not very illuminating. } @@ -6479,7 +6460,8 @@ impl<'tcx> ctxt<'tcx> { ReLateBound(..) | ReFree(..) | ReScope(..) | - ReInfer(..) => { + ReVar(..) | + ReSkolemized(..) => { tcx.sess.bug("unexpected region found when hashing a type") } } @@ -7338,8 +7320,9 @@ impl HasTypeFlags for Region { } } if flags.intersects(TypeFlags::HAS_RE_INFER) { - if let ty::ReInfer(_) = *self { - return true; + match *self { + ty::ReVar(_) | ty::ReSkolemized(..) => { return true } + _ => {} } } false diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index b94711065dfd4..48c2e1e6dca7a 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -13,7 +13,7 @@ use middle::def_id::DefId; use middle::subst::{self, Subst}; use middle::ty::{BoundRegion, BrAnon, BrNamed}; use middle::ty::{ReEarlyBound, BrFresh, ctxt}; -use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty}; +use middle::ty::{ReFree, ReScope, ReStatic, Region, ReEmpty}; use middle::ty::{ReSkolemized, ReVar, BrEnv}; use middle::ty::{TyBool, TyChar, TyStruct, TyEnum}; use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyBareFn}; @@ -413,11 +413,11 @@ impl fmt::Debug for ty::Region { ty::ReStatic => write!(f, "ReStatic"), - ty::ReInfer(ReVar(ref vid)) => { + ty::ReVar(ref vid) => { write!(f, "{:?}", vid) } - ty::ReInfer(ReSkolemized(id, ref bound_region)) => { + ty::ReSkolemized(id, ref bound_region) => { write!(f, "ReSkolemized({}, {:?})", id, bound_region) } @@ -442,11 +442,11 @@ impl fmt::Display for ty::Region { } ty::ReLateBound(_, br) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | - ty::ReInfer(ReSkolemized(_, br)) => { + ty::ReSkolemized(_, br) => { write!(f, "{}", br) } ty::ReScope(_) | - ty::ReInfer(ReVar(_)) => Ok(()), + ty::ReVar(_) => Ok(()), ty::ReStatic => write!(f, "'static"), ty::ReEmpty => write!(f, "'"), } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 6899892a245ed..d1e75afad454b 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -377,7 +377,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { ty::ReEmpty | ty::ReLateBound(..) | ty::ReEarlyBound(..) | - ty::ReInfer(..) => { + ty::ReVar(..) | + ty::ReSkolemized(..) => { self.tcx().sess.span_bug( cmt.span, &format!("invalid borrow lifetime: {:?}", diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index ced3ee82de2bd..156aa14bebf58 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -428,7 +428,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { debug!("implication: {:?}", implication); match implication { ImpliedBound::RegionSubRegion(ty::ReFree(free_a), - ty::ReInfer(ty::ReVar(vid_b))) => { + ty::ReVar(vid_b)) => { self.fcx.inh.infcx.add_given(free_a, vid_b); } ImpliedBound::RegionSubParam(r_a, param_b) => { diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 8165da95aedc7..98058b804eee4 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -1025,8 +1025,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // methods or in fn types. } - ty::ReFree(..) | ty::ReScope(..) | ty::ReInfer(..) | - ty::ReEmpty => { + ty::ReFree(..) | ty::ReScope(..) | ty::ReVar(..) | + ty::ReSkolemized(..) | ty::ReEmpty => { // We don't expect to see anything but 'static or bound // regions when visiting member types or method types. self.tcx() diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6a2d0b46ad420..9cd376f8d31bd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -772,7 +772,8 @@ impl Clean> for ty::Region { ty::ReLateBound(..) | ty::ReFree(..) | ty::ReScope(..) | - ty::ReInfer(..) | + ty::ReVar(..) | + ty::ReSkolemized(..) | ty::ReEmpty(..) => None } } From 2bcc6d8ec7f525328a1e8c8ce423ac3ac015eb6d Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 19 Aug 2015 15:10:18 +0300 Subject: [PATCH 2/7] Use a u32 instead of a usize in CodeExtent This reduces the size of CodeExtent to 12 bytes (was 24). We should have a warning for this kind of problem. --- src/librustc/metadata/tydecode.rs | 3 +-- src/librustc/middle/region.rs | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 59f938d9489a7..7a111003aa8ce 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -269,7 +269,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { assert_eq!(self.next(), '['); let node_id = self.parse_uint() as ast::NodeId; assert_eq!(self.next(), '|'); - let first_stmt_index = self.parse_uint(); + let first_stmt_index = self.parse_u32(); assert_eq!(self.next(), ']'); let block_remainder = region::BlockRemainder { block: node_id, first_statement_index: first_stmt_index, @@ -717,4 +717,3 @@ fn parse_unsafety(c: char) -> ast::Unsafety { _ => panic!("parse_unsafety: bad unsafety {}", c) } } - diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index dafc1e900f3f9..5ccbffa40a3f5 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -144,7 +144,7 @@ impl DestructionScopeData { RustcDecodable, Debug, Copy)] pub struct BlockRemainder { pub block: ast::NodeId, - pub first_statement_index: usize, + pub first_statement_index: u32, } impl CodeExtent { @@ -207,7 +207,7 @@ impl CodeExtent { // // (This is the special case aluded to in the // doc-comment for this method) - let stmt_span = blk.stmts[r.first_statement_index].span; + let stmt_span = blk.stmts[r.first_statement_index as usize].span; Some(Span { lo: stmt_span.hi, ..blk.span }) } } @@ -310,7 +310,7 @@ impl InnermostDeclaringBlock { struct DeclaringStatementContext { stmt_id: ast::NodeId, block_id: ast::NodeId, - stmt_index: usize, + stmt_index: u32, } impl DeclaringStatementContext { @@ -711,7 +711,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) { let declaring = DeclaringStatementContext { stmt_id: stmt_id, block_id: blk.id, - stmt_index: i, + stmt_index: i as u32, }; record_superlifetime( visitor, declaring.to_code_extent(), statement.span); From fc304384e6ed40f505fa0f04043044dd44e73118 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 20 Aug 2015 01:46:28 +0300 Subject: [PATCH 3/7] Use a Vec instead of an HashMap for the scope hierarchy This increases regionck performance greatly - type-checking on librustc decreased from 9.1s to 8.1s. Because of Amdahl's law, total performance is improved only by about 1.5% (LLVM wizards, this is your opportunity to shine!). before: 576.91user 4.26system 7:42.36elapsed 125%CPU (0avgtext+0avgdata 1142192maxresident)k after: 566.50user 4.84system 7:36.84elapsed 125%CPU (0avgtext+0avgdata 1124304maxresident)k I am somewhat worried really need to find out why we have this Red Queen's Race going on here. Originally I suspected it may be a problem from RFC1214's warnings, but it seems to be an effect from other changes. However, the increase seems to be mostly in LLVM's time, so I guess it's the LLVM wizards' problem. --- src/librustc/metadata/tydecode.rs | 43 +- src/librustc/metadata/tyencode.rs | 35 +- src/librustc/middle/astencode.rs | 187 +++--- src/librustc/middle/cfg/construct.rs | 8 +- src/librustc/middle/expr_use_visitor.rs | 10 +- src/librustc/middle/free_region.rs | 4 +- src/librustc/middle/infer/error_reporting.rs | 14 +- .../middle/infer/region_inference/mod.rs | 8 +- src/librustc/middle/region.rs | 626 +++++++++--------- src/librustc/middle/ty.rs | 11 +- src/librustc_borrowck/borrowck/check_loans.rs | 35 +- .../borrowck/gather_loans/mod.rs | 8 +- src/librustc_borrowck/borrowck/mod.rs | 10 +- src/librustc_borrowck/borrowck/move_data.rs | 4 +- src/librustc_driver/test.rs | 46 +- src/librustc_trans/trans/cleanup.rs | 22 +- src/librustc_typeck/check/regionck.rs | 30 +- 17 files changed, 561 insertions(+), 540 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 7a111003aa8ce..768e769efedc4 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -207,6 +207,8 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 'B' => { assert_eq!(self.next(), '['); + // this is totally wrong, but nobody relevant cares about + // this field - it will die soon(TM). let node_id = self.parse_uint() as ast::NodeId; assert_eq!(self.next(), '|'); let space = self.parse_param_space(); @@ -246,24 +248,26 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } fn parse_scope(&mut self) -> region::CodeExtent { - match self.next() { + self.tcx.region_maps.bogus_code_extent(match self.next() { + // the scopes created here are totally bogus with their + // NodeIDs 'P' => { assert_eq!(self.next(), '['); let fn_id = self.parse_uint() as ast::NodeId; assert_eq!(self.next(), '|'); let body_id = self.parse_uint() as ast::NodeId; assert_eq!(self.next(), ']'); - region::CodeExtent::ParameterScope { + region::CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id } } 'M' => { let node_id = self.parse_uint() as ast::NodeId; - region::CodeExtent::Misc(node_id) + region::CodeExtentData::Misc(node_id) } 'D' => { let node_id = self.parse_uint() as ast::NodeId; - region::CodeExtent::DestructionScope(node_id) + region::CodeExtentData::DestructionScope(node_id) } 'B' => { assert_eq!(self.next(), '['); @@ -274,10 +278,10 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { let block_remainder = region::BlockRemainder { block: node_id, first_statement_index: first_stmt_index, }; - region::CodeExtent::Remainder(block_remainder) + region::CodeExtentData::Remainder(block_remainder) } _ => panic!("parse_scope: bad input") - } + }) } fn parse_destruction_scope_data(&mut self) -> region::DestructionScopeData { @@ -619,6 +623,33 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } + pub fn parse_region_param_def(&mut self) -> ty::RegionParameterDef { + let name = self.parse_name(':'); + let def_id = self.parse_def(NominalType); + let space = self.parse_param_space(); + assert_eq!(self.next(), '|'); + let index = self.parse_u32(); + assert_eq!(self.next(), '|'); + let mut bounds = vec![]; + loop { + match self.next() { + 'R' => bounds.push(self.parse_region()), + '.' => { break; } + c => { + panic!("parse_region_param_def: bad bounds ('{}')", c) + } + } + } + ty::RegionParameterDef { + name: name, + def_id: def_id, + space: space, + index: index, + bounds: bounds + } + } + + fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault { match self.next() { 'a' => ty::ObjectLifetimeDefault::Ambiguous, diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 5be19bd5ba7ea..a17d27acc2a26 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -278,14 +278,14 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) { } } -fn enc_scope(w: &mut Encoder, _cx: &ctxt, scope: region::CodeExtent) { - match scope { - region::CodeExtent::ParameterScope { +fn enc_scope(w: &mut Encoder, cx: &ctxt, scope: region::CodeExtent) { + match cx.tcx.region_maps.code_extent_data(scope) { + region::CodeExtentData::ParameterScope { fn_id, body_id } => mywrite!(w, "P[{}|{}]", fn_id, body_id), - region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id), - region::CodeExtent::Remainder(region::BlockRemainder { + region::CodeExtentData::Misc(node_id) => mywrite!(w, "M{}", node_id), + region::CodeExtentData::Remainder(region::BlockRemainder { block: b, first_statement_index: i }) => mywrite!(w, "B[{}|{}]", b, i), - region::CodeExtent::DestructionScope(node_id) => mywrite!(w, "D{}", node_id), + region::CodeExtentData::DestructionScope(node_id) => mywrite!(w, "D{}", node_id), } } @@ -396,17 +396,6 @@ pub fn enc_existential_bounds<'a,'tcx>(w: &mut Encoder, mywrite!(w, "."); } -pub fn enc_region_bounds<'a, 'tcx>(w: &mut Encoder, - cx: &ctxt<'a, 'tcx>, - rs: &[ty::Region]) { - for &r in rs { - mywrite!(w, "R"); - enc_region(w, cx, r); - } - - mywrite!(w, "."); -} - pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, v: &ty::TypeParameterDef<'tcx>) { mywrite!(w, "{}:{}|{}|{}|{}|", @@ -416,6 +405,18 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, enc_object_lifetime_default(w, cx, v.object_lifetime_default); } +pub fn enc_region_param_def(w: &mut Encoder, cx: &ctxt, + v: &ty::RegionParameterDef) { + mywrite!(w, "{}:{}|{}|{}|", + v.name, (cx.ds)(v.def_id), + v.space.to_uint(), v.index); + for &r in &v.bounds { + mywrite!(w, "R"); + enc_region(w, cx, r); + } + mywrite!(w, "."); +} + fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, default: ty::ObjectLifetimeDefault) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 5fd1fea41aebb..2edf2b896ba17 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -478,67 +478,6 @@ impl tr for def::Def { } } -// ______________________________________________________________________ -// Encoding and decoding of ancillary information - -impl tr for ty::Region { - fn tr(&self, dcx: &DecodeContext) -> ty::Region { - match *self { - ty::ReLateBound(debruijn, br) => { - ty::ReLateBound(debruijn, br.tr(dcx)) - } - ty::ReEarlyBound(data) => { - ty::ReEarlyBound(ty::EarlyBoundRegion { - param_id: dcx.tr_id(data.param_id), - space: data.space, - index: data.index, - name: data.name, - }) - } - ty::ReScope(scope) => { - ty::ReScope(scope.tr(dcx)) - } - ty::ReEmpty | ty::ReStatic | ty::ReVar(..) | ty::ReSkolemized(..) => { - *self - } - ty::ReFree(ref fr) => { - ty::ReFree(fr.tr(dcx)) - } - } - } -} - -impl tr for ty::FreeRegion { - fn tr(&self, dcx: &DecodeContext) -> ty::FreeRegion { - ty::FreeRegion { scope: self.scope.tr(dcx), - bound_region: self.bound_region.tr(dcx) } - } -} - -impl tr for region::CodeExtent { - fn tr(&self, dcx: &DecodeContext) -> region::CodeExtent { - self.map_id(|id| dcx.tr_id(id)) - } -} - -impl tr for region::DestructionScopeData { - fn tr(&self, dcx: &DecodeContext) -> region::DestructionScopeData { - region::DestructionScopeData { node_id: dcx.tr_id(self.node_id) } - } -} - -impl tr for ty::BoundRegion { - fn tr(&self, dcx: &DecodeContext) -> ty::BoundRegion { - match *self { - ty::BrAnon(_) | - ty::BrFresh(_) | - ty::BrEnv => *self, - ty::BrNamed(id, ident) => ty::BrNamed(dcx.tr_def_id(id), - ident), - } - } -} - // ______________________________________________________________________ // Encoding and decoding of freevar information @@ -574,24 +513,6 @@ impl tr for ty::Freevar { } } -impl tr for ty::UpvarBorrow { - fn tr(&self, dcx: &DecodeContext) -> ty::UpvarBorrow { - ty::UpvarBorrow { - kind: self.kind, - region: self.region.tr(dcx) - } - } -} - -impl tr for ty::UpvarCapture { - fn tr(&self, dcx: &DecodeContext) -> ty::UpvarCapture { - match *self { - ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, - ty::UpvarCapture::ByRef(ref data) => ty::UpvarCapture::ByRef(data.tr(dcx)), - } - } -} - // ______________________________________________________________________ // Encoding and decoding of MethodCallee @@ -703,10 +624,13 @@ impl<'a, 'tcx> get_ty_str_ctxt<'tcx> for e::EncodeContext<'a, 'tcx> { trait rbml_writer_helpers<'tcx> { fn emit_closure_type<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, closure_type: &ty::ClosureTy<'tcx>); + fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region); fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>); fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]); fn emit_type_param_def<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, type_param_def: &ty::TypeParameterDef<'tcx>); + fn emit_region_param_def(&mut self, ecx: &e::EncodeContext, + region_param_def: &ty::RegionParameterDef); fn emit_predicate<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, predicate: &ty::Predicate<'tcx>); fn emit_trait_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, @@ -718,9 +642,11 @@ trait rbml_writer_helpers<'tcx> { fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, bounds: &ty::ExistentialBounds<'tcx>); fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds); + fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture); fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, adj: &ty::AutoAdjustment<'tcx>); - fn emit_autoref<'a>(&mut self, autoref: &ty::AutoRef<'tcx>); + fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, + autoref: &ty::AutoRef<'tcx>); fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, auto_deref_ref: &ty::AutoDerefRef<'tcx>); } @@ -734,6 +660,10 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { }); } + fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region) { + self.emit_opaque(|this| Ok(e::write_region(ecx, this, r))); + } + fn emit_ty<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, ty: Ty<'tcx>) { self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty))); } @@ -755,7 +685,14 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { type_param_def)) }); } - + fn emit_region_param_def(&mut self, ecx: &e::EncodeContext, + region_param_def: &ty::RegionParameterDef) { + self.emit_opaque(|this| { + Ok(tyencode::enc_region_param_def(this, + &ecx.ty_str_ctxt(), + region_param_def)) + }); + } fn emit_predicate<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, predicate: &ty::Predicate<'tcx>) { self.emit_opaque(|this| { @@ -781,7 +718,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_struct_field("regions", 1, |this| { Ok(encode_vec_per_param_space( this, &type_scheme.generics.regions, - |this, def| def.encode(this).unwrap())) + |this, def| this.emit_region_param_def(ecx, def))) }) }) }); @@ -804,6 +741,26 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { bounds))); } + fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture) { + use serialize::Encoder; + + self.emit_enum("UpvarCapture", |this| { + match *capture { + ty::UpvarCapture::ByValue => { + this.emit_enum_variant("ByValue", 1, 0, |_| Ok(())) + } + ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, region }) => { + this.emit_enum_variant("ByRef", 2, 0, |this| { + this.emit_enum_variant_arg(0, + |this| kind.encode(this)); + this.emit_enum_variant_arg(1, + |this| Ok(this.emit_region(ecx, region))) + }) + } + } + }).unwrap() + } + fn emit_substs<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, substs: &subst::Substs<'tcx>) { self.emit_opaque(|this| Ok(tyencode::enc_substs(this, @@ -837,14 +794,16 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { }); } - fn emit_autoref<'b>(&mut self, autoref: &ty::AutoRef<'tcx>) { + fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, + autoref: &ty::AutoRef<'tcx>) { use serialize::Encoder; self.emit_enum("AutoRef", |this| { match autoref { &ty::AutoPtr(r, m) => { this.emit_enum_variant("AutoPtr", 0, 2, |this| { - this.emit_enum_variant_arg(0, |this| r.encode(this)); + this.emit_enum_variant_arg(0, + |this| Ok(this.emit_region(ecx, *r))); this.emit_enum_variant_arg(1, |this| m.encode(this)) }) } @@ -868,7 +827,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_option(|this| { match auto_deref_ref.autoref { None => this.emit_option_none(), - Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(a))), + Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))), } }) }); @@ -983,7 +942,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, .unwrap() .clone(); var_id.encode(rbml_w); - upvar_capture.encode(rbml_w); + rbml_w.emit_upvar_capture(ecx, &upvar_capture); }) } } @@ -1080,6 +1039,7 @@ trait rbml_decoder_decoder_helpers<'tcx> { f: F) -> R where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x, 'tcx>) -> R; + fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region; fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>; fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec>; fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1088,6 +1048,8 @@ trait rbml_decoder_decoder_helpers<'tcx> { -> ty::PolyTraitRef<'tcx>; fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::TypeParameterDef<'tcx>; + fn read_region_param_def(&mut self, dcx: &DecodeContext) + -> ty::RegionParameterDef; fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::Predicate<'tcx>; fn read_type_scheme<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1096,6 +1058,8 @@ trait rbml_decoder_decoder_helpers<'tcx> { -> ty::ExistentialBounds<'tcx>; fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> subst::Substs<'tcx>; + fn read_upvar_capture(&mut self, dcx: &DecodeContext) + -> ty::UpvarCapture; fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::AutoAdjustment<'tcx>; fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1180,13 +1144,14 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { str } } - - fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> { + fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode // context. However, we do not bother, because region types - // are not used during trans. - + // are not used during trans. This also applies to read_ty. + return self.read_ty_encoded(dcx, |decoder| decoder.parse_region()); + } + fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> { return self.read_ty_encoded(dcx, |decoder| decoder.parse_ty()); } @@ -1209,7 +1174,10 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { -> ty::TypeParameterDef<'tcx> { self.read_ty_encoded(dcx, |decoder| decoder.parse_type_param_def()) } - + fn read_region_param_def(&mut self, dcx: &DecodeContext) + -> ty::RegionParameterDef { + self.read_ty_encoded(dcx, |decoder| decoder.parse_region_param_def()) + } fn read_predicate<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::Predicate<'tcx> { @@ -1232,7 +1200,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { regions: this.read_struct_field("regions", 1, |this| { Ok(this.read_vec_per_param_space( - |this| Decodable::decode(this).unwrap())) + |this| this.read_region_param_def(dcx))) }).unwrap(), }) }) @@ -1258,7 +1226,23 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { .parse_substs()) }).unwrap() } - + fn read_upvar_capture(&mut self, dcx: &DecodeContext) -> ty::UpvarCapture { + self.read_enum("UpvarCapture", |this| { + let variants = ["ByValue", "ByRef"]; + this.read_enum_variant(&variants, |this, i| { + Ok(match i { + 1 => ty::UpvarCapture::ByValue, + 2 => ty::UpvarCapture::ByRef(ty::UpvarBorrow { + kind: this.read_enum_variant_arg(0, + |this| Decodable::decode(this)).unwrap(), + region: this.read_enum_variant_arg(1, + |this| Ok(this.read_region(dcx))).unwrap() + }), + _ => panic!("bad enum variant for ty::UpvarCapture") + }) + }) + }).unwrap() + } fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::AutoAdjustment<'tcx> { self.read_enum("AutoAdjustment", |this| { @@ -1317,11 +1301,15 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { Ok(match i { 0 => { let r: ty::Region = - this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); + this.read_enum_variant_arg(0, |this| { + Ok(this.read_region(dcx)) + }).unwrap(); let m: ast::Mutability = - this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); + this.read_enum_variant_arg(1, |this| { + Decodable::decode(this) + }).unwrap(); - ty::AutoPtr(dcx.tcx.mk_region(r.tr(dcx)), m) + ty::AutoPtr(dcx.tcx.mk_region(r), m) } 1 => { let m: ast::Mutability = @@ -1376,6 +1364,9 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { /// case. We translate them with `tr_def_id()` which will map /// the crate numbers back to the original source crate. /// + /// Scopes will end up as being totally bogus. This can actually + /// be fixed through. + /// /// Unboxed closures are cloned along with the function being /// inlined, and all side tables use interned node IDs, so we /// translate their def IDs accordingly. @@ -1453,8 +1444,8 @@ fn decode_side_tables(dcx: &DecodeContext, var_id: dcx.tr_id(var_id), closure_expr_id: id }; - let ub: ty::UpvarCapture = Decodable::decode(val_dsr).unwrap(); - dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub.tr(dcx)); + let ub = val_dsr.read_upvar_capture(dcx); + dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub); } c::tag_table_tcache => { let type_scheme = val_dsr.read_type_scheme(dcx); diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index d4737f9d604d1..91e35c0679bf2 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -12,7 +12,6 @@ use rustc_data_structures::graph; use middle::cfg::*; use middle::def; use middle::pat_util; -use middle::region::CodeExtent; use middle::ty; use syntax::ast; use syntax::ast_util; @@ -585,11 +584,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { to_loop: LoopScope, to_index: CFGIndex) { let mut data = CFGEdgeData {exiting_scopes: vec!() }; - let mut scope = CodeExtent::from_node_id(from_expr.id); - let target_scope = CodeExtent::from_node_id(to_loop.loop_id); + let mut scope = self.tcx.region_maps.node_extent(from_expr.id); + let target_scope = self.tcx.region_maps.node_extent(to_loop.loop_id); while scope != target_scope { - - data.exiting_scopes.push(scope.node_id()); + data.exiting_scopes.push(scope.node_id(&self.tcx.region_maps)); scope = self.tcx.region_maps.encl_scope(scope); } self.graph.add_edge(from_index, to_index, data); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 30e8dfb293d1d..ce03e10418d2e 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -20,7 +20,7 @@ pub use self::MatchMode::*; use self::TrackMatchMode::*; use self::OverloadedCallType::*; -use middle::{def, region, pat_util}; +use middle::{def, pat_util}; use middle::def_id::{DefId}; use middle::infer; use middle::mem_categorization as mc; @@ -296,7 +296,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { for arg in &decl.inputs { let arg_ty = return_if_err!(self.typer.node_ty(arg.pat.id)); - let fn_body_scope = region::CodeExtent::from_node_id(body.id); + let fn_body_scope = self.tcx().region_maps.node_extent(body.id); let arg_cmt = self.mc.cat_rvalue( arg.id, arg.pat.span, @@ -579,7 +579,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { let callee_ty = return_if_err!(self.typer.expr_ty_adjusted(callee)); debug!("walk_callee: callee={:?} callee_ty={:?}", callee, callee_ty); - let call_scope = region::CodeExtent::from_node_id(call.id); + let call_scope = self.tcx().region_maps.node_extent(call.id); match callee_ty.sty { ty::TyBareFn(..) => { self.consume_expr(callee); @@ -862,7 +862,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { // Converting from a &T to *T (or &mut T to *mut T) is // treated as borrowing it for the enclosing temporary // scope. - let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id)); + let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id)); self.delegate.borrow(expr.id, expr.span, @@ -917,7 +917,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { // methods are implicitly autoref'd which sadly does not use // adjustments, so we must hardcode the borrow here. - let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id)); + let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id)); let bk = ty::ImmBorrow; for &arg in &rhs { diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 744ceb3701dba..4b81117f2e9a9 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -135,7 +135,8 @@ impl FreeRegionMap { tcx.region_maps.is_subscope_of(sub_scope, super_scope), (ty::ReScope(sub_scope), ty::ReFree(fr)) => - tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()) || + tcx.region_maps.is_subscope_of(sub_scope, + fr.scope.to_code_extent(&tcx.region_maps)) || self.is_static(fr), (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => @@ -177,4 +178,3 @@ fn lub() { map.relate_free_regions(frs[1], frs[2]); assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2])); } - diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index dca480b39c825..c7261b4a781c1 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -121,11 +121,11 @@ impl<'tcx> ty::ctxt<'tcx> { format!("{}unknown scope: {:?}{}. Please report a bug.", prefix, scope, suffix) }; - let span = match scope.span(&self.map) { + let span = match scope.span(&self.region_maps, &self.map) { Some(s) => s, None => return self.sess.note(&unknown_scope()) }; - let tag = match self.map.find(scope.node_id()) { + let tag = match self.map.find(scope.node_id(&self.region_maps)) { Some(ast_map::NodeBlock(_)) => "block", Some(ast_map::NodeExpr(expr)) => match expr.node { ast::ExprCall(..) => "call", @@ -142,16 +142,16 @@ impl<'tcx> ty::ctxt<'tcx> { return self.sess.span_note(span, &unknown_scope()); } }; - let scope_decorated_tag = match scope { - region::CodeExtent::Misc(_) => tag, - region::CodeExtent::ParameterScope { .. } => { + let scope_decorated_tag = match self.region_maps.code_extent_data(scope) { + region::CodeExtentData::Misc(_) => tag, + region::CodeExtentData::ParameterScope { .. } => { "scope of parameters for function" } - region::CodeExtent::DestructionScope(_) => { + region::CodeExtentData::DestructionScope(_) => { new_string = format!("destruction scope surrounding {}", tag); &new_string[..] } - region::CodeExtent::Remainder(r) => { + region::CodeExtentData::Remainder(r) => { new_string = format!("block suffix following statement {}", r.first_statement_index); &new_string[..] diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index d9265f78ccae0..4a6c30853df46 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -790,7 +790,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // A "free" region can be interpreted as "some region // at least as big as the block fr.scope_id". So, we can // reasonably compare free regions and scopes: - let fr_scope = fr.scope.to_code_extent(); + let fr_scope = fr.scope.to_code_extent(&self.tcx.region_maps); let r_id = self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id); if r_id == fr_scope { @@ -871,7 +871,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // than the scope `s_id`, then we can say that the GLB // is the scope `s_id`. Otherwise, as we do not know // big the free region is precisely, the GLB is undefined. - let fr_scope = fr.scope.to_code_extent(); + let fr_scope = fr.scope.to_code_extent(&self.tcx.region_maps); if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope || free_regions.is_static(fr) { Ok(s) @@ -927,8 +927,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { Ok(ty::ReFree(*b)) } else { this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b), - a.scope.to_code_extent(), - b.scope.to_code_extent()) + a.scope.to_code_extent(&this.tcx.region_maps), + b.scope.to_code_extent(&this.tcx.region_maps)) } } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 5ccbffa40a3f5..f4260dd700d65 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -20,16 +20,27 @@ use ast_map; use metadata::inline::InlinedItem; use middle::ty::{self, Ty}; use session::Session; -use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap}; +use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use std::cell::RefCell; +use std::collections::hash_map::Entry; +use std::mem; use syntax::codemap::{self, Span}; use syntax::{ast, visit}; use syntax::ast::{Block, Item, FnDecl, NodeId, Arm, Pat, Stmt, Expr, Local}; use syntax::ast_util::stmt_id; -use syntax::ptr::P; use syntax::visit::{Visitor, FnKind}; +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable, + RustcDecodable, Debug, Copy)] +pub struct CodeExtent(u32); + +/// The root of everything. I should be using NonZero or profiling +/// instead of this (probably). +pub const ROOT_CODE_EXTENT : CodeExtent = CodeExtent(0); +/// A placeholder used in trans to stand for real code extents +pub const DUMMY_CODE_EXTENT : CodeExtent = CodeExtent(1); + /// CodeExtent represents a statically-describable extent that can be /// used to bound the lifetime/region for values. /// @@ -91,9 +102,8 @@ use syntax::visit::{Visitor, FnKind}; /// placate the same deriving in `ty::FreeRegion`, but we may want to /// actually attach a more meaningful ordering to scopes than the one /// generated via deriving here. -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable, - RustcDecodable, Debug, Copy)] -pub enum CodeExtent { +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy)] +pub enum CodeExtentData { Misc(ast::NodeId), // extent of parameters passed to a function or closure (they @@ -118,8 +128,9 @@ impl DestructionScopeData { pub fn new(node_id: ast::NodeId) -> DestructionScopeData { DestructionScopeData { node_id: node_id } } - pub fn to_code_extent(&self) -> CodeExtent { - CodeExtent::DestructionScope(self.node_id) + pub fn to_code_extent(&self, region_maps: &RegionMaps) -> CodeExtent { + region_maps.lookup_code_extent( + CodeExtentData::DestructionScope(self.node_id)) } } @@ -134,9 +145,9 @@ impl DestructionScopeData { /// * the subscope with `first_statement_index == 0` is scope of both /// `a` and `b`; it does not include EXPR_1, but does include /// everything after that first `let`. (If you want a scope that -/// includes EXPR_1 as well, then do not use `CodeExtent::Remainder`, +/// includes EXPR_1 as well, then do not use `CodeExtentData::Remainder`, /// but instead another `CodeExtent` that encompasses the whole block, -/// e.g. `CodeExtent::Misc`. +/// e.g. `CodeExtentData::Misc`. /// /// * the subscope with `first_statement_index == 1` is scope of `c`, /// and thus does not include EXPR_2, but covers the `...`. @@ -147,58 +158,41 @@ pub struct BlockRemainder { pub first_statement_index: u32, } -impl CodeExtent { - /// Creates a scope that represents the dynamic extent associated - /// with `node_id`. - pub fn from_node_id(node_id: ast::NodeId) -> CodeExtent { - CodeExtent::Misc(node_id) - } - +impl CodeExtentData { /// Returns a node id associated with this scope. /// /// NB: likely to be replaced as API is refined; e.g. pnkfelix /// anticipates `fn entry_node_id` and `fn each_exit_node_id`. pub fn node_id(&self) -> ast::NodeId { match *self { - CodeExtent::Misc(node_id) => node_id, + CodeExtentData::Misc(node_id) => node_id, // These cases all return rough approximations to the // precise extent denoted by `self`. - CodeExtent::Remainder(br) => br.block, - CodeExtent::DestructionScope(node_id) => node_id, - CodeExtent::ParameterScope { fn_id: _, body_id } => body_id, + CodeExtentData::Remainder(br) => br.block, + CodeExtentData::DestructionScope(node_id) => node_id, + CodeExtentData::ParameterScope { fn_id: _, body_id } => body_id, } } +} - /// Maps this scope to a potentially new one according to the - /// NodeId transformer `f_id`. - pub fn map_id(&self, mut f_id: F) -> CodeExtent where - F: FnMut(ast::NodeId) -> ast::NodeId, - { - match *self { - CodeExtent::Misc(node_id) => CodeExtent::Misc(f_id(node_id)), - CodeExtent::Remainder(br) => - CodeExtent::Remainder(BlockRemainder { - block: f_id(br.block), first_statement_index: br.first_statement_index }), - CodeExtent::DestructionScope(node_id) => - CodeExtent::DestructionScope(f_id(node_id)), - CodeExtent::ParameterScope { fn_id, body_id } => - CodeExtent::ParameterScope { fn_id: f_id(fn_id), body_id: f_id(body_id) }, - } +impl CodeExtent { + pub fn node_id(&self, region_maps: &RegionMaps) -> ast::NodeId { + region_maps.code_extent_data(*self).node_id() } /// Returns the span of this CodeExtent. Note that in general the /// returned span may not correspond to the span of any node id in /// the AST. - pub fn span(&self, ast_map: &ast_map::Map) -> Option { - match ast_map.find(self.node_id()) { + pub fn span(&self, region_maps: &RegionMaps, ast_map: &ast_map::Map) -> Option { + match ast_map.find(self.node_id(region_maps)) { Some(ast_map::NodeBlock(ref blk)) => { - match *self { - CodeExtent::ParameterScope { .. } | - CodeExtent::Misc(_) | - CodeExtent::DestructionScope(_) => Some(blk.span), + match region_maps.code_extent_data(*self) { + CodeExtentData::ParameterScope { .. } | + CodeExtentData::Misc(_) | + CodeExtentData::DestructionScope(_) => Some(blk.span), - CodeExtent::Remainder(r) => { + CodeExtentData::Remainder(r) => { assert_eq!(r.block, blk.id); // Want span for extent starting after the // indexed statement and ending at end of @@ -222,13 +216,15 @@ impl CodeExtent { /// The region maps encode information about region relationships. pub struct RegionMaps { + code_extents: RefCell>, + code_extent_interner: RefCell>, /// `scope_map` maps from a scope id to the enclosing scope id; /// this is usually corresponding to the lexical nesting, though /// in the case of closures the parent scope is the innermost /// conditional expression or repeating block. (Note that the /// enclosing scope id for the block associated with a closure is /// the closure itself.) - scope_map: RefCell>, + scope_map: RefCell>, /// `var_map` maps from a variable or binding id to the block in /// which that variable is declared. @@ -242,26 +238,6 @@ pub struct RegionMaps { /// block (see `terminating_scopes`). rvalue_scopes: RefCell>, - /// `terminating_scopes` is a set containing the ids of each - /// statement, or conditional/repeating expression. These scopes - /// are calling "terminating scopes" because, when attempting to - /// find the scope of a temporary, by default we search up the - /// enclosing scopes until we encounter the terminating scope. A - /// conditional/repeating expression is one which is not - /// guaranteed to execute exactly once upon entering the parent - /// scope. This could be because the expression only executes - /// conditionally, such as the expression `b` in `a && b`, or - /// because the expression may execute many times, such as a loop - /// body. The reason that we distinguish such expressions is that, - /// upon exiting the parent scope, we cannot statically know how - /// many times the expression executed, and thus if the expression - /// creates temporaries we cannot know statically how many such - /// temporaries we would have to cleanup. Therefore we ensure that - /// the temporaries never outlast the conditional/repeating - /// expression, preventing the need for dynamic checks and/or - /// arbitrary amounts of stack space. - terminating_scopes: RefCell>, - /// Encodes the hierarchy of fn bodies. Every fn body (including /// closures) forms its own distinct region hierarchy, rooted in /// the block that is the fn body. This map points from the id of @@ -275,75 +251,6 @@ pub struct RegionMaps { fn_tree: RefCell>, } -/// Carries the node id for the innermost block or match expression, -/// for building up the `var_map` which maps ids to the blocks in -/// which they were declared. -#[derive(PartialEq, Eq, Debug, Copy, Clone)] -enum InnermostDeclaringBlock { - None, - Block(ast::NodeId), - Statement(DeclaringStatementContext), - Match(ast::NodeId), - FnDecl { fn_id: ast::NodeId, body_id: ast::NodeId }, -} - -impl InnermostDeclaringBlock { - fn to_code_extent(&self) -> Option { - let extent = match *self { - InnermostDeclaringBlock::None => { - return Option::None; - } - InnermostDeclaringBlock::FnDecl { fn_id, body_id } => - CodeExtent::ParameterScope { fn_id: fn_id, body_id: body_id }, - InnermostDeclaringBlock::Block(id) | - InnermostDeclaringBlock::Match(id) => CodeExtent::from_node_id(id), - InnermostDeclaringBlock::Statement(s) => s.to_code_extent(), - }; - Option::Some(extent) - } -} - -/// Contextual information for declarations introduced by a statement -/// (i.e. `let`). It carries node-id's for statement and enclosing -/// block both, as well as the statement's index within the block. -#[derive(PartialEq, Eq, Debug, Copy, Clone)] -struct DeclaringStatementContext { - stmt_id: ast::NodeId, - block_id: ast::NodeId, - stmt_index: u32, -} - -impl DeclaringStatementContext { - fn to_code_extent(&self) -> CodeExtent { - CodeExtent::Remainder(BlockRemainder { - block: self.block_id, - first_statement_index: self.stmt_index, - }) - } -} - -#[derive(PartialEq, Eq, Debug, Copy, Clone)] -enum InnermostEnclosingExpr { - None, - Some(ast::NodeId), - Statement(DeclaringStatementContext), -} - -impl InnermostEnclosingExpr { - fn to_code_extent(&self) -> Option { - let extent = match *self { - InnermostEnclosingExpr::None => { - return Option::None; - } - InnermostEnclosingExpr::Statement(s) => - s.to_code_extent(), - InnermostEnclosingExpr::Some(parent_id) => - CodeExtent::from_node_id(parent_id), - }; - Some(extent) - } -} - #[derive(Debug, Copy, Clone)] pub struct Context { /// the root of the current region tree. This is typically the id @@ -355,10 +262,10 @@ pub struct Context { root_id: Option, /// the scope that contains any new variables declared - var_parent: InnermostDeclaringBlock, + var_parent: CodeExtent, /// region parent of expressions etc - parent: InnermostEnclosingExpr, + parent: CodeExtent } struct RegionResolutionVisitor<'a> { @@ -367,14 +274,94 @@ struct RegionResolutionVisitor<'a> { // Generated maps: region_maps: &'a RegionMaps, - cx: Context + cx: Context, + + /// `terminating_scopes` is a set containing the ids of each + /// statement, or conditional/repeating expression. These scopes + /// are calling "terminating scopes" because, when attempting to + /// find the scope of a temporary, by default we search up the + /// enclosing scopes until we encounter the terminating scope. A + /// conditional/repeating expression is one which is not + /// guaranteed to execute exactly once upon entering the parent + /// scope. This could be because the expression only executes + /// conditionally, such as the expression `b` in `a && b`, or + /// because the expression may execute many times, such as a loop + /// body. The reason that we distinguish such expressions is that, + /// upon exiting the parent scope, we cannot statically know how + /// many times the expression executed, and thus if the expression + /// creates temporaries we cannot know statically how many such + /// temporaries we would have to cleanup. Therefore we ensure that + /// the temporaries never outlast the conditional/repeating + /// expression, preventing the need for dynamic checks and/or + /// arbitrary amounts of stack space. Terminating scopes end + /// up being contained in a DestructionScope that contains the + /// destructor's execution. + terminating_scopes: NodeSet } impl RegionMaps { + /// create a bogus code extent for the regions in astencode types. Nobody + /// really cares about the contents of these. + pub fn bogus_code_extent(&self, e: CodeExtentData) -> CodeExtent { + self.intern_code_extent(e, DUMMY_CODE_EXTENT) + } + pub fn lookup_code_extent(&self, e: CodeExtentData) -> CodeExtent { + self.code_extent_interner.borrow()[&e] + } + pub fn intern_code_extent(&self, + e: CodeExtentData, + parent: CodeExtent) -> CodeExtent { + match self.code_extent_interner.borrow_mut().entry(e) { + Entry::Occupied(o) => { + // this can happen when the bogus code extents from tydecode + // have (bogus) NodeId-s that overlap items created during + // inlining. + // We probably shouldn't be creating bogus code extents + // through. + let idx = *o.get(); + if parent == DUMMY_CODE_EXTENT { + info!("CodeExtent({}) = {:?} [parent={}] BOGUS!", + idx.0, e, parent.0); + } else { + assert_eq!(self.scope_map.borrow()[idx.0 as usize], + DUMMY_CODE_EXTENT); + info!("CodeExtent({}) = {:?} [parent={}] RECLAIMED!", + idx.0, e, parent.0); + self.scope_map.borrow_mut()[idx.0 as usize] = parent; + } + idx + } + Entry::Vacant(v) => { + if self.code_extents.borrow().len() > 0xffffffffusize { + unreachable!() // should pass a sess, + // but this isn't the only place + } + let idx = CodeExtent(self.code_extents.borrow().len() as u32); + info!("CodeExtent({}) = {:?} [parent={}]", idx.0, e, parent.0); + self.code_extents.borrow_mut().push(e); + self.scope_map.borrow_mut().push(parent); + *v.insert(idx) + } + } + } + pub fn intern_node(&self, + n: ast::NodeId, + parent: CodeExtent) -> CodeExtent { + self.intern_code_extent(CodeExtentData::Misc(n), parent) + } + pub fn node_extent(&self, n: ast::NodeId) -> CodeExtent { + self.lookup_code_extent(CodeExtentData::Misc(n)) + } + pub fn code_extent_data(&self, e: CodeExtent) -> CodeExtentData { + self.code_extents.borrow()[e.0 as usize] + } pub fn each_encl_scope(&self, mut e:E) where E: FnMut(&CodeExtent, &CodeExtent) { - for (child, parent) in self.scope_map.borrow().iter() { - e(child, parent) + for child_id in (1..self.code_extents.borrow().len()) { + let child = CodeExtent(child_id as u32); + if let Some(parent) = self.opt_encl_scope(child) { + e(&child, &parent) + } } } pub fn each_var_scope(&self, mut e:E) where E: FnMut(&ast::NodeId, &CodeExtent) { @@ -387,12 +374,6 @@ impl RegionMaps { e(child, parent) } } - pub fn each_terminating_scope(&self, mut e:E) where E: FnMut(&CodeExtent) { - for scope in self.terminating_scopes.borrow().iter() { - e(scope) - } - } - /// 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. @@ -414,44 +395,30 @@ impl RegionMaps { } } - pub fn record_encl_scope(&self, sub: CodeExtent, sup: CodeExtent) { - debug!("record_encl_scope(sub={:?}, sup={:?})", sub, sup); - assert!(sub != sup); - self.scope_map.borrow_mut().insert(sub, sup); - } - fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime); - assert!(var != lifetime.node_id()); + assert!(var != lifetime.node_id(self)); self.var_map.borrow_mut().insert(var, lifetime); } fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime); - assert!(var != lifetime.node_id()); + assert!(var != lifetime.node_id(self)); self.rvalue_scopes.borrow_mut().insert(var, lifetime); } - /// Records that a scope is a TERMINATING SCOPE. Whenever we create automatic temporaries -- - /// e.g. by an expression like `a().f` -- they will be freed within the innermost terminating - /// scope. - fn mark_as_terminating_scope(&self, scope_id: CodeExtent) { - debug!("record_terminating_scope(scope_id={:?})", scope_id); - self.terminating_scopes.borrow_mut().insert(scope_id); - } - pub fn opt_encl_scope(&self, id: CodeExtent) -> Option { //! Returns the narrowest scope that encloses `id`, if any. - self.scope_map.borrow().get(&id).cloned() + match self.scope_map.borrow()[id.0 as usize] { + ROOT_CODE_EXTENT => None, + c => Some(c) + } } #[allow(dead_code)] // used in middle::cfg pub fn encl_scope(&self, id: CodeExtent) -> CodeExtent { //! Returns the narrowest scope that encloses `id`, if any. - match self.scope_map.borrow().get(&id) { - Some(&r) => r, - None => { panic!("no enclosing scope for id {:?}", id); } - } + self.opt_encl_scope(id).unwrap() } /// Returns the lifetime of the local variable `var_id` @@ -478,24 +445,28 @@ impl RegionMaps { // if there's one. Static items, for instance, won't // have an enclosing scope, hence no scope will be // returned. - let mut id = match self.opt_encl_scope(CodeExtent::from_node_id(expr_id)) { + // For some reason, the expr's scope itself is skipped here. + let mut id = match self.opt_encl_scope(self.node_extent(expr_id)) { Some(i) => i, None => { return None; } }; - while !self.terminating_scopes.borrow().contains(&id) { - match self.opt_encl_scope(id) { - Some(p) => { - id = p; - } - None => { - debug!("temporary_scope({:?}) = None", expr_id); - return None; + loop { match self.opt_encl_scope(id) { + Some(p) => { + match self.code_extent_data(p) { + CodeExtentData::DestructionScope(..) => { + debug!("temporary_scope({:?}) = {:?} [enclosing]", + expr_id, id); + return Some(id); + } + _ => id = p } } - } - debug!("temporary_scope({:?}) = {:?} [enclosing]", expr_id, id); - return Some(id); + None => { + debug!("temporary_scope({:?}) = None", expr_id); + return None; + } + } } } pub fn var_region(&self, id: ast::NodeId) -> ty::Region { @@ -519,15 +490,15 @@ impl RegionMaps { superscope: CodeExtent) -> bool { let mut s = subscope; + debug!("is_subscope_of({:?}, {:?})", subscope, superscope); while superscope != s { - match self.scope_map.borrow().get(&s) { + match self.opt_encl_scope(s) { None => { debug!("is_subscope_of({:?}, {:?}, s={:?})=false", subscope, superscope, s); - return false; } - Some(&scope) => s = scope + Some(scope) => s = scope } } @@ -545,8 +516,15 @@ impl RegionMaps { -> CodeExtent { if scope_a == scope_b { return scope_a; } - let a_ancestors = ancestors_of(self, scope_a); - let b_ancestors = ancestors_of(self, scope_b); + let mut a_buf: [CodeExtent; 32] = [ROOT_CODE_EXTENT; 32]; + let mut a_vec: Vec = vec![]; + let mut b_buf: [CodeExtent; 32] = [ROOT_CODE_EXTENT; 32]; + let mut b_vec: Vec = vec![]; + let scope_map : &[CodeExtent] = &self.scope_map.borrow(); + let a_ancestors = ancestors_of(scope_map, + scope_a, &mut a_buf, &mut a_vec); + let b_ancestors = ancestors_of(scope_map, + scope_b, &mut b_buf, &mut b_vec); let mut a_index = a_ancestors.len() - 1; let mut b_index = b_ancestors.len() - 1; @@ -564,11 +542,11 @@ impl RegionMaps { // nesting. The reasoning behind this is subtle. See the // "Modeling closures" section of the README in // middle::infer::region_inference for more details. - let a_root_scope = a_ancestors[a_index]; - let b_root_scope = a_ancestors[a_index]; + let a_root_scope = self.code_extent_data(a_ancestors[a_index]); + let b_root_scope = self.code_extent_data(a_ancestors[a_index]); return match (a_root_scope, b_root_scope) { - (CodeExtent::DestructionScope(a_root_id), - CodeExtent::DestructionScope(b_root_id)) => { + (CodeExtentData::DestructionScope(a_root_id), + CodeExtentData::DestructionScope(b_root_id)) => { if self.fn_is_enclosed_by(a_root_id, b_root_id) { // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a` scope_b @@ -599,47 +577,52 @@ impl RegionMaps { } } - fn ancestors_of(this: &RegionMaps, scope: CodeExtent) -> Vec { + fn ancestors_of<'a>(scope_map: &[CodeExtent], + scope: CodeExtent, + buf: &'a mut [CodeExtent; 32], + vec: &'a mut Vec) -> &'a [CodeExtent] { // debug!("ancestors_of(scope={:?})", scope); - let mut result = vec!(scope); let mut scope = scope; + + let mut i = 0; + while i < 32 { + buf[i] = scope; + let superscope = scope_map[scope.0 as usize]; + if superscope == ROOT_CODE_EXTENT { + return &buf[..i+1]; + } else { + scope = superscope; + } + i += 1; + } + + *vec = Vec::with_capacity(64); + vec.extend((*buf).into_iter()); loop { - match this.scope_map.borrow().get(&scope) { - None => return result, - Some(&superscope) => { - result.push(superscope); - scope = superscope; - } + vec.push(scope); + let superscope = scope_map[scope.0 as usize]; + if superscope == ROOT_CODE_EXTENT { + return &*vec; + } else { + scope = superscope; } - // debug!("ancestors_of_loop(scope={:?})", scope); } } } } -/// Records the current parent (if any) as the parent of `child_scope`. -fn record_superlifetime(visitor: &mut RegionResolutionVisitor, - child_scope: CodeExtent, - _sp: Span) { - match visitor.cx.parent.to_code_extent() { - Some(parent_scope) => - visitor.region_maps.record_encl_scope(child_scope, parent_scope), - None => {} - } -} - /// Records the lifetime of a local variable as `cx.var_parent` fn record_var_lifetime(visitor: &mut RegionResolutionVisitor, var_id: ast::NodeId, _sp: Span) { - match visitor.cx.var_parent.to_code_extent() { - Some(parent_scope) => - visitor.region_maps.record_var_scope(var_id, parent_scope), - None => { + match visitor.cx.var_parent { + ROOT_CODE_EXTENT => { // this can happen in extern fn declarations like // // extern fn isalnum(c: c_int) -> c_int } + parent_scope => + visitor.region_maps.record_var_scope(var_id, parent_scope), } } @@ -647,21 +630,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) { debug!("resolve_block(blk.id={:?})", blk.id); let prev_cx = visitor.cx; - - let blk_scope = CodeExtent::Misc(blk.id); - - // If block was previously marked as a terminating scope during - // the recursive visit of its parent node in the AST, then we need - // to account for the destruction scope representing the extent of - // the destructors that run immediately after the the block itself - // completes. - if visitor.region_maps.terminating_scopes.borrow().contains(&blk_scope) { - let dtor_scope = CodeExtent::DestructionScope(blk.id); - record_superlifetime(visitor, dtor_scope, blk.span); - visitor.region_maps.record_encl_scope(blk_scope, dtor_scope); - } else { - record_superlifetime(visitor, blk_scope, blk.span); - } + let block_extent = visitor.new_node_extent_with_dtor(blk.id); // We treat the tail expression in the block (if any) somewhat // differently from the statements. The issue has to do with @@ -690,35 +659,34 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) { visitor.cx = Context { root_id: prev_cx.root_id, - var_parent: InnermostDeclaringBlock::Block(blk.id), - parent: InnermostEnclosingExpr::Some(blk.id), + var_parent: block_extent, + parent: block_extent, }; { // This block should be kept approximately in sync with // `visit::walk_block`. (We manually walk the block, rather // than call `walk_block`, in order to maintain precise - // `InnermostDeclaringBlock` information.) + // index information.) for (i, statement) in blk.stmts.iter().enumerate() { - if let ast::StmtDecl(_, stmt_id) = statement.node { + if let ast::StmtDecl(..) = statement.node { // Each StmtDecl introduces a subscope for bindings // introduced by the declaration; this subscope covers // a suffix of the block . Each subscope in a block // has the previous subscope in the block as a parent, // except for the first such subscope, which has the // block itself as a parent. - let declaring = DeclaringStatementContext { - stmt_id: stmt_id, - block_id: blk.id, - stmt_index: i as u32, - }; - record_superlifetime( - visitor, declaring.to_code_extent(), statement.span); + let stmt_extent = visitor.new_code_extent( + CodeExtentData::Remainder(BlockRemainder { + block: blk.id, + first_statement_index: i as u32 + }) + ); visitor.cx = Context { root_id: prev_cx.root_id, - var_parent: InnermostDeclaringBlock::Statement(declaring), - parent: InnermostEnclosingExpr::Statement(declaring), + var_parent: stmt_extent, + parent: stmt_extent, }; } visitor.visit_stmt(&**statement) @@ -730,22 +698,17 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) { } fn resolve_arm(visitor: &mut RegionResolutionVisitor, arm: &ast::Arm) { - let arm_body_scope = CodeExtent::from_node_id(arm.body.id); - visitor.region_maps.mark_as_terminating_scope(arm_body_scope); + visitor.terminating_scopes.insert(arm.body.id); - match arm.guard { - Some(ref expr) => { - let guard_scope = CodeExtent::from_node_id(expr.id); - visitor.region_maps.mark_as_terminating_scope(guard_scope); - } - None => { } + if let Some(ref expr) = arm.guard { + visitor.terminating_scopes.insert(expr.id); } visit::walk_arm(visitor, arm); } fn resolve_pat(visitor: &mut RegionResolutionVisitor, pat: &ast::Pat) { - record_superlifetime(visitor, CodeExtent::from_node_id(pat.id), pat.span); + visitor.new_node_extent(pat.id); // If this is a binding (or maybe a binding, I'm too lazy to check // the def map) then record the lifetime of that binding. @@ -763,20 +726,16 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) { let stmt_id = stmt_id(stmt); debug!("resolve_stmt(stmt.id={:?})", stmt_id); - let stmt_scope = CodeExtent::from_node_id(stmt_id); - // Every statement will clean up the temporaries created during // execution of that statement. Therefore each statement has an // associated destruction scope that represents the extent of the // statement plus its destructors, and thus the extent for which // regions referenced by the destructors need to survive. - visitor.region_maps.mark_as_terminating_scope(stmt_scope); - let dtor_scope = CodeExtent::DestructionScope(stmt_id); - visitor.region_maps.record_encl_scope(stmt_scope, dtor_scope); - record_superlifetime(visitor, dtor_scope, stmt.span); + visitor.terminating_scopes.insert(stmt_id); + let stmt_extent = visitor.new_node_extent_with_dtor(stmt_id); let prev_parent = visitor.cx.parent; - visitor.cx.parent = InnermostEnclosingExpr::Some(stmt_id); + visitor.cx.parent = stmt_extent; visit::walk_stmt(visitor, stmt); visitor.cx.parent = prev_parent; } @@ -784,32 +743,14 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) { fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { debug!("resolve_expr(expr.id={:?})", expr.id); - let expr_scope = CodeExtent::Misc(expr.id); - // If expr was previously marked as a terminating scope during the - // recursive visit of its parent node in the AST, then we need to - // account for the destruction scope representing the extent of - // the destructors that run immediately after the the expression - // itself completes. - if visitor.region_maps.terminating_scopes.borrow().contains(&expr_scope) { - let dtor_scope = CodeExtent::DestructionScope(expr.id); - record_superlifetime(visitor, dtor_scope, expr.span); - visitor.region_maps.record_encl_scope(expr_scope, dtor_scope); - } else { - record_superlifetime(visitor, expr_scope, expr.span); - } - + let expr_extent = visitor.new_node_extent_with_dtor(expr.id); let prev_cx = visitor.cx; - visitor.cx.parent = InnermostEnclosingExpr::Some(expr.id); + visitor.cx.parent = expr_extent; { - let region_maps = &mut visitor.region_maps; - let terminating = |e: &P| { - let scope = CodeExtent::from_node_id(e.id); - region_maps.mark_as_terminating_scope(scope) - }; - let terminating_block = |b: &P| { - let scope = CodeExtent::from_node_id(b.id); - region_maps.mark_as_terminating_scope(scope) + let terminating_scopes = &mut visitor.terminating_scopes; + let mut terminating = |id: ast::NodeId| { + terminating_scopes.insert(id); }; match expr.node { // Conditional or repeating scopes are always terminating @@ -820,30 +761,30 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { ast::ExprBinary(codemap::Spanned { node: ast::BiOr, .. }, _, ref r) => { // For shortcircuiting operators, mark the RHS as a terminating // scope since it only executes conditionally. - terminating(r); + terminating(r.id); } ast::ExprIf(_, ref then, Some(ref otherwise)) => { - terminating_block(then); - terminating(otherwise); + terminating(then.id); + terminating(otherwise.id); } ast::ExprIf(ref expr, ref then, None) => { - terminating(expr); - terminating_block(then); + terminating(expr.id); + terminating(then.id); } ast::ExprLoop(ref body, _) => { - terminating_block(body); + terminating(body.id); } ast::ExprWhile(ref expr, ref body, _) => { - terminating(expr); - terminating_block(body); + terminating(expr.id); + terminating(body.id); } ast::ExprMatch(..) => { - visitor.cx.var_parent = InnermostDeclaringBlock::Match(expr.id); + visitor.cx.var_parent = expr_extent; } ast::ExprAssignOp(..) | ast::ExprIndex(..) | @@ -883,10 +824,8 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) { // For convenience in trans, associate with the local-id the var // scope that will be used for any bindings declared in this // pattern. - let blk_scope = visitor.cx.var_parent.to_code_extent() - .unwrap_or_else(|| visitor.sess.span_bug( - local.span, "local without enclosing block")); - + let blk_scope = visitor.cx.var_parent; + assert!(blk_scope != ROOT_CODE_EXTENT); // locals must be within a block visitor.region_maps.record_var_scope(local.id, blk_scope); // As an exception to the normal rules governing temporary @@ -1109,13 +1048,16 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) { fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &ast::Item) { // Items create a new outer block scope as far as we're concerned. let prev_cx = visitor.cx; + let prev_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet()); visitor.cx = Context { root_id: None, - var_parent: InnermostDeclaringBlock::None, - parent: InnermostEnclosingExpr::None + var_parent: ROOT_CODE_EXTENT, + parent: ROOT_CODE_EXTENT }; visit::walk_item(visitor, item); + visitor.create_item_scope_if_needed(item.id); visitor.cx = prev_cx; + visitor.terminating_scopes = prev_ts; } fn resolve_fn(visitor: &mut RegionResolutionVisitor, @@ -1133,51 +1075,76 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, body.id, visitor.cx.parent); - // This scope covers the function body, which includes the - // bindings introduced by let statements as well as temporaries - // created by the fn's tail expression (if any). It does *not* - // include the fn parameters (see below). - let body_scope = CodeExtent::from_node_id(body.id); - visitor.region_maps.mark_as_terminating_scope(body_scope); - - let dtor_scope = CodeExtent::DestructionScope(body.id); - visitor.region_maps.record_encl_scope(body_scope, dtor_scope); - - let fn_decl_scope = CodeExtent::ParameterScope { fn_id: id, body_id: body.id }; - visitor.region_maps.record_encl_scope(dtor_scope, fn_decl_scope); - - record_superlifetime(visitor, fn_decl_scope, body.span); + let fn_decl_scope = visitor.new_code_extent( + CodeExtentData::ParameterScope { fn_id: id, body_id: body.id }); if let Some(root_id) = visitor.cx.root_id { visitor.region_maps.record_fn_parent(body.id, root_id); } let outer_cx = visitor.cx; + let outer_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet()); + visitor.terminating_scopes.insert(body.id); // The arguments and `self` are parented to the fn. visitor.cx = Context { root_id: Some(body.id), - parent: InnermostEnclosingExpr::None, - var_parent: InnermostDeclaringBlock::FnDecl { - fn_id: id, body_id: body.id - }, + parent: ROOT_CODE_EXTENT, + var_parent: fn_decl_scope, }; + visit::walk_fn_decl(visitor, decl); // The body of the every fn is a root scope. visitor.cx = Context { root_id: Some(body.id), - parent: InnermostEnclosingExpr::None, - var_parent: InnermostDeclaringBlock::None + parent: fn_decl_scope, + var_parent: fn_decl_scope }; visitor.visit_block(body); // Restore context we had at the start. visitor.cx = outer_cx; + visitor.terminating_scopes = outer_ts; } -impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> { +impl<'a> RegionResolutionVisitor<'a> { + /// Records the current parent (if any) as the parent of `child_scope`. + fn new_code_extent(&mut self, child_scope: CodeExtentData) -> CodeExtent { + self.region_maps.intern_code_extent(child_scope, self.cx.parent) + } + fn new_node_extent(&mut self, child_scope: ast::NodeId) -> CodeExtent { + self.new_code_extent(CodeExtentData::Misc(child_scope)) + } + + fn new_node_extent_with_dtor(&mut self, id: ast::NodeId) -> CodeExtent { + // If node was previously marked as a terminating scope during the + // recursive visit of its parent node in the AST, then we need to + // account for the destruction scope representing the extent of + // the destructors that run immediately after it completes. + if self.terminating_scopes.contains(&id) { + let ds = self.new_code_extent( + CodeExtentData::DestructionScope(id)); + self.region_maps.intern_node(id, ds) + } else { + self.new_node_extent(id) + } + } + + fn create_item_scope_if_needed(&mut self, id: ast::NodeId) { + // create a region for the destruction scope - this is needed + // for constructing parameter environments based on the item. + // functions put their destruction scopes *inside* their parameter + // scopes. + let scope = CodeExtentData::DestructionScope(id); + if !self.region_maps.code_extent_interner.borrow().contains_key(&scope) { + self.region_maps.intern_code_extent(scope, ROOT_CODE_EXTENT); + } + } +} + +impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> { fn visit_block(&mut self, b: &Block) { resolve_block(self, b); } @@ -1186,6 +1153,16 @@ impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> { resolve_item(self, i); } + fn visit_impl_item(&mut self, ii: &ast::ImplItem) { + visit::walk_impl_item(self, ii); + self.create_item_scope_if_needed(ii.id); + } + + fn visit_trait_item(&mut self, ti: &ast::TraitItem) { + visit::walk_trait_item(self, ti); + self.create_item_scope_if_needed(ti.id); + } + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, n: NodeId) { resolve_fn(self, fk, fd, b, s, n); @@ -1209,21 +1186,29 @@ impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> { pub fn resolve_crate(sess: &Session, krate: &ast::Crate) -> RegionMaps { let maps = RegionMaps { - scope_map: RefCell::new(FnvHashMap()), + code_extents: RefCell::new(vec![]), + code_extent_interner: RefCell::new(FnvHashMap()), + scope_map: RefCell::new(vec![]), var_map: RefCell::new(NodeMap()), rvalue_scopes: RefCell::new(NodeMap()), - terminating_scopes: RefCell::new(FnvHashSet()), fn_tree: RefCell::new(NodeMap()), }; + let root_extent = maps.bogus_code_extent( + CodeExtentData::DestructionScope(ast::DUMMY_NODE_ID)); + assert_eq!(root_extent, ROOT_CODE_EXTENT); + let bogus_extent = maps.bogus_code_extent( + CodeExtentData::Misc(ast::DUMMY_NODE_ID)); + assert_eq!(bogus_extent, DUMMY_CODE_EXTENT); { let mut visitor = RegionResolutionVisitor { sess: sess, region_maps: &maps, cx: Context { root_id: None, - parent: InnermostEnclosingExpr::None, - var_parent: InnermostDeclaringBlock::None, - } + parent: ROOT_CODE_EXTENT, + var_parent: ROOT_CODE_EXTENT + }, + terminating_scopes: NodeSet() }; visit::walk_crate(&mut visitor, krate); } @@ -1238,9 +1223,10 @@ pub fn resolve_inlined_item(sess: &Session, region_maps: region_maps, cx: Context { root_id: None, - parent: InnermostEnclosingExpr::None, - var_parent: InnermostDeclaringBlock::None - } + parent: ROOT_CODE_EXTENT, + var_parent: ROOT_CODE_EXTENT + }, + terminating_scopes: NodeSet() }; item.visit(&mut visitor); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 52d76d277792e..a18bff5591dd1 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1503,7 +1503,7 @@ pub struct DebruijnIndex { } /// Representation of regions: -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Copy)] +#[derive(Clone, PartialEq, Eq, Hash, Copy)] pub enum Region { // Region bound in a type or fn declaration which will be // substituted 'early' -- that is, at the same time when type @@ -1609,7 +1609,7 @@ pub enum BorrowKind { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Debug, Copy)] +#[derive(PartialEq, Clone, Debug, Copy)] pub enum UpvarCapture { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases @@ -1620,7 +1620,7 @@ pub enum UpvarCapture { ByRef(UpvarBorrow), } -#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Copy)] +#[derive(PartialEq, Clone, Copy)] pub struct UpvarBorrow { /// The kind of borrow: by-ref upvars have access to shared /// immutable borrows, which are not part of the normal language @@ -2271,7 +2271,7 @@ pub struct TypeParameterDef<'tcx> { pub object_lifetime_default: ObjectLifetimeDefault, } -#[derive(RustcEncodable, RustcDecodable, Clone, Debug)] +#[derive(Clone, Debug)] pub struct RegionParameterDef { pub name: ast::Name, pub def_id: DefId, @@ -6673,7 +6673,8 @@ impl<'tcx> ctxt<'tcx> { let unnormalized_env = ty::ParameterEnvironment { tcx: self, free_substs: free_substs, - implicit_region_bound: ty::ReScope(free_id_outlive.to_code_extent()), + implicit_region_bound: ty::ReScope( + free_id_outlive.to_code_extent(&self.region_maps)), caller_bounds: predicates, selection_cache: traits::SelectionCache::new(), free_id: free_id, diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 62cb1f73cf853..3e3ce5c7be002 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { None => { } } - self.check_for_conflicting_loans(region::CodeExtent::from_node_id(borrow_id)); + self.check_for_conflicting_loans(borrow_id); } fn mutate(&mut self, @@ -230,16 +230,16 @@ fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind, impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.bccx.tcx } - pub fn each_issued_loan(&self, scope: region::CodeExtent, mut op: F) -> bool where + pub fn each_issued_loan(&self, node: ast::NodeId, mut op: F) -> bool where F: FnMut(&Loan<'tcx>) -> bool, { //! Iterates over each loan that has been issued - //! on entrance to `scope`, regardless of whether it is + //! on entrance to `node`, regardless of whether it is //! actually *in scope* at that point. Sometimes loans //! are issued for future scopes and thus they may have been //! *issued* but not yet be in effect. - self.dfcx_loans.each_bit_on_entry(scope.node_id(), |loan_index| { + self.dfcx_loans.each_bit_on_entry(node, |loan_index| { let loan = &self.all_loans[loan_index]; op(loan) }) @@ -252,7 +252,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { //! currently in scope. let tcx = self.tcx(); - self.each_issued_loan(scope, |loan| { + self.each_issued_loan(scope.node_id(&tcx.region_maps), |loan| { if tcx.region_maps.is_subscope_of(scope, loan.kill_scope) { op(loan) } else { @@ -336,33 +336,33 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { return true; } - pub fn loans_generated_by(&self, scope: region::CodeExtent) -> Vec { + pub fn loans_generated_by(&self, node: ast::NodeId) -> Vec { //! Returns a vector of the loans that are generated as - //! we enter `scope`. + //! we enter `node`. let mut result = Vec::new(); - self.dfcx_loans.each_gen_bit(scope.node_id(), |loan_index| { + self.dfcx_loans.each_gen_bit(node, |loan_index| { result.push(loan_index); true }); return result; } - pub fn check_for_conflicting_loans(&self, scope: region::CodeExtent) { + pub fn check_for_conflicting_loans(&self, node: ast::NodeId) { //! Checks to see whether any of the loans that are issued - //! on entrance to `scope` conflict with loans that have already been - //! issued when we enter `scope` (for example, we do not + //! on entrance to `node` conflict with loans that have already been + //! issued when we enter `node` (for example, we do not //! permit two `&mut` borrows of the same variable). //! //! (Note that some loans can be *issued* without necessarily //! taking effect yet.) - debug!("check_for_conflicting_loans(scope={:?})", scope); + debug!("check_for_conflicting_loans(node={:?})", node); - let new_loan_indices = self.loans_generated_by(scope); + let new_loan_indices = self.loans_generated_by(node); debug!("new_loan_indices = {:?}", new_loan_indices); - self.each_issued_loan(scope, |issued_loan| { + self.each_issued_loan(node, |issued_loan| { for &new_loan_index in &new_loan_indices { let new_loan = &self.all_loans[new_loan_index]; self.report_error_if_loans_conflict(issued_loan, new_loan); @@ -557,7 +557,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { old_loan.span, &format!("{}; {}", borrow_summary, rule_summary)); - let old_loan_span = self.tcx().map.span(old_loan.kill_scope.node_id()); + let old_loan_span = self.tcx().map.span( + old_loan.kill_scope.node_id(&self.tcx().region_maps)); self.bccx.span_end_note(old_loan_span, "previous borrow ends here"); @@ -673,7 +674,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { let mut ret = UseOk; self.each_in_scope_loan_affecting_path( - region::CodeExtent::from_node_id(expr_id), use_path, |loan| { + self.tcx().region_maps.node_extent(expr_id), use_path, |loan| { if !compatible_borrow_kinds(loan.kind, borrow_kind) { ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span); false @@ -787,7 +788,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // Check that we don't invalidate any outstanding loans if let Some(loan_path) = opt_loan_path(&assignee_cmt) { - let scope = region::CodeExtent::from_node_id(assignment_id); + let scope = self.tcx().region_maps.node_extent(assignment_id); self.each_in_scope_loan_affecting_path(scope, &*loan_path, |loan| { self.report_illegal_mutation(assignment_span, &*loan_path, loan); false diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index d1e75afad454b..c3801f436e582 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -44,7 +44,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, let mut glcx = GatherLoanCtxt { bccx: bccx, all_loans: Vec::new(), - item_ub: region::CodeExtent::from_node_id(body.id), + item_ub: bccx.tcx.region_maps.node_extent(body.id), move_data: MoveData::new(), move_error_collector: move_error::MoveErrorCollector::new(), }; @@ -360,7 +360,9 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { let loan_scope = match loan_region { ty::ReScope(scope) => scope, - ty::ReFree(ref fr) => fr.scope.to_code_extent(), + ty::ReFree(ref fr) => { + fr.scope.to_code_extent(&self.tcx().region_maps) + } ty::ReStatic => { // If we get here, an error must have been @@ -387,7 +389,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { }; debug!("loan_scope = {:?}", loan_scope); - let borrow_scope = region::CodeExtent::from_node_id(borrow_id); + let borrow_scope = self.tcx().region_maps.node_extent(borrow_id); let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope); debug!("gen_scope = {:?}", gen_scope); diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 187d4b4e5deb9..9a684021fcdd3 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -191,6 +191,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, -> AnalysisData<'a, 'tcx> { // Check the body of fn items. + let tcx = this.tcx; let id_range = ast_util::compute_id_range_for_fn_body(fk, decl, body, sp, id); let (all_loans, move_data) = gather_loans::gather_loans_in_fn(this, id, decl, body); @@ -204,8 +205,9 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, id_range, all_loans.len()); for (loan_idx, loan) in all_loans.iter().enumerate() { - loan_dfcx.add_gen(loan.gen_scope.node_id(), loan_idx); - loan_dfcx.add_kill(KillFrom::ScopeEnd, loan.kill_scope.node_id(), loan_idx); + loan_dfcx.add_gen(loan.gen_scope.node_id(&tcx.region_maps), loan_idx); + loan_dfcx.add_kill(KillFrom::ScopeEnd, + loan.kill_scope.node_id(&tcx.region_maps), loan_idx); } loan_dfcx.add_kills_from_flow_exits(cfg); loan_dfcx.propagate(cfg, body); @@ -414,7 +416,7 @@ impl<'tcx> LoanPath<'tcx> { LpVar(local_id) => tcx.region_maps.var_scope(local_id), LpUpvar(upvar_id) => { let block_id = closure_to_block(upvar_id.closure_expr_id, tcx); - region::CodeExtent::from_node_id(block_id) + tcx.region_maps.node_extent(block_id) } LpDowncast(ref base, _) | LpExtend(ref base, _, _) => base.kill_scope(tcx), @@ -1135,7 +1137,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { fn statement_scope_span(tcx: &ty::ctxt, region: ty::Region) -> Option { match region { ty::ReScope(scope) => { - match tcx.map.find(scope.node_id()) { + match tcx.map.find(scope.node_id(&tcx.region_maps)) { Some(ast_map::NodeStmt(stmt)) => Some(stmt.span), _ => None } diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index ec25dcc7e8376..a389095df7911 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -494,7 +494,7 @@ impl<'tcx> MoveData<'tcx> { LpVar(..) | LpUpvar(..) | LpDowncast(..) => { let kill_scope = path.loan_path.kill_scope(tcx); let path = *self.path_map.borrow().get(&path.loan_path).unwrap(); - self.kill_moves(path, kill_scope.node_id(), + self.kill_moves(path, kill_scope.node_id(&tcx.region_maps), KillFrom::ScopeEnd, dfcx_moves); } LpExtend(..) => {} @@ -509,7 +509,7 @@ impl<'tcx> MoveData<'tcx> { LpVar(..) | LpUpvar(..) | LpDowncast(..) => { let kill_scope = lp.kill_scope(tcx); dfcx_assign.add_kill(KillFrom::ScopeEnd, - kill_scope.node_id(), + kill_scope.node_id(&tcx.region_maps), assignment_index); } LpExtend(..) => { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 7d50395aca3af..dcc92efc2a2ca 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -18,6 +18,7 @@ use rustc_resolve as resolve; use rustc_typeck::middle::lang_items; use rustc_typeck::middle::free_region::FreeRegionMap; use rustc_typeck::middle::region::{self, CodeExtent, DestructionScopeData}; +use rustc_typeck::middle::region::CodeExtentData; use rustc_typeck::middle::resolve_lifetime; use rustc_typeck::middle::stability; use rustc_typeck::middle::subst; @@ -153,24 +154,25 @@ impl<'a, 'tcx> Env<'a, 'tcx> { self.infcx.tcx } - pub fn create_region_hierarchy(&self, rh: &RH) { + pub fn create_region_hierarchy(&self, rh: &RH, parent: CodeExtent) { + let me = self.infcx.tcx.region_maps.intern_node(rh.id, parent); for child_rh in rh.sub { - self.create_region_hierarchy(child_rh); - self.infcx.tcx.region_maps.record_encl_scope( - CodeExtent::from_node_id(child_rh.id), - CodeExtent::from_node_id(rh.id)); + self.create_region_hierarchy(child_rh, me); } } pub fn create_simple_region_hierarchy(&self) { // creates a region hierarchy where 1 is root, 10 and 11 are // children of 1, etc + let dscope = self.infcx.tcx.region_maps.intern_code_extent( + CodeExtentData::DestructionScope(1), region::ROOT_CODE_EXTENT); self.create_region_hierarchy( &RH {id: 1, sub: &[RH {id: 10, sub: &[]}, RH {id: 11, - sub: &[]}]}); + sub: &[]}]}, + dscope); } #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now @@ -321,7 +323,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> { - let r = ty::ReScope(CodeExtent::from_node_id(id)); + let r = ty::ReScope(self.tcx().region_maps.node_extent(id)); self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) } @@ -462,7 +464,8 @@ fn sub_free_bound_false() { //! does NOT hold. test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_rptr_free1 = env.t_rptr_free(0, 1); + env.create_simple_region_hierarchy(); + let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_bound1 = env.t_rptr_late_bound(1); env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); @@ -478,8 +481,9 @@ fn sub_bound_free_true() { //! DOES hold. test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + env.create_simple_region_hierarchy(); let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_free1 = env.t_rptr_free(0, 1); + let t_rptr_free1 = env.t_rptr_free(1, 1); env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); }) @@ -512,9 +516,10 @@ fn lub_free_bound_infer() { //! anyhow. test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + env.create_simple_region_hierarchy(); let t_infer1 = env.infcx.next_ty_var(); let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_free1 = env.t_rptr_free(0, 1); + let t_rptr_free1 = env.t_rptr_free(1, 1); env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize), env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); @@ -535,8 +540,9 @@ fn lub_bound_bound() { #[test] fn lub_bound_free() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + env.create_simple_region_hierarchy(); let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_free1 = env.t_rptr_free(0, 1); + let t_rptr_free1 = env.t_rptr_free(1, 1); env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), env.t_fn(&[t_rptr_free1], env.tcx().types.isize), env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); @@ -568,8 +574,9 @@ fn lub_bound_bound_inverse_order() { #[test] fn lub_free_free() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_rptr_free1 = env.t_rptr_free(0, 1); - let t_rptr_free2 = env.t_rptr_free(0, 2); + env.create_simple_region_hierarchy(); + let t_rptr_free1 = env.t_rptr_free(1, 1); + let t_rptr_free2 = env.t_rptr_free(1, 2); let t_rptr_static = env.t_rptr_static(); env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), env.t_fn(&[t_rptr_free2], env.tcx().types.isize), @@ -594,9 +601,10 @@ fn lub_returning_scope() { #[test] fn glb_free_free_with_common_scope() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_rptr_free1 = env.t_rptr_free(0, 1); - let t_rptr_free2 = env.t_rptr_free(0, 2); - let t_rptr_scope = env.t_rptr_scope(0); + env.create_simple_region_hierarchy(); + let t_rptr_free1 = env.t_rptr_free(1, 1); + let t_rptr_free2 = env.t_rptr_free(1, 2); + let t_rptr_scope = env.t_rptr_scope(1); env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), env.t_fn(&[t_rptr_free2], env.tcx().types.isize), env.t_fn(&[t_rptr_scope], env.tcx().types.isize)); @@ -617,8 +625,9 @@ fn glb_bound_bound() { #[test] fn glb_bound_free() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + env.create_simple_region_hierarchy(); let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_rptr_free1 = env.t_rptr_free(0, 1); + let t_rptr_free1 = env.t_rptr_free(1, 1); env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), env.t_fn(&[t_rptr_free1], env.tcx().types.isize), env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); @@ -738,10 +747,11 @@ fn escaping() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { // Situation: // Theta = [A -> &'a foo] + env.create_simple_region_hierarchy(); assert!(!env.t_nil().has_escaping_regions()); - let t_rptr_free1 = env.t_rptr_free(0, 1); + let t_rptr_free1 = env.t_rptr_free(1, 1); assert!(!t_rptr_free1.has_escaping_regions()); let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)); diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 5e472e45775d0..ecfbaf5790306 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -253,18 +253,16 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { // now we just say that if there is already an AST scope on the stack, // this new AST scope had better be its immediate child. let top_scope = self.top_ast_scope(); + let region_maps = &self.ccx.tcx().region_maps; if top_scope.is_some() { - assert!((self.ccx - .tcx() - .region_maps - .opt_encl_scope(region::CodeExtent::from_node_id(debug_loc.id)) - .map(|s|s.node_id()) == top_scope) + assert!((region_maps + .opt_encl_scope(region_maps.node_extent(debug_loc.id)) + .map(|s|s.node_id(region_maps)) == top_scope) || - (self.ccx - .tcx() - .region_maps - .opt_encl_scope(region::CodeExtent::DestructionScope(debug_loc.id)) - .map(|s|s.node_id()) == top_scope)); + (region_maps + .opt_encl_scope(region_maps.lookup_code_extent( + region::CodeExtentData::DestructionScope(debug_loc.id))) + .map(|s|s.node_id(region_maps)) == top_scope)); } self.push_scope(CleanupScope::new(AstScopeKind(debug_loc.id), @@ -1111,7 +1109,7 @@ pub fn temporary_scope(tcx: &ty::ctxt, -> ScopeId { match tcx.region_maps.temporary_scope(id) { Some(scope) => { - let r = AstScope(scope.node_id()); + let r = AstScope(scope.node_id(&tcx.region_maps)); debug!("temporary_scope({}) = {:?}", id, r); r } @@ -1125,7 +1123,7 @@ pub fn temporary_scope(tcx: &ty::ctxt, pub fn var_scope(tcx: &ty::ctxt, id: ast::NodeId) -> ScopeId { - let r = AstScope(tcx.region_maps.var_scope(id).node_id()); + let r = AstScope(tcx.region_maps.var_scope(id).node_id(&tcx.region_maps)); debug!("var_scope({}) = {:?}", id, r); r } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 156aa14bebf58..847cbfdbec623 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -294,7 +294,9 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { let old_body_id = self.set_body_id(body.id); self.relate_free_regions(&fn_sig[..], body.id, span); - link_fn_args(self, CodeExtent::from_node_id(body.id), &fn_decl.inputs[..]); + link_fn_args(self, + self.tcx().region_maps.node_extent(body.id), + &fn_decl.inputs[..]); self.visit_block(body); self.visit_region_obligations(body.id); @@ -564,17 +566,15 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // No matter what, the type of each expression must outlive the // scope of that expression. This also guarantees basic WF. let expr_ty = rcx.resolve_node_type(expr.id); - + // the region corresponding to this expression + let expr_region = ty::ReScope(rcx.tcx().region_maps.node_extent(expr.id)); type_must_outlive(rcx, infer::ExprTypeIsNotInScope(expr_ty, expr.span), - expr_ty, ty::ReScope(CodeExtent::from_node_id(expr.id))); + expr_ty, expr_region); let method_call = MethodCall::expr(expr.id); let opt_method_callee = rcx.fcx.inh.tables.borrow().method_map.get(&method_call).cloned(); let has_method_map = opt_method_callee.is_some(); - // the region corresponding to this expression - let expr_region = ty::ReScope(CodeExtent::from_node_id(expr.id)); - // If we are calling a method (either explicitly or via an // overloaded operator), check that all of the types provided as // arguments for its type parameters are well-formed, and all the regions @@ -609,7 +609,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // FIXME(#6268) remove to support nested method calls type_of_node_must_outlive( rcx, infer::AutoBorrow(expr.span), - expr.id, ty::ReScope(CodeExtent::from_node_id(expr.id))); + expr.id, expr_region); } } /* @@ -726,7 +726,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { type_must_outlive(rcx, infer::Operand(expr.span), ty, - ty::ReScope(CodeExtent::from_node_id(expr.id))); + expr_region); } visit::walk_expr(rcx, expr); } @@ -756,7 +756,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { }; if let ty::TyRef(r_ptr, _) = base_ty.sty { mk_subregion_due_to_dereference( - rcx, expr.span, ty::ReScope(CodeExtent::from_node_id(expr.id)), *r_ptr); + rcx, expr.span, expr_region, *r_ptr); } visit::walk_expr(rcx, expr); @@ -789,8 +789,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // // FIXME(#6268) nested method calls requires that this rule change let ty0 = rcx.resolve_node_type(expr.id); - type_must_outlive(rcx, infer::AddrOf(expr.span), - ty0, ty::ReScope(CodeExtent::from_node_id(expr.id))); + type_must_outlive(rcx, infer::AddrOf(expr.span), ty0, expr_region); visit::walk_expr(rcx, expr); } @@ -919,7 +918,7 @@ fn constrain_call<'a, I: Iterator>(rcx: &mut Rcx, // call occurs. // // FIXME(#6268) to support nested method calls, should be callee_id - let callee_scope = CodeExtent::from_node_id(call_expr.id); + let callee_scope = rcx.tcx().region_maps.node_extent(call_expr.id); let callee_region = ty::ReScope(callee_scope); debug!("callee_region={:?}", callee_region); @@ -966,7 +965,8 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, derefs, derefd_ty); - let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id)); + let s_deref_expr = rcx.tcx().region_maps.node_extent(deref_expr.id); + let r_deref_expr = ty::ReScope(s_deref_expr); for i in 0..derefs { let method_call = MethodCall::autoderef(deref_expr.id, i as u32); debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs); @@ -1083,7 +1083,7 @@ fn constrain_index<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, debug!("constrain_index(index_expr=?, indexed_ty={}", rcx.fcx.infcx().ty_to_string(indexed_ty)); - let r_index_expr = ty::ReScope(CodeExtent::from_node_id(index_expr.id)); + let r_index_expr = ty::ReScope(rcx.tcx().region_maps.node_extent(index_expr.id)); if let ty::TyRef(r_ptr, mt) = indexed_ty.sty { match mt.ty.sty { ty::TySlice(_) | ty::TyStr => { @@ -1234,7 +1234,7 @@ fn link_autoref(rcx: &Rcx, } ty::AutoUnsafe(m) => { - let r = ty::ReScope(CodeExtent::from_node_id(expr.id)); + let r = ty::ReScope(rcx.tcx().region_maps.node_extent(expr.id)); link_region(rcx, expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt); } } From 65e9bc0c93ec7e4b25b8fd0e03e377c09bfd1748 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 22 Aug 2015 17:39:21 +0300 Subject: [PATCH 4/7] store the CodeExtent directly in FreeRegion this makes the code cleaner --- src/librustc/metadata/tydecode.rs | 7 +------ src/librustc/metadata/tyencode.rs | 7 +------ src/librustc/middle/free_region.rs | 3 +-- src/librustc/middle/infer/error_reporting.rs | 7 ++++--- src/librustc/middle/infer/region_inference/mod.rs | 11 ++++------- src/librustc/middle/liveness.rs | 3 +-- src/librustc/middle/mem_categorization.rs | 3 +-- src/librustc/middle/region.rs | 10 +++++++--- src/librustc/middle/ty.rs | 11 +++++------ src/librustc_borrowck/borrowck/gather_loans/mod.rs | 4 +--- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/closure.rs | 3 +-- src/librustc_typeck/check/mod.rs | 5 ++--- src/librustc_typeck/check/wf.rs | 8 +++----- src/librustc_typeck/check/wfcheck.rs | 3 +-- src/librustc_typeck/collect.rs | 4 ++-- 16 files changed, 36 insertions(+), 55 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 768e769efedc4..c66d4084aca9e 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -225,7 +225,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 'f' => { assert_eq!(self.next(), '['); - let scope = self.parse_destruction_scope_data(); + let scope = self.parse_scope(); assert_eq!(self.next(), '|'); let br = self.parse_bound_region(); assert_eq!(self.next(), ']'); @@ -284,11 +284,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { }) } - fn parse_destruction_scope_data(&mut self) -> region::DestructionScopeData { - let node_id = self.parse_uint() as ast::NodeId; - region::DestructionScopeData::new(node_id) - } - fn parse_opt(&mut self, f: F) -> Option where F: FnOnce(&mut TyDecoder<'a, 'tcx>) -> T, { diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index a17d27acc2a26..70345dc8bad11 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -255,7 +255,7 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) { } ty::ReFree(ref fr) => { mywrite!(w, "f["); - enc_destruction_scope_data(w, fr.scope); + enc_scope(w, cx, fr.scope); mywrite!(w, "|"); enc_bound_region(w, cx, fr.bound_region); mywrite!(w, "]"); @@ -289,11 +289,6 @@ fn enc_scope(w: &mut Encoder, cx: &ctxt, scope: region::CodeExtent) { } } -fn enc_destruction_scope_data(w: &mut Encoder, - d: region::DestructionScopeData) { - mywrite!(w, "{}", d.node_id); -} - fn enc_bound_region(w: &mut Encoder, cx: &ctxt, br: ty::BoundRegion) { match br { ty::BrAnon(idx) => { diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 4b81117f2e9a9..6ab56badbcf41 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -135,8 +135,7 @@ impl FreeRegionMap { tcx.region_maps.is_subscope_of(sub_scope, super_scope), (ty::ReScope(sub_scope), ty::ReFree(fr)) => - tcx.region_maps.is_subscope_of(sub_scope, - fr.scope.to_code_extent(&tcx.region_maps)) || + tcx.region_maps.is_subscope_of(sub_scope, fr.scope) || self.is_static(fr), (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index c7261b4a781c1..9044bf4db8c3d 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -172,7 +172,7 @@ impl<'tcx> ty::ctxt<'tcx> { } }; - match self.map.find(fr.scope.node_id) { + match self.map.find(fr.scope.node_id(&self.region_maps)) { Some(ast_map::NodeBlock(ref blk)) => { let (msg, opt_span) = explain_span(self, "block", blk.span); (format!("{} {}", prefix, msg), opt_span) @@ -183,7 +183,8 @@ impl<'tcx> ty::ctxt<'tcx> { (format!("{} {}", prefix, msg), opt_span) } Some(_) | None => { - // this really should not happen + // this really should not happen, but it does: + // FIXME(#27942) (format!("{} unknown free region bounded by scope {:?}", prefix, fr.scope), None) } @@ -422,7 +423,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { return None } assert!(fr1.scope == fr2.scope); - (fr1.scope.node_id, fr1, fr2) + (fr1.scope.node_id(&tcx.region_maps), fr1, fr2) }, _ => return None }; diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 4a6c30853df46..1785fe09f87a4 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -790,10 +790,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // A "free" region can be interpreted as "some region // at least as big as the block fr.scope_id". So, we can // reasonably compare free regions and scopes: - let fr_scope = fr.scope.to_code_extent(&self.tcx.region_maps); - let r_id = self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id); + let r_id = self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id); - if r_id == fr_scope { + 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 // region itself: @@ -871,8 +870,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // than the scope `s_id`, then we can say that the GLB // is the scope `s_id`. Otherwise, as we do not know // big the free region is precisely, the GLB is undefined. - let fr_scope = fr.scope.to_code_extent(&self.tcx.region_maps); - if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope || + if self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id) == fr.scope || free_regions.is_static(fr) { Ok(s) } else { @@ -927,8 +925,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { Ok(ty::ReFree(*b)) } else { this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b), - a.scope.to_code_extent(&this.tcx.region_maps), - b.scope.to_code_extent(&this.tcx.region_maps)) + a.scope, b.scope) } } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 87b8e72f56f11..e1866d878bda6 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -111,7 +111,6 @@ use self::VarKind::*; use middle::def::*; use middle::pat_util; -use middle::region; use middle::ty; use lint; use util::nodemap::NodeMap; @@ -1509,7 +1508,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // within the fn body, late-bound regions are liberated: let fn_ret = self.ir.tcx.liberate_late_bound_regions( - region::DestructionScopeData::new(body.id), + self.ir.tcx.region_maps.item_extent(body.id), &self.fn_ret(id)); match fn_ret { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0cab4b610be72..a991407310204 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -77,7 +77,6 @@ use middle::def_id::DefId; use middle::infer; use middle::check_const; use middle::def; -use middle::region; use middle::ty::{self, Ty}; use syntax::ast::{MutImmutable, MutMutable}; @@ -749,7 +748,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { // The environment of a closure is guaranteed to // outlive any bindings introduced in the body of the // closure itself. - scope: region::DestructionScopeData::new(fn_body_id), + scope: self.tcx().region_maps.item_extent(fn_body_id), bound_region: ty::BrEnv }); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index f4260dd700d65..f9faba8c3198e 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -309,6 +309,13 @@ impl RegionMaps { pub fn lookup_code_extent(&self, e: CodeExtentData) -> CodeExtent { self.code_extent_interner.borrow()[&e] } + pub fn node_extent(&self, n: ast::NodeId) -> CodeExtent { + self.lookup_code_extent(CodeExtentData::Misc(n)) + } + // Returns the code extent for an item - the destruction scope. + pub fn item_extent(&self, n: ast::NodeId) -> CodeExtent { + self.lookup_code_extent(CodeExtentData::DestructionScope(n)) + } pub fn intern_code_extent(&self, e: CodeExtentData, parent: CodeExtent) -> CodeExtent { @@ -350,9 +357,6 @@ impl RegionMaps { parent: CodeExtent) -> CodeExtent { self.intern_code_extent(CodeExtentData::Misc(n), parent) } - pub fn node_extent(&self, n: ast::NodeId) -> CodeExtent { - self.lookup_code_extent(CodeExtentData::Misc(n)) - } pub fn code_extent_data(&self, e: CodeExtent) -> CodeExtentData { self.code_extents.borrow()[e.0 as usize] } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a18bff5591dd1..eff560653c140 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1679,7 +1679,7 @@ impl Region { /// A "free" region `fr` can be interpreted as "some region /// at least as big as the scope `fr.scope`". pub struct FreeRegion { - pub scope: region::DestructionScopeData, + pub scope: region::CodeExtent, pub bound_region: BoundRegion } @@ -6610,7 +6610,7 @@ impl<'tcx> ctxt<'tcx> { types.push(def.space, self.mk_param_from_def(def)); } - let free_id_outlive = region::DestructionScopeData::new(free_id); + let free_id_outlive = self.region_maps.item_extent(free_id); // map bound 'a => free 'a let mut regions = VecPerParamSpace::empty(); @@ -6641,7 +6641,7 @@ impl<'tcx> ctxt<'tcx> { // let free_substs = self.construct_free_substs(generics, free_id); - let free_id_outlive = region::DestructionScopeData::new(free_id); + let free_id_outlive = self.region_maps.item_extent(free_id); // // Compute the bounds on Self and the type parameters. @@ -6673,8 +6673,7 @@ impl<'tcx> ctxt<'tcx> { let unnormalized_env = ty::ParameterEnvironment { tcx: self, free_substs: free_substs, - implicit_region_bound: ty::ReScope( - free_id_outlive.to_code_extent(&self.region_maps)), + implicit_region_bound: ty::ReScope(free_id_outlive), caller_bounds: predicates, selection_cache: traits::SelectionCache::new(), free_id: free_id, @@ -6838,7 +6837,7 @@ impl<'tcx> ctxt<'tcx> { /// Replace any late-bound regions bound in `value` with free variants attached to scope-id /// `scope_id`. pub fn liberate_late_bound_regions(&self, - all_outlive_scope: region::DestructionScopeData, + all_outlive_scope: region::CodeExtent, value: &Binder) -> T where T : TypeFoldable<'tcx> diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index c3801f436e582..cbdd0020a3032 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -360,9 +360,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { let loan_scope = match loan_region { ty::ReScope(scope) => scope, - ty::ReFree(ref fr) => { - fr.scope.to_code_extent(&self.tcx().region_maps) - } + ty::ReFree(ref fr) => fr.scope, ty::ReStatic => { // If we get here, an error must have been diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f14f196f1aebb..944169fc45ebb 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -179,7 +179,7 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) Some(&rl::DefFreeRegion(scope, id)) => { ty::ReFree(ty::FreeRegion { - scope: scope, + scope: tcx.region_maps.item_extent(scope.node_id), bound_region: ty::BrNamed(DefId::local(id), lifetime.name) }) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 6d7919a84efb5..a3714fead8e28 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -14,7 +14,6 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv; use middle::def_id::DefId; -use middle::region; use middle::subst; use middle::ty::{self, ToPolyTraitRef, Ty}; use std::cmp; @@ -77,7 +76,7 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, fcx.write_ty(expr.id, closure_type); let fn_sig = fcx.tcx().liberate_late_bound_regions( - region::DestructionScopeData::new(body.id), &fn_ty.sig); + fcx.tcx().region_maps.item_extent(body.id), &fn_ty.sig); check_fn(fcx.ccx, ast::Unsafety::Normal, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bbea25525738a..cf08490d720c9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -91,7 +91,6 @@ use middle::infer; use middle::infer::type_variable; use middle::pat_util::{self, pat_id_map}; use middle::privacy::{AllPublic, LastMod}; -use middle::region::{self}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace}; use middle::traits::{self, report_fulfillment_errors}; use middle::ty::{FnSig, GenericPredicates, TypeScheme}; @@ -455,11 +454,11 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let inh = Inherited::new(ccx.tcx, &tables, param_env); // Compute the fty from point of view of inside fn. + let fn_scope = ccx.tcx.region_maps.item_extent(body.id); let fn_sig = fn_ty.sig.subst(ccx.tcx, &inh.infcx.parameter_environment.free_substs); let fn_sig = - ccx.tcx.liberate_late_bound_regions(region::DestructionScopeData::new(body.id), - &fn_sig); + ccx.tcx.liberate_late_bound_regions(fn_scope, &fn_sig); let fn_sig = inh.normalize_associated_types_in(body.span, body.id, diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index d1e159d445605..0ef1d4b81acad 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -466,10 +466,7 @@ pub struct BoundsChecker<'cx,'tcx:'cx> { fcx: &'cx FnCtxt<'cx,'tcx>, span: Span, - // This field is often attached to item impls; it is not clear - // that `CodeExtent` is well-defined for such nodes, so pnkfelix - // has left it as a NodeId rather than porting to CodeExtent. - scope: ast::NodeId, + scope: region::CodeExtent, binding_count: usize, cache: Option<&'cx mut HashSet>>, @@ -480,6 +477,7 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { scope: ast::NodeId, cache: Option<&'cx mut HashSet>>) -> BoundsChecker<'cx,'tcx> { + let scope = fcx.tcx().region_maps.item_extent(scope); BoundsChecker { fcx: fcx, span: DUMMY_SP, scope: scope, cache: cache, binding_count: 0 } } @@ -532,7 +530,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { { self.binding_count += 1; let value = self.fcx.tcx().liberate_late_bound_regions( - region::DestructionScopeData::new(self.scope), + self.scope, binder); debug!("BoundsChecker::fold_binder: late-bound regions replaced: {:?} at scope: {:?}", value, self.scope); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index cdad1257533cb..4280e392d180f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,7 +13,6 @@ use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; use middle::def_id::DefId; -use middle::region::DestructionScopeData; use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use middle::traits; use middle::ty::{self, Ty}; @@ -362,7 +361,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { { let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; let fty = fcx.instantiate_type_scheme(span, free_substs, fty); - let free_id_outlive = DestructionScopeData::new(free_id); + let free_id_outlive = fcx.tcx().region_maps.item_extent(free_id); let sig = fcx.tcx().liberate_late_bound_regions(free_id_outlive, &fty.sig); for &input_ty in &sig.inputs { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d3e414fd9c0e4..544f6d9f0ed85 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2311,7 +2311,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( _ => typ, }; - let body_scope = region::DestructionScopeData::new(body_id); + let body_scope = tcx.region_maps.item_extent(body_id); // "Required type" comes from the trait definition. It may // contain late-bound regions from the method, but not the @@ -2363,7 +2363,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( fn liberate_early_bound_regions<'tcx,T>( tcx: &ty::ctxt<'tcx>, - scope: region::DestructionScopeData, + scope: region::CodeExtent, value: &T) -> T where T : TypeFoldable<'tcx> From 581e5ee45e00965df45dbb96fcdd869b378d2ffe Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 22 Aug 2015 22:51:29 +0300 Subject: [PATCH 5/7] fix test --- src/librustc/middle/free_region.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 6ab56badbcf41..c39c3fd302712 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -162,8 +162,8 @@ impl FreeRegionMap { #[cfg(test)] fn free_region(index: u32) -> FreeRegion { - use middle::region::DestructionScopeData; - FreeRegion { scope: DestructionScopeData::new(0), + use middle::region::DUMMY_CODE_EXTENT; + FreeRegion { scope: DUMMY_CODE_EXTENT, bound_region: ty::BoundRegion::BrAnon(index) } } From 1e507d44505a336fb60ee1dbd121bd986788296e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 24 Aug 2015 21:30:39 +0300 Subject: [PATCH 6/7] address nits --- src/librustc/metadata/tydecode.rs | 14 +++-- src/librustc/middle/astencode.rs | 2 +- src/librustc/middle/infer/error_reporting.rs | 2 +- src/librustc/middle/region.rs | 66 ++++++++++---------- 4 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index c66d4084aca9e..0c802356af10d 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -207,8 +207,10 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 'B' => { assert_eq!(self.next(), '['); - // this is totally wrong, but nobody relevant cares about - // this field - it will die soon(TM). + // this is the wrong NodeId, but `param_id` is only accessed + // by the receiver-matching code in collect, which won't + // be going down this code path, and anyway I will kill it + // the moment wfcheck becomes the standard. let node_id = self.parse_uint() as ast::NodeId; assert_eq!(self.next(), '|'); let space = self.parse_param_space(); @@ -249,8 +251,12 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { fn parse_scope(&mut self) -> region::CodeExtent { self.tcx.region_maps.bogus_code_extent(match self.next() { - // the scopes created here are totally bogus with their - // NodeIDs + // This creates scopes with the wrong NodeId. This isn't + // actually a problem because scopes only exist *within* + // functions, and functions aren't loaded until trans which + // doesn't care about regions. + // + // May still be worth fixing though. 'P' => { assert_eq!(self.next(), '['); let fn_id = self.parse_uint() as ast::NodeId; diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 2edf2b896ba17..4ea55d2d4e42c 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1365,7 +1365,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { /// the crate numbers back to the original source crate. /// /// Scopes will end up as being totally bogus. This can actually - /// be fixed through. + /// be fixed though. /// /// Unboxed closures are cloned along with the function being /// inlined, and all side tables use interned node IDs, so we diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 9044bf4db8c3d..61fa08c462069 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -201,7 +201,7 @@ impl<'tcx> ty::ctxt<'tcx> { // ReFree rather than dumping Debug output on the user. // // We shouldn't really be having unification failures with ReVar - // and ReLateBound through. + // and ReLateBound though. ty::ReSkolemized(..) | ty::ReVar(_) | ty::ReLateBound(..) => { (format!("lifetime {:?}", region), None) } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index f9faba8c3198e..37b9d8aa645bc 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -177,6 +177,14 @@ impl CodeExtentData { } impl CodeExtent { + #[inline] + fn into_option(self) -> Option { + if self == ROOT_CODE_EXTENT { + None + } else { + Some(self) + } + } pub fn node_id(&self, region_maps: &RegionMaps) -> ast::NodeId { region_maps.code_extent_data(*self).node_id() } @@ -325,7 +333,7 @@ impl RegionMaps { // have (bogus) NodeId-s that overlap items created during // inlining. // We probably shouldn't be creating bogus code extents - // through. + // though. let idx = *o.get(); if parent == DUMMY_CODE_EXTENT { info!("CodeExtent({}) = {:?} [parent={}] BOGUS!", @@ -413,10 +421,7 @@ impl RegionMaps { pub fn opt_encl_scope(&self, id: CodeExtent) -> Option { //! Returns the narrowest scope that encloses `id`, if any. - match self.scope_map.borrow()[id.0 as usize] { - ROOT_CODE_EXTENT => None, - c => Some(c) - } + self.scope_map.borrow()[id.0 as usize].into_option() } #[allow(dead_code)] // used in middle::cfg @@ -445,32 +450,33 @@ impl RegionMaps { None => { } } + let scope_map : &[CodeExtent] = &self.scope_map.borrow(); + let code_extents: &[CodeExtentData] = &self.code_extents.borrow(); + // else, locate the innermost terminating scope // if there's one. Static items, for instance, won't // have an enclosing scope, hence no scope will be // returned. + let expr_extent = self.node_extent(expr_id); // For some reason, the expr's scope itself is skipped here. - let mut id = match self.opt_encl_scope(self.node_extent(expr_id)) { + let mut id = match scope_map[expr_extent.0 as usize].into_option() { Some(i) => i, - None => { return None; } + _ => return None }; - loop { match self.opt_encl_scope(id) { - Some(p) => { - match self.code_extent_data(p) { - CodeExtentData::DestructionScope(..) => { - debug!("temporary_scope({:?}) = {:?} [enclosing]", - expr_id, id); - return Some(id); - } - _ => id = p + while let Some(p) = scope_map[id.0 as usize].into_option() { + match code_extents[p.0 as usize] { + CodeExtentData::DestructionScope(..) => { + debug!("temporary_scope({:?}) = {:?} [enclosing]", + expr_id, id); + return Some(id); } + _ => id = p } - None => { - debug!("temporary_scope({:?}) = None", expr_id); - return None; - } - } } + } + + debug!("temporary_scope({:?}) = None", expr_id); + return None; } pub fn var_region(&self, id: ast::NodeId) -> ty::Region { @@ -591,24 +597,20 @@ impl RegionMaps { let mut i = 0; while i < 32 { buf[i] = scope; - let superscope = scope_map[scope.0 as usize]; - if superscope == ROOT_CODE_EXTENT { - return &buf[..i+1]; - } else { - scope = superscope; + match scope_map[scope.0 as usize].into_option() { + Some(superscope) => scope = superscope, + _ => return &buf[..i+1] } i += 1; } *vec = Vec::with_capacity(64); - vec.extend((*buf).into_iter()); + vec.push_all(buf); loop { vec.push(scope); - let superscope = scope_map[scope.0 as usize]; - if superscope == ROOT_CODE_EXTENT { - return &*vec; - } else { - scope = superscope; + match scope_map[scope.0 as usize].into_option() { + Some(superscope) => scope = superscope, + _ => return &*vec } } } From 06563fe0b7d64b7552d65a7ab00aa360820f05c5 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 24 Aug 2015 23:41:02 +0300 Subject: [PATCH 7/7] fix other test --- src/librustc_driver/test.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index dcc92efc2a2ca..3277e07dfc163 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -17,7 +17,7 @@ use rustc_lint; use rustc_resolve as resolve; use rustc_typeck::middle::lang_items; use rustc_typeck::middle::free_region::FreeRegionMap; -use rustc_typeck::middle::region::{self, CodeExtent, DestructionScopeData}; +use rustc_typeck::middle::region::{self, CodeExtent}; use rustc_typeck::middle::region::CodeExtentData; use rustc_typeck::middle::resolve_lifetime; use rustc_typeck::middle::stability; @@ -329,8 +329,10 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region { - ty::ReFree(ty::FreeRegion { scope: DestructionScopeData::new(nid), - bound_region: ty::BrAnon(id)}) + ty::ReFree(ty::FreeRegion { + scope: self.tcx().region_maps.item_extent(nid), + bound_region: ty::BrAnon(id) + }) } pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> {