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.)
This commit is contained in:
Felix S. Klock II 2014-11-18 14:22:59 +01:00
parent b825b3496a
commit 5ff9087e05
25 changed files with 427 additions and 276 deletions

View File

@ -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<T> {
match next(st) {

View File

@ -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) => {

View File

@ -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 {

View File

@ -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<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);
@ -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
});

View File

@ -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<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));
@ -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

View File

@ -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<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> {
@ -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,

View File

@ -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<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,
}
@ -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
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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() {

View File

@ -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<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;
@ -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
});

View File

@ -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<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 {
@ -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<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,
@ -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<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
@ -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<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
@ -349,8 +388,8 @@ impl RegionMaps {
}
}
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;
@ -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 {

View File

@ -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<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
}
@ -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);
}

View File

@ -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<ast::NodeId> {
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent> {
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>(

View File

@ -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)
})

View File

@ -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<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 {
@ -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);
}

View File

@ -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<ast::NodeId> {
fn temporary_scope(&self, id: ast::NodeId) -> Option<CodeExtent> {
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

View File

@ -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<Ty<'tcx>>>,
}
@ -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<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 }
}
@ -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()));

View File

@ -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={}",

View File

@ -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
};

View File

@ -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

View File

@ -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<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)
}
@ -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))
}
}

View File

@ -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> {

View File

@ -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
}

View File

@ -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<ast::NodeId> {
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent> {
self.tcx().region_maps.temporary_scope(rvalue_id)
}