pub use self::DefIdSource::*;
+use middle::region;
use middle::subst;
use middle::subst::VecPerParamSpace;
use middle::ty::{mod, Ty};
}
'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
}
}
+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<T> {
match next(st) {
use std::cell::RefCell;
+use middle::region;
use middle::subst;
use middle::subst::VecPerParamSpace;
use middle::ty::ParamTy;
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");
}
}
+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) => {
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 {
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;
None => { }
}
- self.check_for_conflicting_loans(borrow_id);
+ self.check_for_conflicting_loans(region::CodeExtent::from_node_id(borrow_id));
}
fn mutate(&mut self,
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
}
fn each_in_scope_loan_affecting_path(&self,
- scope_id: ast::NodeId,
+ scope: region::CodeExtent,
loan_path: &LoanPath,
op: |&Loan| -> bool)
-> bool {
// 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 {
}
}
- 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 {
return true;
}
- pub fn loans_generated_by(&self, scope_id: ast::NodeId) -> Vec<uint> {
+ pub fn loans_generated_by(&self, scope: region::CodeExtent) -> Vec<uint> {
//! 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);
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");
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
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
});
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;
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,
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,
impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option<ast::NodeId>) -> 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));
}
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)))
temp_scope
}
mc::cat_upvar(..) => {
- ty::ReScope(self.item_scope_id)
+ ty::ReScope(self.item_scope)
}
mc::cat_static_item => {
ty::ReStatic
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};
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(),
};
move_data: move_data::MoveData,
move_error_collector: move_error::MoveErrorCollector<'tcx>,
all_loans: Vec<Loan>,
- 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> {
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
};
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);
}
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,
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};
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);
loan_path: Rc<LoanPath>,
kind: ty::BorrowKind,
restricted_paths: Vec<Rc<LoanPath>>,
- 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,
}
}
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),
}
}
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
}
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);
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);
use middle::cfg::*;
use middle::def;
use middle::graph;
+use middle::region::CodeExtent;
use middle::typeck;
use middle::ty;
use syntax::ast;
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);
}
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};
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);
// 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);
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);
match f.onceness {
ast::Many => {
self.borrow_expr(callee,
- ty::ReScope(call.id),
+ ty::ReScope(call_scope),
ty::UniqueImmBorrow,
ClosureInvocation);
}
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);
}
// 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() {
pub use self::categorization::*;
use middle::def;
+use middle::region;
use middle::ty::{mod, Ty};
use middle::typeck;
use util::nodemap::{DefIdMap, NodeMap};
fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option<Ty<'tcx>>;
fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>;
fn is_method_call(&self, id: ast::NodeId) -> bool;
- fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId>;
+ fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>;
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow;
fn capture_mode(&self, closure_expr_id: ast::NodeId)
-> ast::CaptureClause;
// 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
});
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};
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.
for dynamic checks and/or arbitrary amounts of stack space.
*/
pub struct RegionMaps {
- scope_map: RefCell<NodeMap<ast::NodeId>>,
- var_map: RefCell<NodeMap<ast::NodeId>>,
+ scope_map: RefCell<FnvHashMap<CodeExtent, CodeExtent>>,
+ var_map: RefCell<NodeMap<CodeExtent>>,
free_region_map: RefCell<FnvHashMap<FreeRegion, Vec<FreeRegion>>>,
- rvalue_scopes: RefCell<NodeMap<ast::NodeId>>,
- terminating_scopes: RefCell<NodeSet>,
+ rvalue_scopes: RefCell<NodeMap<CodeExtent>>,
+ terminating_scopes: RefCell<FnvHashSet<CodeExtent>>,
}
pub struct Context {
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
self.terminating_scopes.borrow_mut().insert(scope_id);
}
- pub fn opt_encl_scope(&self, id: ast::NodeId) -> Option<ast::NodeId> {
+ pub fn opt_encl_scope(&self, id: CodeExtent) -> Option<CodeExtent> {
//! 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,
}
}
- 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`
*/
}
}
- pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option<ast::NodeId> {
+ pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option<CodeExtent> {
//! Returns the scope when temp created by expr_id will be cleaned up
// check for a designated rvalue scope
// 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; }
};
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
}
(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)) => {
}
pub fn nearest_common_ancestor(&self,
- scope_a: ast::NodeId,
- scope_b: ast::NodeId)
- -> Option<ast::NodeId> {
+ scope_a: CodeExtent,
+ scope_b: CodeExtent)
+ -> Option<CodeExtent> {
/*!
* Finds the nearest common ancestor (if any) of two scopes. That
* is, finds the smallest scope which is greater than or equal to
}
}
- fn ancestors_of(this: &RegionMaps, scope: ast::NodeId)
- -> Vec<ast::NodeId> {
+ fn ancestors_of(this: &RegionMaps, scope: CodeExtent)
+ -> Vec<CodeExtent> {
// debug!("ancestors_of(scope={})", scope);
let mut result = vec!(scope);
let mut scope = scope;
_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 => {}
}
_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
}
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 => { }
}
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;
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.
-
- 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);
- }
+ {
+ 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.
+ terminating(r.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 then, Some(ref otherwise)) => {
+ terminating(then.id);
+ terminating(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::ExprIf(ref expr, ref then, None) => {
+ terminating(expr.id);
+ terminating(then.id);
+ }
- ast::ExprLoop(ref body, _) => {
- visitor.region_maps.mark_as_terminating_scope(body.id);
- }
+ ast::ExprLoop(ref body, _) => {
+ terminating(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::ExprWhile(ref expr, ref body, _) => {
+ terminating(expr.id);
+ terminating(body.id);
+ }
- ast::ExprForLoop(ref _pat, ref _head, ref body, _) => {
- visitor.region_maps.mark_as_terminating_scope(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);
- }
+ // 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::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::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;
// 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
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);
}
}
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:
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
// 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) |
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;
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 {
use session::Session;
use middle::def;
+use middle::region;
use middle::resolve::DefMap;
use middle::subst;
use middle::ty;
/* 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),
}
LateScope(&'a Vec<ast::LifetimeDef>, 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
}
}
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) {
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 => {
}
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;
}
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);
}
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;
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,
}
#[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
}
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) })
}
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,
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(),
};
self.method_map.borrow().contains_key(&typeck::MethodCall::expr(id))
}
- fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId> {
+ fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent> {
self.region_maps.temporary_scope(rvalue_id)
}
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>
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>(
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)
})
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;
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<ast::NodeId> {
+ fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
self.tcx().temporary_scope(rvalue_id)
}
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
// 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;
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,
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.
//
// 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));
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,
.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()
// 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);
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>,
// 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={} \
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);
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);
}
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};
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))
}
}
_ => {
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,
self.fcx.inh.method_map.borrow().contains_key(&MethodCall::expr(id))
}
- fn temporary_scope(&self, id: ast::NodeId) -> Option<ast::NodeId> {
+ fn temporary_scope(&self, id: ast::NodeId) -> Option<CodeExtent> {
self.tcx().region_maps.temporary_scope(id)
}
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);
// 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)));
}
}
/*
};
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);
}
_ => {}
}
// 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);
}
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);
}
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);
// 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)));
}
});
}
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 {
// 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));
* 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),
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 => {
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
// 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;
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.
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);
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
// 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);
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
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<Ty<'tcx>>>,
}
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<Ty<'tcx>>>)
-> BoundsChecker<'cx,'tcx> {
- BoundsChecker { fcx: fcx, span: span, scope_id: scope_id,
+ BoundsChecker { fcx: fcx, span: span, scope: scope,
cache: cache, binding_count: 0 }
}
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()));
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};
_ => 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
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={}",
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
};
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};
// 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:
// 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))
}
}
Ok(ty::ReFree(*b))
} else {
this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
- a.scope_id, b.scope_id)
+ a.scope, b.scope)
}
}
}
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
pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
-> (String, Option<Span>) {
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)
}
}
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)
}
}
}
}
};
- 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)
}
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)
}
}
}
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))
}
}
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;
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));
}
}
}
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> {
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;
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);
}
-> 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
}
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
}
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;
self.tcx().method_map.borrow().contains_key(&typeck::MethodCall::expr(id))
}
- fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId> {
+ fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent> {
self.tcx().region_maps.temporary_scope(rvalue_id)
}