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:
parent
b825b3496a
commit
5ff9087e05
@ -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) {
|
||||
|
@ -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) => {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
});
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
});
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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>(
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()));
|
||||
|
@ -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={}",
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user