From 5ff9087e05e6661990856ab3bdbc197e50380db5 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 18 Nov 2014 14:22:59 +0100 Subject: [PATCH] Refactored new CodeExtent type for improved abstraction. (Previously, statically identifiable scopes/regions were solely identified with NodeId's; this refactoring prepares for a future where that 1:1 correspondence does not hold.) --- src/librustc/metadata/tydecode.rs | 19 +- src/librustc/metadata/tyencode.rs | 17 +- src/librustc/middle/astencode.rs | 20 +- src/librustc/middle/borrowck/check_loans.rs | 50 ++-- .../middle/borrowck/gather_loans/lifetime.rs | 20 +- .../middle/borrowck/gather_loans/mod.rs | 29 +- src/librustc/middle/borrowck/mod.rs | 32 ++- src/librustc/middle/borrowck/move_data.rs | 8 +- src/librustc/middle/cfg/construct.rs | 10 +- src/librustc/middle/expr_use_visitor.rs | 16 +- src/librustc/middle/mem_categorization.rs | 5 +- src/librustc/middle/region.rs | 262 +++++++++++------- src/librustc/middle/resolve_lifetime.rs | 22 +- src/librustc/middle/ty.rs | 21 +- src/librustc/middle/typeck/astconv.rs | 4 +- src/librustc/middle/typeck/check/mod.rs | 29 +- src/librustc/middle/typeck/check/regionck.rs | 34 +-- src/librustc/middle/typeck/check/wf.rs | 34 ++- src/librustc/middle/typeck/collect.rs | 15 +- .../middle/typeck/infer/error_reporting.rs | 6 +- .../typeck/infer/region_inference/mod.rs | 15 +- src/librustc/util/ppaux.rs | 12 +- src/librustc_trans/test.rs | 12 +- src/librustc_trans/trans/cleanup.rs | 8 +- src/librustc_trans/trans/common.rs | 3 +- 25 files changed, 427 insertions(+), 276 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 34b57c5b437..00d12ad6a38 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -18,6 +18,7 @@ pub use self::DefIdSource::*; +use middle::region; use middle::subst; use middle::subst::VecPerParamSpace; use middle::ty::{mod, Ty}; @@ -315,17 +316,17 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { } 'f' => { assert_eq!(next(st), '['); - let id = parse_uint(st) as ast::NodeId; + let scope = parse_scope(st); assert_eq!(next(st), '|'); let br = parse_bound_region(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); - ty::ReFree(ty::FreeRegion {scope_id: id, + ty::ReFree(ty::FreeRegion { scope: scope, bound_region: br}) } 's' => { - let id = parse_uint(st) as ast::NodeId; + let scope = parse_scope(st); assert_eq!(next(st), '|'); - ty::ReScope(id) + ty::ReScope(scope) } 't' => { ty::ReStatic @@ -337,6 +338,16 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { } } +fn parse_scope(st: &mut PState) -> region::CodeExtent { + match next(st) { + 'M' => { + let node_id = parse_uint(st) as ast::NodeId; + region::CodeExtent::Misc(node_id) + } + _ => panic!("parse_scope: bad input") + } +} + fn parse_opt<'a, 'tcx, T>(st: &mut PState<'a, 'tcx>, f: |&mut PState<'a, 'tcx>| -> T) -> Option { match next(st) { diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index ea778d07e1c..bbb2faaae06 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -15,6 +15,7 @@ use std::cell::RefCell; +use middle::region; use middle::subst; use middle::subst::VecPerParamSpace; use middle::ty::ParamTy; @@ -143,12 +144,16 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) { token::get_name(name)); } ty::ReFree(ref fr) => { - mywrite!(w, "f[{}|", fr.scope_id); + mywrite!(w, "f["); + enc_scope(w, cx, fr.scope); + mywrite!(w, "|"); enc_bound_region(w, cx, fr.bound_region); mywrite!(w, "]"); } - ty::ReScope(nid) => { - mywrite!(w, "s{}|", nid); + ty::ReScope(scope) => { + mywrite!(w, "s"); + enc_scope(w, cx, scope); + mywrite!(w, "|"); } ty::ReStatic => { mywrite!(w, "t"); @@ -163,6 +168,12 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) { } } +fn enc_scope(w: &mut SeekableMemWriter, _cx: &ctxt, scope: region::CodeExtent) { + match scope { + region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id) + } +} + fn enc_bound_region(w: &mut SeekableMemWriter, cx: &ctxt, br: ty::BoundRegion) { match br { ty::BrAnon(idx) => { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 3cebb7236b6..7986a526b23 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -489,20 +489,32 @@ impl tr for ty::Region { ty::ReEarlyBound(id, space, index, ident) => { ty::ReEarlyBound(dcx.tr_id(id), space, index, ident) } - ty::ReScope(id) => { - ty::ReScope(dcx.tr_id(id)) + ty::ReScope(scope) => { + ty::ReScope(scope.tr(dcx)) } ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) => { *self } ty::ReFree(ref fr) => { - ty::ReFree(ty::FreeRegion {scope_id: dcx.tr_id(fr.scope_id), - bound_region: fr.bound_region.tr(dcx)}) + 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 ty::BoundRegion { fn tr(&self, dcx: &DecodeContext) -> ty::BoundRegion { match *self { diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index d91d666511d..238a4ca7bd6 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -21,6 +21,7 @@ use self::UseError::*; use middle::borrowck::*; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; +use middle::region; use middle::ty; use syntax::ast; use syntax::codemap::Span; @@ -134,7 +135,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { None => { } } - self.check_for_conflicting_loans(borrow_id); + self.check_for_conflicting_loans(region::CodeExtent::from_node_id(borrow_id)); } fn mutate(&mut self, @@ -215,30 +216,30 @@ 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_id: ast::NodeId, op: |&Loan| -> bool) + pub fn each_issued_loan(&self, scope: region::CodeExtent, op: |&Loan| -> bool) -> bool { //! Iterates over each loan that has been issued - //! on entrance to `scope_id`, regardless of whether it is + //! on entrance to `scope`, 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_id, |loan_index| { + self.dfcx_loans.each_bit_on_entry(scope.node_id(), |loan_index| { let loan = &self.all_loans[loan_index]; op(loan) }) } pub fn each_in_scope_loan(&self, - scope_id: ast::NodeId, + scope: region::CodeExtent, op: |&Loan| -> bool) -> bool { //! Like `each_issued_loan()`, but only considers loans that are //! currently in scope. let tcx = self.tcx(); - self.each_issued_loan(scope_id, |loan| { - if tcx.region_maps.is_subscope_of(scope_id, loan.kill_scope) { + self.each_issued_loan(scope, |loan| { + if tcx.region_maps.is_subscope_of(scope, loan.kill_scope) { op(loan) } else { true @@ -247,7 +248,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } fn each_in_scope_loan_affecting_path(&self, - scope_id: ast::NodeId, + scope: region::CodeExtent, loan_path: &LoanPath, op: |&Loan| -> bool) -> bool { @@ -262,7 +263,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // let y = a; // Conflicts with restriction let loan_path = owned_ptr_base_path(loan_path); - let cont = self.each_in_scope_loan(scope_id, |loan| { + let cont = self.each_in_scope_loan(scope, |loan| { let mut ret = true; for restr_path in loan.restricted_paths.iter() { if **restr_path == *loan_path { @@ -302,7 +303,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } } - let cont = self.each_in_scope_loan(scope_id, |loan| { + let cont = self.each_in_scope_loan(scope, |loan| { if *loan.loan_path == *loan_path { op(loan) } else { @@ -318,30 +319,33 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { return true; } - pub fn loans_generated_by(&self, scope_id: ast::NodeId) -> Vec { + pub fn loans_generated_by(&self, scope: region::CodeExtent) -> Vec { //! Returns a vector of the loans that are generated as - //! we encounter `scope_id`. + //! we enter `scope`. let mut result = Vec::new(); - self.dfcx_loans.each_gen_bit(scope_id, |loan_index| { + self.dfcx_loans.each_gen_bit(scope.node_id(), |loan_index| { result.push(loan_index); true }); return result; } - pub fn check_for_conflicting_loans(&self, scope_id: ast::NodeId) { + pub fn check_for_conflicting_loans(&self, scope: region::CodeExtent) { //! Checks to see whether any of the loans that are issued - //! by `scope_id` conflict with loans that have already been - //! issued when we enter `scope_id` (for example, we do not + //! on entrance to `scope` conflict with loans that have already been + //! issued when we enter `scope` (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_id={})", scope_id); + debug!("check_for_conflicting_loans(scope={})", scope); - let new_loan_indices = self.loans_generated_by(scope_id); + let new_loan_indices = self.loans_generated_by(scope); debug!("new_loan_indices = {}", new_loan_indices); - self.each_issued_loan(scope_id, |issued_loan| { + self.each_issued_loan(scope, |issued_loan| { for &new_loan_index in new_loan_indices.iter() { let new_loan = &self.all_loans[new_loan_index]; self.report_error_if_loans_conflict(issued_loan, new_loan); @@ -535,7 +539,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { old_loan.span, format!("{}; {}", borrow_summary, rule_summary).as_slice()); - let old_loan_span = self.tcx().map.span(old_loan.kill_scope); + let old_loan_span = self.tcx().map.span(old_loan.kill_scope.node_id()); self.bccx.span_end_note(old_loan_span, "previous borrow ends here"); @@ -657,7 +661,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { let mut ret = UseOk; - self.each_in_scope_loan_affecting_path(expr_id, use_path, |loan| { + self.each_in_scope_loan_affecting_path( + region::CodeExtent::from_node_id(expr_id), use_path, |loan| { if !compatible_borrow_kinds(loan.kind, borrow_kind) { ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span); false @@ -924,7 +929,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { None => { return; /* no loan path, can't be any loans */ } }; - this.each_in_scope_loan_affecting_path(assignment_id, &*loan_path, |loan| { + let scope = region::CodeExtent::from_node_id(assignment_id); + this.each_in_scope_loan_affecting_path(scope, &*loan_path, |loan| { this.report_illegal_mutation(assignment_span, &*loan_path, loan); false }); diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 99795fb3009..5b8cb0608b3 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -16,6 +16,7 @@ use middle::borrowck::*; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; +use middle::region; use middle::ty; use util::ppaux::Repr; use syntax::ast; @@ -24,17 +25,20 @@ use syntax::codemap::Span; type R = Result<(),()>; pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - item_scope_id: ast::NodeId, + item_scope: region::CodeExtent, span: Span, cause: euv::LoanCause, cmt: mc::cmt<'tcx>, loan_region: ty::Region, _: ty::BorrowKind) -> Result<(),()> { + //! Reports error if `loan_region` is larger than S + //! where S is `item_scope` if `cmt` is an upvar, + //! and is scope of `cmt` otherwise. debug!("guarantee_lifetime(cmt={}, loan_region={})", cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx)); let ctxt = GuaranteeLifetimeContext {bccx: bccx, - item_scope_id: item_scope_id, + item_scope: item_scope, span: span, cause: cause, loan_region: loan_region, @@ -48,8 +52,8 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { bccx: &'a BorrowckCtxt<'a, 'tcx>, - // the node id of the function body for the enclosing item - item_scope_id: ast::NodeId, + // the scope of the function body for the enclosing item + item_scope: region::CodeExtent, span: Span, cause: euv::LoanCause, @@ -60,7 +64,9 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option) -> R { - //! Main routine. Walks down `cmt` until we find the "guarantor". + //! Main routine. Walks down `cmt` until we find the + //! "guarantor". Reports an error if `self.loan_region` is + //! larger than scope of `cmt`. debug!("guarantee_lifetime.check(cmt={}, loan_region={})", cmt.repr(self.bccx.tcx), self.loan_region.repr(self.bccx.tcx)); @@ -88,7 +94,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } fn check_scope(&self, max_scope: ty::Region) -> R { - //! Reports an error if `loan_region` is larger than `valid_scope` + //! Reports an error if `loan_region` is larger than `max_scope` if !self.bccx.is_subregion_of(self.loan_region, max_scope) { Err(self.report_error(err_out_of_scope(max_scope, self.loan_region))) @@ -109,7 +115,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { temp_scope } mc::cat_upvar(..) => { - ty::ReScope(self.item_scope_id) + ty::ReScope(self.item_scope) } mc::cat_static_item => { ty::ReStatic diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 6bb511b2077..c36a466919b 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -20,6 +20,7 @@ use middle::borrowck::*; use middle::borrowck::move_data::MoveData; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; +use middle::region; use middle::ty; use util::ppaux::{Repr}; @@ -42,7 +43,7 @@ pub fn gather_loans_in_fn(bccx: &BorrowckCtxt, let mut glcx = GatherLoanCtxt { bccx: bccx, all_loans: Vec::new(), - item_ub: body.id, + item_ub: region::CodeExtent::from_node_id(body.id), move_data: MoveData::new(), move_error_collector: move_error::MoveErrorCollector::new(), }; @@ -62,7 +63,9 @@ struct GatherLoanCtxt<'a, 'tcx: 'a> { move_data: move_data::MoveData, move_error_collector: move_error::MoveErrorCollector<'tcx>, all_loans: Vec, - item_ub: ast::NodeId, + /// `item_ub` is used as an upper-bound on the lifetime whenever we + /// ask for the scope of an expression categorized as an upvar. + item_ub: region::CodeExtent, } impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { @@ -266,8 +269,9 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { restrictions::SafeIf(loan_path, restricted_paths) => { let loan_scope = match loan_region { - ty::ReScope(id) => id, - ty::ReFree(ref fr) => fr.scope_id, + ty::ReScope(scope) => scope, + + ty::ReFree(ref fr) => fr.scope, ty::ReStatic => { // If we get here, an error must have been @@ -293,7 +297,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { }; debug!("loan_scope = {}", loan_scope); - let gen_scope = self.compute_gen_scope(borrow_id, loan_scope); + let borrow_scope = region::CodeExtent::from_node_id(borrow_id); + let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope); debug!("gen_scope = {}", gen_scope); let kill_scope = self.compute_kill_scope(loan_scope, &*loan_path); @@ -406,23 +411,23 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } pub fn compute_gen_scope(&self, - borrow_id: ast::NodeId, - loan_scope: ast::NodeId) - -> ast::NodeId { + borrow_scope: region::CodeExtent, + loan_scope: region::CodeExtent) + -> region::CodeExtent { //! Determine when to introduce the loan. Typically the loan //! is introduced at the point of the borrow, but in some cases, //! notably method arguments, the loan may be introduced only //! later, once it comes into scope. - if self.bccx.tcx.region_maps.is_subscope_of(borrow_id, loan_scope) { - borrow_id + if self.bccx.tcx.region_maps.is_subscope_of(borrow_scope, loan_scope) { + borrow_scope } else { loan_scope } } - pub fn compute_kill_scope(&self, loan_scope: ast::NodeId, lp: &LoanPath) - -> ast::NodeId { + pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent, lp: &LoanPath) + -> region::CodeExtent { //! Determine when the loan restrictions go out of scope. //! This is either when the lifetime expires or when the //! local variable which roots the loan-path goes out of scope, diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 1ab9baa1ac4..5271a619141 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -24,6 +24,7 @@ use middle::dataflow::BitwiseOperator; use middle::dataflow::DataFlowOperator; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; +use middle::region; use middle::ty::{mod, Ty}; use util::ppaux::{note_and_explain_region, Repr, UserString}; @@ -169,8 +170,8 @@ 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, loan_idx); - loan_dfcx.add_kill(loan.kill_scope, loan_idx); + loan_dfcx.add_gen(loan.gen_scope.node_id(), loan_idx); + loan_dfcx.add_kill(loan.kill_scope.node_id(), loan_idx); } loan_dfcx.add_kills_from_flow_exits(cfg); loan_dfcx.propagate(cfg, body); @@ -258,8 +259,19 @@ pub struct Loan { loan_path: Rc, kind: ty::BorrowKind, restricted_paths: Vec>, - gen_scope: ast::NodeId, - kill_scope: ast::NodeId, + + /// gen_scope indicates where loan is introduced. Typically the + /// loan is introduced at the point of the borrow, but in some + /// cases, notably method arguments, the loan may be introduced + /// only later, once it comes into scope. See also + /// `GatherLoanCtxt::compute_gen_scope`. + gen_scope: region::CodeExtent, + + /// kill_scope indicates when the loan goes out of scope. This is + /// either when the lifetime expires or when the local variable + /// which roots the loan-path goes out of scope, whichever happens + /// faster. See also `GatherLoanCtxt::compute_kill_scope`. + kill_scope: region::CodeExtent, span: Span, cause: euv::LoanCause, } @@ -297,11 +309,13 @@ pub fn closure_to_block(closure_id: ast::NodeId, } impl LoanPath { - pub fn kill_scope(&self, tcx: &ty::ctxt) -> ast::NodeId { + pub fn kill_scope(&self, tcx: &ty::ctxt) -> region::CodeExtent { match *self { LpVar(local_id) => tcx.region_maps.var_scope(local_id), - LpUpvar(upvar_id) => - closure_to_block(upvar_id.closure_expr_id, tcx), + LpUpvar(upvar_id) => { + let block_id = closure_to_block(upvar_id.closure_expr_id, tcx); + region::CodeExtent::from_node_id(block_id) + } LpExtend(ref base, _, _) => base.kill_scope(tcx), } } @@ -901,8 +915,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool { match region { - ty::ReScope(node_id) => { - match tcx.map.find(node_id) { + ty::ReScope(scope) => { + match tcx.map.find(scope.node_id()) { Some(ast_map::NodeStmt(_)) => true, _ => false } diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index b28d963371e..ab4c7787fe8 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -435,9 +435,9 @@ impl MoveData { for path in self.paths.borrow().iter() { match *path.loan_path { LpVar(id) => { - let kill_id = tcx.region_maps.var_scope(id); + let kill_scope = tcx.region_maps.var_scope(id); let path = (*self.path_map.borrow())[path.loan_path]; - self.kill_moves(path, kill_id, dfcx_moves); + self.kill_moves(path, kill_scope.node_id(), dfcx_moves); } LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) => { let kill_id = closure_to_block(closure_expr_id, tcx); @@ -453,8 +453,8 @@ impl MoveData { self.var_assignments.borrow().iter().enumerate() { match *self.path_loan_path(assignment.path) { LpVar(id) => { - let kill_id = tcx.region_maps.var_scope(id); - dfcx_assign.add_kill(kill_id, assignment_index); + let kill_scope = tcx.region_maps.var_scope(id); + dfcx_assign.add_kill(kill_scope.node_id(), assignment_index); } LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) => { let kill_id = closure_to_block(closure_expr_id, tcx); diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index e84e70e2cd9..b4557021b69 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -11,6 +11,7 @@ use middle::cfg::*; use middle::def; use middle::graph; +use middle::region::CodeExtent; use middle::typeck; use middle::ty; use syntax::ast; @@ -580,11 +581,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { to_loop: LoopScope, to_index: CFGIndex) { let mut data = CFGEdgeData {exiting_scopes: vec!() }; - let mut scope_id = from_expr.id; - while scope_id != to_loop.loop_id { + let mut scope = CodeExtent::from_node_id(from_expr.id); + let target_scope = CodeExtent::from_node_id(to_loop.loop_id); + while scope != target_scope { - data.exiting_scopes.push(scope_id); - scope_id = self.tcx.region_maps.encl_scope(scope_id); + data.exiting_scopes.push(scope.node_id()); + 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 f4c22c57163..3215b5e8fe9 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -23,6 +23,7 @@ use self::OverloadedCallType::*; use middle::mem_categorization as mc; use middle::def; use middle::mem_categorization::Typer; +use middle::region; use middle::pat_util; use middle::ty::{mod, Ty}; use middle::typeck::{MethodCall, MethodObject, MethodTraitObject}; @@ -245,10 +246,11 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { for arg in decl.inputs.iter() { 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 arg_cmt = self.mc.cat_rvalue( arg.id, arg.pat.span, - ty::ReScope(body.id), // Args live only as long as the fn body. + ty::ReScope(fn_body_scope), // Args live only as long as the fn body. arg_ty); self.walk_pat(arg_cmt, &*arg.pat); @@ -443,9 +445,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // Fetch the type of the value that the iteration yields to // produce the pattern's categorized mutable type. let pattern_type = return_if_err!(self.typer.node_ty(pat.id)); + let blk_scope = region::CodeExtent::from_node_id(blk.id); let pat_cmt = self.mc.cat_rvalue(pat.id, pat.span, - ty::ReScope(blk.id), + ty::ReScope(blk_scope), pattern_type); self.walk_pat(pat_cmt, &**pat); @@ -519,6 +522,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { let callee_ty = ty::expr_ty_adjusted(self.tcx(), callee); debug!("walk_callee: callee={} callee_ty={}", callee.repr(self.tcx()), callee_ty.repr(self.tcx())); + let call_scope = region::CodeExtent::from_node_id(call.id); match callee_ty.sty { ty::ty_bare_fn(..) => { self.consume_expr(callee); @@ -527,7 +531,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { match f.onceness { ast::Many => { self.borrow_expr(callee, - ty::ReScope(call.id), + ty::ReScope(call_scope), ty::UniqueImmBorrow, ClosureInvocation); } @@ -557,13 +561,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { match overloaded_call_type { FnMutOverloadedCall => { self.borrow_expr(callee, - ty::ReScope(call.id), + ty::ReScope(call_scope), ty::MutBorrow, ClosureInvocation); } FnOverloadedCall => { self.borrow_expr(callee, - ty::ReScope(call.id), + ty::ReScope(call_scope), ty::ImmBorrow, ClosureInvocation); } @@ -814,7 +818,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // methods are implicitly autoref'd which sadly does not use // adjustments, so we must hardcode the borrow here. - let r = ty::ReScope(expr.id); + let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id)); let bk = ty::ImmBorrow; for &arg in rhs.iter() { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 93c2e8f0d99..bb5af2f4297 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -74,6 +74,7 @@ pub use self::deref_kind::*; pub use self::categorization::*; use middle::def; +use middle::region; use middle::ty::{mod, Ty}; use middle::typeck; use util::nodemap::{DefIdMap, NodeMap}; @@ -289,7 +290,7 @@ pub trait Typer<'tcx> { fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option>; fn adjustments<'a>(&'a self) -> &'a RefCell>>; fn is_method_call(&self, id: ast::NodeId) -> bool; - fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option; + fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option; fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow; fn capture_mode(&self, closure_expr_id: ast::NodeId) -> ast::CaptureClause; @@ -702,7 +703,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { // Region of environment pointer let env_region = ty::ReFree(ty::FreeRegion { - scope_id: fn_body_id, + scope: region::CodeExtent::from_node_id(fn_body_id), bound_region: ty::BrEnv }); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 0c0861eda3e..8a50cb4ed4e 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -24,10 +24,11 @@ Most of the documentation on regions can be found in use session::Session; use middle::ty::{FreeRegion}; use middle::ty::{mod, Ty}; -use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; +use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap}; use util::common::can_reach; use std::cell::RefCell; +use std::hash::{Hash}; use syntax::codemap::Span; use syntax::{ast, visit}; use syntax::ast::{Block, Item, FnDecl, NodeId, Arm, Pat, Stmt, Expr, Local}; @@ -35,6 +36,44 @@ use syntax::ast_util::{stmt_id}; use syntax::ptr::P; use syntax::visit::{Visitor, FnKind}; +/// CodeExtent represents a statically-describable extent that can be +/// used to bound the lifetime/region for values. +/// +/// FIXME (pnkfelix): This currently derives `PartialOrd` and `Ord` to +/// 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. +#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] +pub enum CodeExtent { + Misc(ast::NodeId) +} + +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) + } + + /// 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, + } + } + + /// Maps this scope to a potentially new one according to the + /// NodeId transformer `f_id`. + pub fn map_id(&self, f_id: |ast::NodeId| -> ast::NodeId) -> CodeExtent { + match *self { + CodeExtent::Misc(node_id) => CodeExtent::Misc(f_id(node_id)), + } + } +} + /** The region maps encode information about region relationships. @@ -76,11 +115,11 @@ The region maps encode information about region relationships. for dynamic checks and/or arbitrary amounts of stack space. */ pub struct RegionMaps { - scope_map: RefCell>, - var_map: RefCell>, + scope_map: RefCell>, + var_map: RefCell>, free_region_map: RefCell>>, - rvalue_scopes: RefCell>, - terminating_scopes: RefCell, + rvalue_scopes: RefCell>, + terminating_scopes: RefCell>, } pub struct Context { @@ -116,25 +155,25 @@ impl RegionMaps { self.free_region_map.borrow_mut().insert(sub, vec!(sup)); } - pub fn record_encl_scope(&self, sub: ast::NodeId, sup: ast::NodeId) { + 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); } - pub fn record_var_scope(&self, var: ast::NodeId, lifetime: ast::NodeId) { + pub fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { debug!("record_var_scope(sub={}, sup={})", var, lifetime); - assert!(var != lifetime); + assert!(var != lifetime.node_id()); self.var_map.borrow_mut().insert(var, lifetime); } - pub fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: ast::NodeId) { + pub fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { debug!("record_rvalue_scope(sub={}, sup={})", var, lifetime); - assert!(var != lifetime); + assert!(var != lifetime.node_id()); self.rvalue_scopes.borrow_mut().insert(var, lifetime); } - pub fn mark_as_terminating_scope(&self, scope_id: ast::NodeId) { + pub fn mark_as_terminating_scope(&self, scope_id: CodeExtent) { /*! * Records that a scope is a TERMINATING SCOPE. Whenever we * create automatic temporaries -- e.g. by an @@ -146,13 +185,13 @@ impl RegionMaps { self.terminating_scopes.borrow_mut().insert(scope_id); } - pub fn opt_encl_scope(&self, id: ast::NodeId) -> Option { + pub fn opt_encl_scope(&self, id: CodeExtent) -> Option { //! Returns the narrowest scope that encloses `id`, if any. self.scope_map.borrow().get(&id).map(|x| *x) } #[allow(dead_code)] // used in middle::cfg - pub fn encl_scope(&self, id: ast::NodeId) -> ast::NodeId { + 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, @@ -160,7 +199,7 @@ impl RegionMaps { } } - pub fn var_scope(&self, var_id: ast::NodeId) -> ast::NodeId { + pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent { /*! * Returns the lifetime of the local variable `var_id` */ @@ -170,7 +209,7 @@ impl RegionMaps { } } - pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option { + pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option { //! Returns the scope when temp created by expr_id will be cleaned up // check for a designated rvalue scope @@ -186,7 +225,7 @@ 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(expr_id) { + let mut id = match self.opt_encl_scope(CodeExtent::from_node_id(expr_id)) { Some(i) => i, None => { return None; } }; @@ -214,15 +253,15 @@ impl RegionMaps { scope } - pub fn scopes_intersect(&self, scope1: ast::NodeId, scope2: ast::NodeId) + pub fn scopes_intersect(&self, scope1: CodeExtent, scope2: CodeExtent) -> bool { self.is_subscope_of(scope1, scope2) || self.is_subscope_of(scope2, scope1) } pub fn is_subscope_of(&self, - subscope: ast::NodeId, - superscope: ast::NodeId) + subscope: CodeExtent, + superscope: CodeExtent) -> bool { /*! * Returns true if `subscope` is equal to or is lexically @@ -284,7 +323,7 @@ impl RegionMaps { } (ty::ReScope(sub_scope), ty::ReFree(ref fr)) => { - self.is_subscope_of(sub_scope, fr.scope_id) + self.is_subscope_of(sub_scope, fr.scope) } (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => { @@ -309,9 +348,9 @@ impl RegionMaps { } pub fn nearest_common_ancestor(&self, - scope_a: ast::NodeId, - scope_b: ast::NodeId) - -> Option { + scope_a: CodeExtent, + scope_b: CodeExtent) + -> Option { /*! * Finds the nearest common ancestor (if any) of two scopes. That * is, finds the smallest scope which is greater than or equal to @@ -349,8 +388,8 @@ impl RegionMaps { } } - fn ancestors_of(this: &RegionMaps, scope: ast::NodeId) - -> Vec { + fn ancestors_of(this: &RegionMaps, scope: CodeExtent) + -> Vec { // debug!("ancestors_of(scope={})", scope); let mut result = vec!(scope); let mut scope = scope; @@ -374,7 +413,9 @@ fn record_superlifetime(visitor: &mut RegionResolutionVisitor, _sp: Span) { match visitor.cx.parent { Some(parent_id) => { - visitor.region_maps.record_encl_scope(child_id, parent_id); + let child_scope = CodeExtent::from_node_id(child_id); + let parent_scope = CodeExtent::from_node_id(parent_id); + visitor.region_maps.record_encl_scope(child_scope, parent_scope); } None => {} } @@ -386,7 +427,8 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor, _sp: Span) { match visitor.cx.var_parent { Some(parent_id) => { - visitor.region_maps.record_var_scope(var_id, parent_id); + let parent_scope = CodeExtent::from_node_id(parent_id); + visitor.region_maps.record_var_scope(var_id, parent_scope); } None => { // this can happen in extern fn declarations like @@ -418,11 +460,13 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) { } fn resolve_arm(visitor: &mut RegionResolutionVisitor, arm: &ast::Arm) { - visitor.region_maps.mark_as_terminating_scope(arm.body.id); + let arm_body_scope = CodeExtent::from_node_id(arm.body.id); + visitor.region_maps.mark_as_terminating_scope(arm_body_scope); match arm.guard { Some(ref expr) => { - visitor.region_maps.mark_as_terminating_scope(expr.id); + let guard_scope = CodeExtent::from_node_id(expr.id); + visitor.region_maps.mark_as_terminating_scope(guard_scope); } None => { } } @@ -449,7 +493,8 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) { let stmt_id = stmt_id(stmt); debug!("resolve_stmt(stmt.id={})", stmt_id); - visitor.region_maps.mark_as_terminating_scope(stmt_id); + let stmt_scope = CodeExtent::from_node_id(stmt_id); + visitor.region_maps.mark_as_terminating_scope(stmt_scope); record_superlifetime(visitor, stmt_id, stmt.span); let prev_parent = visitor.cx.parent; @@ -465,73 +510,80 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { let prev_cx = visitor.cx; visitor.cx.parent = Some(expr.id); - match expr.node { - // Conditional or repeating scopes are always terminating - // scopes, meaning that temporaries cannot outlive them. - // This ensures fixed size stacks. + { + let region_maps = &mut visitor.region_maps; + let terminating = |id| { + let scope = CodeExtent::from_node_id(id); + region_maps.mark_as_terminating_scope(scope) + }; + match expr.node { + // Conditional or repeating scopes are always terminating + // scopes, meaning that temporaries cannot outlive them. + // This ensures fixed size stacks. - ast::ExprBinary(ast::BiAnd, _, ref r) | - ast::ExprBinary(ast::BiOr, _, ref r) => { - // For shortcircuiting operators, mark the RHS as a terminating - // scope since it only executes conditionally. - visitor.region_maps.mark_as_terminating_scope(r.id); + ast::ExprBinary(ast::BiAnd, _, ref r) | + ast::ExprBinary(ast::BiOr, _, ref r) => { + // For shortcircuiting operators, mark the RHS as a terminating + // scope since it only executes conditionally. + terminating(r.id); + } + + ast::ExprIf(_, ref then, Some(ref otherwise)) => { + terminating(then.id); + terminating(otherwise.id); + } + + ast::ExprIf(ref expr, ref then, None) => { + terminating(expr.id); + terminating(then.id); + } + + ast::ExprLoop(ref body, _) => { + terminating(body.id); + } + + ast::ExprWhile(ref expr, ref body, _) => { + terminating(expr.id); + terminating(body.id); + } + + ast::ExprForLoop(ref _pat, ref _head, ref body, _) => { + terminating(body.id); + + // The variable parent of everything inside (most importantly, the + // pattern) is the body. + visitor.cx.var_parent = Some(body.id); + } + + ast::ExprMatch(..) => { + visitor.cx.var_parent = Some(expr.id); + } + + ast::ExprAssignOp(..) | ast::ExprIndex(..) | + ast::ExprUnary(..) | ast::ExprCall(..) | ast::ExprMethodCall(..) => { + // FIXME(#6268) Nested method calls + // + // The lifetimes for a call or method call look as follows: + // + // call.id + // - arg0.id + // - ... + // - argN.id + // - call.callee_id + // + // The idea is that call.callee_id represents *the time when + // the invoked function is actually running* and call.id + // represents *the time to prepare the arguments and make the + // call*. See the section "Borrows in Calls" borrowck/doc.rs + // for an extended explanation of why this distinction is + // important. + // + // record_superlifetime(new_cx, expr.callee_id); + } + + _ => {} } - - ast::ExprIf(_, ref then, Some(ref otherwise)) => { - visitor.region_maps.mark_as_terminating_scope(then.id); - visitor.region_maps.mark_as_terminating_scope(otherwise.id); - } - - ast::ExprIf(ref expr, ref then, None) => { - visitor.region_maps.mark_as_terminating_scope(expr.id); - visitor.region_maps.mark_as_terminating_scope(then.id); - } - - ast::ExprLoop(ref body, _) => { - visitor.region_maps.mark_as_terminating_scope(body.id); - } - - ast::ExprWhile(ref expr, ref body, _) => { - visitor.region_maps.mark_as_terminating_scope(expr.id); - visitor.region_maps.mark_as_terminating_scope(body.id); - } - - ast::ExprForLoop(ref _pat, ref _head, ref body, _) => { - visitor.region_maps.mark_as_terminating_scope(body.id); - - // The variable parent of everything inside (most importantly, the - // pattern) is the body. - visitor.cx.var_parent = Some(body.id); - } - - ast::ExprMatch(..) => { - visitor.cx.var_parent = Some(expr.id); - } - - ast::ExprAssignOp(..) | ast::ExprIndex(..) | - ast::ExprUnary(..) | ast::ExprCall(..) | ast::ExprMethodCall(..) => { - // FIXME(#6268) Nested method calls - // - // The lifetimes for a call or method call look as follows: - // - // call.id - // - arg0.id - // - ... - // - argN.id - // - call.callee_id - // - // The idea is that call.callee_id represents *the time when - // the invoked function is actually running* and call.id - // represents *the time to prepare the arguments and make the - // call*. See the section "Borrows in Calls" borrowck/doc.rs - // for an extended explanation of why this distinction is - // important. - // - // record_superlifetime(new_cx, expr.callee_id); - } - - _ => {} - }; + } visit::walk_expr(visitor, expr); visitor.cx = prev_cx; @@ -553,7 +605,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. - visitor.region_maps.record_var_scope(local.id, blk_id); + let blk_scope = CodeExtent::from_node_id(blk_id); + visitor.region_maps.record_var_scope(local.id, blk_scope); // As an exception to the normal rules governing temporary // lifetimes, initializers in a let have a temporary lifetime @@ -618,10 +671,10 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) { match local.init { Some(ref expr) => { - record_rvalue_scope_if_borrow_expr(visitor, &**expr, blk_id); + record_rvalue_scope_if_borrow_expr(visitor, &**expr, blk_scope); if is_binding_pat(&*local.pat) || is_borrowed_ty(&*local.ty) { - record_rvalue_scope(visitor, &**expr, blk_id); + record_rvalue_scope(visitor, &**expr, blk_scope); } } @@ -682,7 +735,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) { fn record_rvalue_scope_if_borrow_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr, - blk_id: ast::NodeId) { + blk_id: CodeExtent) { /*! * If `expr` matches the `E&` grammar, then records an extended * rvalue scope as appropriate: @@ -738,7 +791,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) { fn record_rvalue_scope<'a>(visitor: &mut RegionResolutionVisitor, expr: &'a ast::Expr, - blk_id: ast::NodeId) { + blk_scope: CodeExtent) { /*! * Applied to an expression `expr` if `expr` -- or something * owned or partially owned by `expr` -- is going to be @@ -766,7 +819,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) { // because in trans if we must compile e.g. `*rvalue()` // into a temporary, we request the temporary scope of the // outer expression. - visitor.region_maps.record_rvalue_scope(expr.id, blk_id); + visitor.region_maps.record_rvalue_scope(expr.id, blk_scope); match expr.node { ast::ExprAddrOf(_, ref subexpr) | @@ -809,7 +862,8 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, body.id, visitor.cx.parent); - visitor.region_maps.mark_as_terminating_scope(body.id); + let body_scope = CodeExtent::from_node_id(body.id); + visitor.region_maps.mark_as_terminating_scope(body_scope); let outer_cx = visitor.cx; @@ -873,11 +927,11 @@ 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(NodeMap::new()), + scope_map: RefCell::new(FnvHashMap::new()), var_map: RefCell::new(NodeMap::new()), free_region_map: RefCell::new(FnvHashMap::new()), rvalue_scopes: RefCell::new(NodeMap::new()), - terminating_scopes: RefCell::new(NodeSet::new()), + terminating_scopes: RefCell::new(FnvHashSet::new()), }; { let mut visitor = RegionResolutionVisitor { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 3fc92a84194..fae64ff9242 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -22,6 +22,7 @@ use self::ScopeChain::*; use session::Session; use middle::def; +use middle::region; use middle::resolve::DefMap; use middle::subst; use middle::ty; @@ -43,7 +44,7 @@ pub enum DefRegion { /* lifetime decl */ ast::NodeId), DefLateBoundRegion(ty::DebruijnIndex, /* lifetime decl */ ast::NodeId), - DefFreeRegion(/* block scope */ ast::NodeId, + DefFreeRegion(/* block scope */ region::CodeExtent, /* lifetime decl */ ast::NodeId), } @@ -67,7 +68,7 @@ enum ScopeChain<'a> { LateScope(&'a Vec, Scope<'a>), /// lifetimes introduced by items within a code block are scoped /// to that block. - BlockScope(ast::NodeId, Scope<'a>), + BlockScope(region::CodeExtent, Scope<'a>), RootScope } @@ -195,7 +196,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { } fn visit_block(&mut self, b: &ast::Block) { - self.with(BlockScope(b.id, self.scope), |this| visit::walk_block(this, b)); + self.with(BlockScope(region::CodeExtent::from_node_id(b.id), self.scope), + |this| visit::walk_block(this, b)); } fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) { @@ -307,8 +309,8 @@ impl<'a> LifetimeContext<'a> { let mut scope = self.scope; loop { match *scope { - BlockScope(id, s) => { - return self.resolve_free_lifetime_ref(id, lifetime_ref, s); + BlockScope(blk_scope, s) => { + return self.resolve_free_lifetime_ref(blk_scope, lifetime_ref, s); } RootScope => { @@ -350,19 +352,19 @@ impl<'a> LifetimeContext<'a> { } fn resolve_free_lifetime_ref(&mut self, - scope_id: ast::NodeId, + scope_data: region::CodeExtent, lifetime_ref: &ast::Lifetime, scope: Scope) { // Walk up the scope chain, tracking the outermost free scope, // until we encounter a scope that contains the named lifetime // or we run out of scopes. - let mut scope_id = scope_id; + let mut scope_data = scope_data; let mut scope = scope; let mut search_result = None; loop { match *scope { - BlockScope(id, s) => { - scope_id = id; + BlockScope(blk_scope_data, s) => { + scope_data = blk_scope_data; scope = s; } @@ -383,7 +385,7 @@ impl<'a> LifetimeContext<'a> { match search_result { Some((_depth, decl_id)) => { - let def = DefFreeRegion(scope_id, decl_id); + let def = DefFreeRegion(scope_data, decl_id); self.insert_lifetime(lifetime_ref, def); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 15c292a6b20..11badf7d190 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -46,6 +46,7 @@ use middle::dependency_format; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem}; use middle::lang_items::{FnOnceTraitLangItem, TyDescStructLangItem}; use middle::mem_categorization as mc; +use middle::region; use middle::resolve; use middle::resolve_lifetime; use middle::stability; @@ -837,7 +838,7 @@ pub enum Region { ReFree(FreeRegion), /// A concrete region naming some expression within the current function. - ReScope(NodeId), + ReScope(region::CodeExtent), /// Static data that has an "infinite" lifetime. Top in the region lattice. ReStatic, @@ -987,8 +988,10 @@ impl Region { } #[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] +/// A "free" region `fr` can be interpreted as "some region +/// at least as big as the scope `fr.scope`". pub struct FreeRegion { - pub scope_id: NodeId, + pub scope: region::CodeExtent, pub bound_region: BoundRegion } @@ -3564,7 +3567,7 @@ pub fn ty_region(tcx: &ctxt, pub fn free_region_from_def(free_id: ast::NodeId, def: &RegionParameterDef) -> ty::Region { - ty::ReFree(ty::FreeRegion { scope_id: free_id, + ty::ReFree(ty::FreeRegion { scope: region::CodeExtent::from_node_id(free_id), bound_region: ty::BrNamed(def.def_id, def.name) }) } @@ -5629,12 +5632,14 @@ pub fn construct_parameter_environment<'tcx>( regions: subst::NonerasedRegions(regions) }; + let free_id_scope = region::CodeExtent::from_node_id(free_id); + // // Compute the bounds on Self and the type parameters. // let bounds = generics.to_bounds(tcx, &free_substs); - let bounds = liberate_late_bound_regions(tcx, free_id, &bind(bounds)).value; + let bounds = liberate_late_bound_regions(tcx, free_id_scope, &bind(bounds)).value; let obligations = traits::obligations_for_generics(tcx, traits::ObligationCause::misc(span), &bounds, @@ -5662,7 +5667,7 @@ pub fn construct_parameter_environment<'tcx>( return ty::ParameterEnvironment { free_substs: free_substs, bounds: bounds.types, - implicit_region_bound: ty::ReScope(free_id), + implicit_region_bound: ty::ReScope(free_id_scope), caller_obligations: obligations, selection_cache: traits::SelectionCache::new(), }; @@ -5781,7 +5786,7 @@ impl<'tcx> mc::Typer<'tcx> for ty::ctxt<'tcx> { self.method_map.borrow().contains_key(&typeck::MethodCall::expr(id)) } - fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { + fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { self.region_maps.temporary_scope(rvalue_id) } @@ -5906,7 +5911,7 @@ impl<'tcx> AutoDerefRef<'tcx> { pub fn liberate_late_bound_regions<'tcx, HR>( tcx: &ty::ctxt<'tcx>, - scope_id: ast::NodeId, + scope: region::CodeExtent, value: &HR) -> HR where HR : HigherRankedFoldable<'tcx> @@ -5918,7 +5923,7 @@ pub fn liberate_late_bound_regions<'tcx, HR>( replace_late_bound_regions( tcx, value, - |br, _| ty::ReFree(ty::FreeRegion{scope_id: scope_id, bound_region: br})).0 + |br, _| ty::ReFree(ty::FreeRegion{scope: scope, bound_region: br})).0 } pub fn erase_late_bound_regions<'tcx, HR>( diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 637c1f58157..9190c8bf115 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -113,9 +113,9 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) ty::ReEarlyBound(id, space, index, lifetime.name) } - Some(&rl::DefFreeRegion(scope_id, id)) => { + Some(&rl::DefFreeRegion(scope, id)) => { ty::ReFree(ty::FreeRegion { - scope_id: scope_id, + scope: scope, bound_region: ty::BrNamed(ast_util::local_def(id), lifetime.name) }) diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 553d80852c2..b7e33f60147 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -90,6 +90,7 @@ use middle::mem_categorization::McResult; use middle::mem_categorization; use middle::pat_util::pat_id_map; use middle::pat_util; +use middle::region::CodeExtent; use middle::subst; use middle::subst::{Subst, Substs, VecPerParamSpace, ParamSpace}; use middle::traits; @@ -308,7 +309,7 @@ impl<'a, 'tcx> mem_categorization::Typer<'tcx> for FnCtxt<'a, 'tcx> { fn is_method_call(&self, id: ast::NodeId) -> bool { self.inh.method_map.borrow().contains_key(&typeck::MethodCall::expr(id)) } - fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { + fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { self.tcx().temporary_scope(rvalue_id) } fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow { @@ -529,7 +530,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, // First, we have to replace any bound regions in the fn type with free ones. // The free region references will be bound the node_id of the body block. - let fn_sig = liberate_late_bound_regions(tcx, body.id, fn_sig); + let fn_sig = liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), fn_sig); let arg_tys = fn_sig.inputs.as_slice(); let ret_ty = fn_sig.output; @@ -742,7 +743,8 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("fty (raw): {}", fty.repr(ccx.tcx)); let body_id = method.pe_body().id; - let fty = liberate_late_bound_regions(ccx.tcx, body_id, &ty::bind(fty)).value; + let fty = liberate_late_bound_regions( + ccx.tcx, CodeExtent::from_node_id(body_id), &ty::bind(fty)).value; debug!("fty (liberated): {}", fty.repr(ccx.tcx)); check_bare_fn(ccx, @@ -937,6 +939,8 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_impl_method(impl_trait_ref={})", impl_trait_ref.repr(tcx)); + let impl_m_body_scope = CodeExtent::from_node_id(impl_m_body_id); + // The impl's trait ref may bind late-bound regions from the impl. // Liberate them and assign them the scope of the method body. // @@ -954,7 +958,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // Foo<&'A T> // // where `'A` is the `ReFree` version of `'a`. - let impl_trait_ref = liberate_late_bound_regions(tcx, impl_m_body_id, impl_trait_ref); + let impl_trait_ref = liberate_late_bound_regions(tcx, impl_m_body_scope, impl_trait_ref); debug!("impl_trait_ref (liberated) = {}", impl_trait_ref.repr(tcx)); @@ -1097,7 +1101,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, if !check_region_bounds_on_impl_method(tcx, impl_m_span, impl_m, - impl_m_body_id, + impl_m_body_scope, &trait_m.generics, &impl_m.generics, &trait_to_skol_substs, @@ -1139,7 +1143,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, .map(|impl_param_def| liberate_late_bound_regions( tcx, - impl_m_body_id, + impl_m_body_scope, &ty::bind(ty::bind(impl_param_def.bounds.clone()))).value.value); for (i, (trait_param_bounds, impl_param_bounds)) in trait_bounds.zip(impl_bounds).enumerate() @@ -1205,7 +1209,8 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // that we must liberate the late-bound regions from the impl. let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone()); let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs); - let impl_fty = liberate_late_bound_regions(tcx, impl_m_body_id, &ty::bind(impl_fty)).value; + let impl_fty = liberate_late_bound_regions( + tcx, impl_m_body_scope, &ty::bind(impl_fty)).value; let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone()); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); @@ -1240,7 +1245,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, impl_m: &ty::Method<'tcx>, - impl_m_body_id: ast::NodeId, + impl_m_body_scope: CodeExtent, trait_generics: &ty::Generics<'tcx>, impl_generics: &ty::Generics<'tcx>, trait_to_skol_substs: &Substs<'tcx>, @@ -1331,9 +1336,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // impl, and the method. let impl_bounds = ty::liberate_late_bound_regions( - tcx, - impl_m_body_id, - &ty::bind(ty::bind(impl_bounds))).value.value; + tcx, impl_m_body_scope, &ty::bind(ty::bind(impl_bounds))).value.value; debug!("check_region_bounds_on_impl_method: \ trait_param={} \ @@ -1881,7 +1884,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut bounds_checker = wf::BoundsChecker::new(self, ast_t.span, - self.body_id, + CodeExtent::from_node_id(self.body_id), None); bounds_checker.check_ty(t); @@ -2055,7 +2058,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &ast::Expr) { for &ty in substs.types.iter() { - let default_bound = ty::ReScope(expr.id); + let default_bound = ty::ReScope(CodeExtent::from_node_id(expr.id)); let origin = infer::RelateDefaultParamBound(expr.span, ty); self.register_region_obligation(origin, ty, default_bound); } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 44c11318038..d5908845422 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -120,6 +120,7 @@ and report an error, and it just seems like more mess in the end.) use middle::def; use middle::mem_categorization as mc; +use middle::region::CodeExtent; use middle::traits; use middle::ty::{ReScope}; use middle::ty::{mod, Ty}; @@ -253,7 +254,7 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { if body_id == ast::DUMMY_NODE_ID { tcx.region_maps.var_region(node_id) } else { - ReScope(body_id) + ReScope(CodeExtent::from_node_id(body_id)) } } _ => { @@ -408,7 +409,8 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { for &ty in fn_sig_tys.iter() { let ty = self.resolve_type(ty); debug!("relate_free_regions(t={})", ty.repr(tcx)); - let body_scope = ty::ReScope(body_id); + let body_scope = CodeExtent::from_node_id(body_id); + let body_scope = ty::ReScope(body_scope); let constraints = regionmanip::region_wf_constraints( tcx, @@ -474,7 +476,7 @@ impl<'fcx, 'tcx> mc::Typer<'tcx> for Rcx<'fcx, 'tcx> { self.fcx.inh.method_map.borrow().contains_key(&MethodCall::expr(id)) } - fn temporary_scope(&self, id: ast::NodeId) -> Option { + fn temporary_scope(&self, id: ast::NodeId) -> Option { self.tcx().region_maps.temporary_scope(id) } @@ -587,7 +589,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { let expr_ty = rcx.resolve_node_type(expr.id); type_must_outlive(rcx, infer::ExprTypeIsNotInScope(expr_ty, expr.span), - expr_ty, ty::ReScope(expr.id)); + expr_ty, ty::ReScope(CodeExtent::from_node_id(expr.id))); let method_call = MethodCall::expr(expr.id); let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call); @@ -608,7 +610,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(expr.id)); + expr.id, ty::ReScope(CodeExtent::from_node_id(expr.id))); } } /* @@ -695,8 +697,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { }; match base_ty.sty { ty::ty_rptr(r_ptr, _) => { - mk_subregion_due_to_dereference(rcx, expr.span, - ty::ReScope(expr.id), r_ptr); + mk_subregion_due_to_dereference( + rcx, expr.span, ty::ReScope(CodeExtent::from_node_id(expr.id)), r_ptr); } _ => {} } @@ -732,7 +734,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(expr.id)); + ty0, ty::ReScope(CodeExtent::from_node_id(expr.id))); visit::walk_expr(rcx, expr); } @@ -772,7 +774,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { let pat_ty = rcx.resolve_node_type(pat.id); let pat_cmt = mc.cat_rvalue(pat.id, pat.span, - ty::ReScope(body.id), + ty::ReScope(CodeExtent::from_node_id(body.id)), pat_ty); link_pattern(rcx, mc, pat_cmt, &**pat); } @@ -781,7 +783,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { type_of_node_must_outlive(rcx, infer::AddrOf(expr.span), head.id, - ty::ReScope(expr.id)); + ty::ReScope(CodeExtent::from_node_id(expr.id))); let repeating_scope = rcx.set_repeating_scope(body.id); rcx.visit_block(&**body); @@ -866,7 +868,7 @@ fn check_expr_fn_block(rcx: &mut Rcx, // outlive the appropriate temporary scope. let s = rcx.repeating_scope; rcx.fcx.mk_subr(infer::InfStackClosure(expr.span), - bounds.region_bound, ty::ReScope(s)); + bounds.region_bound, ty::ReScope(CodeExtent::from_node_id(s))); } }); } @@ -1089,7 +1091,7 @@ fn constrain_callee(rcx: &mut Rcx, callee_id: ast::NodeId, call_expr: &ast::Expr, callee_expr: &ast::Expr) { - let call_region = ty::ReScope(call_expr.id); + let call_region = ty::ReScope(CodeExtent::from_node_id(call_expr.id)); let callee_ty = rcx.resolve_node_type(callee_id); match callee_ty.sty { @@ -1147,7 +1149,7 @@ fn constrain_call<'a, I: Iterator<&'a ast::Expr>>(rcx: &mut Rcx, // call occurs. // // FIXME(#6268) to support nested method calls, should be callee_id - let callee_scope = call_expr.id; + let callee_scope = CodeExtent::from_node_id(call_expr.id); let callee_region = ty::ReScope(callee_scope); debug!("callee_region={}", callee_region.repr(tcx)); @@ -1191,7 +1193,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, * this is a region pointer being dereferenced, the lifetime of * the pointer includes the deref expr. */ - let r_deref_expr = ty::ReScope(deref_expr.id); + let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id)); for i in range(0u, derefs) { debug!("constrain_autoderefs(deref_expr=?, derefd_ty={}, derefs={}/{}", rcx.fcx.infcx().ty_to_string(derefd_ty), @@ -1271,7 +1273,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(index_expr.id); + let r_index_expr = ty::ReScope(CodeExtent::from_node_id(index_expr.id)); match indexed_ty.sty { ty::ty_rptr(r_ptr, mt) => match mt.ty.sty { ty::ty_vec(_, None) | ty::ty_str => { @@ -1425,7 +1427,7 @@ fn link_autoref(rcx: &Rcx, fn link_by_ref(rcx: &Rcx, expr: &ast::Expr, - callee_scope: ast::NodeId) { + callee_scope: CodeExtent) { /*! * Computes the guarantor for cases where the `expr` is * being passed by implicit reference and must outlive diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs index 5cc619bba26..d9c6c3cb626 100644 --- a/src/librustc/middle/typeck/check/wf.rs +++ b/src/librustc/middle/typeck/check/wf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::region; use middle::subst; use middle::subst::{Subst}; use middle::traits; @@ -118,8 +119,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { self.with_fcx(item, |this, fcx| { let variants = lookup_fields(fcx); - let mut bounds_checker = BoundsChecker::new(fcx, item.span, - item.id, Some(&mut this.cache)); + let mut bounds_checker = BoundsChecker::new(fcx, + item.span, + region::CodeExtent::from_node_id(item.id), + Some(&mut this.cache)); for variant in variants.iter() { for field in variant.fields.iter() { // Regions are checked below. @@ -154,8 +157,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { item: &ast::Item) { self.with_fcx(item, |this, fcx| { - let mut bounds_checker = BoundsChecker::new(fcx, item.span, - item.id, Some(&mut this.cache)); + let mut bounds_checker = BoundsChecker::new(fcx, + item.span, + region::CodeExtent::from_node_id(item.id), + Some(&mut this.cache)); let polytype = ty::lookup_item_type(fcx.tcx(), local_def(item.id)); let item_ty = polytype.ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); bounds_checker.check_traits_in_ty(item_ty); @@ -166,8 +171,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { item: &ast::Item) { self.with_fcx(item, |this, fcx| { - let mut bounds_checker = BoundsChecker::new(fcx, item.span, - item.id, Some(&mut this.cache)); + let item_scope = region::CodeExtent::from_node_id(item.id); + + let mut bounds_checker = BoundsChecker::new(fcx, + item.span, + item_scope, + Some(&mut this.cache)); // Find the impl self type as seen from the "inside" -- // that is, with all type parameters converted from bound @@ -175,7 +184,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // liberated. let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); - let self_ty = liberate_late_bound_regions(fcx.tcx(), item.id, &ty::bind(self_ty)).value; + let self_ty = liberate_late_bound_regions( + fcx.tcx(), item_scope, &ty::bind(self_ty)).value; bounds_checker.check_traits_in_ty(self_ty); @@ -186,7 +196,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { Some(t) => { t } }; let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs); - let trait_ref = liberate_late_bound_regions(fcx.tcx(), item.id, &trait_ref); + let trait_ref = liberate_late_bound_regions(fcx.tcx(), item_scope, &trait_ref); // There are special rules that apply to drop. if @@ -257,7 +267,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { pub struct BoundsChecker<'cx,'tcx:'cx> { fcx: &'cx FnCtxt<'cx,'tcx>, span: Span, - scope_id: ast::NodeId, + scope: region::CodeExtent, binding_count: uint, cache: Option<&'cx mut HashSet>>, } @@ -265,10 +275,10 @@ pub struct BoundsChecker<'cx,'tcx:'cx> { impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>, span: Span, - scope_id: ast::NodeId, + scope: region::CodeExtent, cache: Option<&'cx mut HashSet>>) -> BoundsChecker<'cx,'tcx> { - BoundsChecker { fcx: fcx, span: span, scope_id: scope_id, + BoundsChecker { fcx: fcx, span: span, scope: scope, cache: cache, binding_count: 0 } } @@ -383,7 +393,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { ty::ty_closure(box ty::ClosureTy{sig: ref fn_sig, ..}) => { self.binding_count += 1; - let fn_sig = liberate_late_bound_regions(self.fcx.tcx(), self.scope_id, fn_sig); + let fn_sig = liberate_late_bound_regions(self.fcx.tcx(), self.scope, fn_sig); debug!("late-bound regions replaced: {}", fn_sig.repr(self.tcx())); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 90ad0d2f3e5..13a0bf0bdcb 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -35,6 +35,7 @@ use self::CreateTypeParametersForAssociatedTypesFlag::*; use metadata::csearch; use middle::def; use middle::lang_items::SizedTraitLangItem; +use middle::region; use middle::resolve_lifetime; use middle::subst; use middle::subst::{Substs}; @@ -2161,6 +2162,8 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( _ => typ, }; + let body_scope = region::CodeExtent::from_node_id(body_id); + // "Required type" comes from the trait definition. It may // contain late-bound regions from the method, but not the // trait (since traits only have early-bound region @@ -2168,22 +2171,16 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( assert!(!ty::type_escapes_depth(required_type, 1)); let required_type_free = ty::liberate_late_bound_regions( - crate_context.tcx, - body_id, - &ty::bind(required_type)).value; + crate_context.tcx, body_scope, &ty::bind(required_type)).value; // The "base type" comes from the impl. It may have late-bound // regions from the impl or the method. let base_type_free = // liberate impl regions: ty::liberate_late_bound_regions( - crate_context.tcx, - body_id, - &ty::bind(ty::bind(base_type))).value.value; + crate_context.tcx, body_scope, &ty::bind(ty::bind(base_type))).value.value; let base_type_free = // liberate method regions: ty::liberate_late_bound_regions( - crate_context.tcx, - body_id, - &ty::bind(base_type_free)).value; + crate_context.tcx, body_scope, &ty::bind(base_type_free)).value; debug!("required_type={} required_type_free={} \ base_type={} base_type_free={}", diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 7a7a7c79674..bc36a2bd801 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -301,11 +301,11 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { debug!("free_regions_from_same_fn(sub={}, sup={})", sub, sup); let (scope_id, fr1, fr2) = match (sub, sup) { (ReFree(fr1), ReFree(fr2)) => { - if fr1.scope_id != fr2.scope_id { + if fr1.scope != fr2.scope { return None } - assert!(fr1.scope_id == fr2.scope_id); - (fr1.scope_id, fr1, fr2) + assert!(fr1.scope == fr2.scope); + (fr1.scope.node_id(), fr1, fr2) }, _ => return None }; diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 5452a99127f..6a447d467cf 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -18,6 +18,7 @@ pub use self::RegionResolutionError::*; pub use self::VarValue::*; use self::Classification::*; +use middle::region; use middle::ty; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; @@ -747,11 +748,11 @@ 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: - match self.tcx.region_maps.nearest_common_ancestor(fr.scope_id, s_id) { + match self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id) { // 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: - Some(r_id) if r_id == fr.scope_id => f, + Some(r_id) if r_id == fr.scope => f, // otherwise, we don't know what the free region is, // so we must conservatively say the LUB is static: @@ -856,8 +857,8 @@ 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. - match self.tcx.region_maps.nearest_common_ancestor(fr.scope_id, s_id) { - Some(r_id) if r_id == fr.scope_id => Ok(s), + match self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id) { + Some(r_id) if r_id == fr.scope => Ok(s), _ => Err(ty::terr_regions_no_overlap(b, a)) } } @@ -909,7 +910,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { Ok(ty::ReFree(*b)) } else { this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b), - a.scope_id, b.scope_id) + a.scope, b.scope) } } } @@ -917,8 +918,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn intersect_scopes(&self, region_a: ty::Region, region_b: ty::Region, - scope_a: ast::NodeId, - scope_b: ast::NodeId) -> cres<'tcx, Region> + scope_a: region::CodeExtent, + scope_b: region::CodeExtent) -> cres<'tcx, Region> { // We want to generate the intersection of two // scopes or two free regions. So, if one of diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 76055372a61..761a1f66501 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -84,8 +84,8 @@ fn item_scope_tag(item: &ast::Item) -> &'static str { pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) -> (String, Option) { return match region { - ReScope(node_id) => { - match cx.map.find(node_id) { + ReScope(scope) => { + match cx.map.find(scope.node_id()) { Some(ast_map::NodeBlock(ref blk)) => { explain_span(cx, "block", blk.span) } @@ -112,7 +112,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) } Some(_) | None => { // this really should not happen - (format!("unknown scope: {}. Please report a bug.", node_id), None) + (format!("unknown scope: {}. Please report a bug.", scope), None) } } } @@ -129,7 +129,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) } }; - match cx.map.find(fr.scope_id) { + match cx.map.find(fr.scope.node_id()) { Some(ast_map::NodeBlock(ref blk)) => { let (msg, opt_span) = explain_span(cx, "block", blk.span); (format!("{} {}", prefix, msg), opt_span) @@ -141,7 +141,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) } Some(_) | None => { // this really should not happen - (format!("{} node {}", prefix, fr.scope_id), None) + (format!("{} unknown free region bounded by scope {}", prefix, fr.scope), None) } } } @@ -879,7 +879,7 @@ impl<'tcx> UserString<'tcx> for ty::Region { impl<'tcx> Repr<'tcx> for ty::FreeRegion { fn repr(&self, tcx: &ctxt) -> String { format!("ReFree({}, {})", - self.scope_id, + self.scope.node_id(), self.bound_region.repr(tcx)) } } diff --git a/src/librustc_trans/test.rs b/src/librustc_trans/test.rs index 984c1f99720..1e8c1fd1478 100644 --- a/src/librustc_trans/test.rs +++ b/src/librustc_trans/test.rs @@ -18,7 +18,7 @@ use driver::diagnostic; use driver::diagnostic::Emitter; use driver::driver; use middle::lang_items; -use middle::region; +use middle::region::{mod, CodeExtent}; use middle::resolve; use middle::resolve_lifetime; use middle::stability; @@ -149,7 +149,9 @@ impl<'a, 'tcx> Env<'a, 'tcx> { pub fn create_region_hierarchy(&self, rh: &RH) { for child_rh in rh.sub.iter() { self.create_region_hierarchy(child_rh); - self.infcx.tcx.region_maps.record_encl_scope(child_rh.id, rh.id); + self.infcx.tcx.region_maps.record_encl_scope( + CodeExtent::from_node_id(child_rh.id), + CodeExtent::from_node_id(rh.id)); } } @@ -321,12 +323,12 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> { - ty::mk_imm_rptr(self.infcx.tcx, ty::ReScope(id), ty::mk_int()) + ty::mk_imm_rptr(self.infcx.tcx, ty::ReScope(CodeExtent::from_node_id(id)), ty::mk_int()) } pub fn re_free(&self, nid: ast::NodeId, id: uint) -> ty::Region { - ty::ReFree(ty::FreeRegion {scope_id: nid, - bound_region: ty::BrAnon(id)}) + ty::ReFree(ty::FreeRegion { scope: CodeExtent::from_node_id(nid), + bound_region: ty::BrAnon(id)}) } pub fn t_rptr_free(&self, nid: ast::NodeId, id: uint) -> Ty<'tcx> { diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index d6124736586..b0235be7497 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -26,6 +26,7 @@ use trans::common; use trans::common::{Block, FunctionContext, ExprId, NodeInfo}; use trans::debuginfo; use trans::glue; +use middle::region; use trans::type_::Type; use middle::ty::{mod, Ty}; use std::fmt; @@ -137,7 +138,8 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { assert_eq!(self.ccx .tcx() .region_maps - .opt_encl_scope(debug_loc.id), + .opt_encl_scope(region::CodeExtent::from_node_id(debug_loc.id)) + .map(|s|s.node_id()), top_scope); } @@ -1096,7 +1098,7 @@ pub fn temporary_scope(tcx: &ty::ctxt, -> ScopeId { match tcx.region_maps.temporary_scope(id) { Some(scope) => { - let r = AstScope(scope); + let r = AstScope(scope.node_id()); debug!("temporary_scope({}) = {}", id, r); r } @@ -1110,7 +1112,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)); + let r = AstScope(tcx.region_maps.var_scope(id).node_id()); debug!("var_scope({}) = {}", id, r); r } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 9cd249f1e00..235805a7c83 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -21,6 +21,7 @@ use llvm::{True, False, Bool}; use middle::def; use middle::lang_items::LangItem; use middle::mem_categorization as mc; +use middle::region; use middle::subst; use middle::subst::{Subst, Substs}; use trans::base; @@ -490,7 +491,7 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> { self.tcx().method_map.borrow().contains_key(&typeck::MethodCall::expr(id)) } - fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { + fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { self.tcx().region_maps.temporary_scope(rvalue_id) }