Added DestructionScope variant to CodeExtent, representing the area

immediately surrounding a node that is a terminating_scope
(e.g. statements, looping forms) during which the destructors run (the
destructors for temporaries from the execution of that node, that is).

Introduced DestructionScopeData newtype wrapper around ast::NodeId, to
preserve invariant that FreeRegion and ScopeChain::BlockScope carry
destruction scopes (rather than arbitrary CodeExtents).

Insert DestructionScope and block Remainder into enclosing CodeExtents
hierarchy.

Add more doc for DestructionScope, complete with ASCII art.

Switch to constructing DestructionScope rather than Misc in a number
of places, mostly related to `ty::ReFree` creation, and use
destruction-scopes of node-ids at various calls to
liberate_late_bound_regions.

middle::resolve_lifetime: Map BlockScope to DestructionScope in `fn resolve_free_lifetime`.

Add the InnermostDeclaringBlock and InnermostEnclosingExpr enums that
are my attempt to clarify the region::Context structure, and that
later commmts build upon.

Improve the debug output for `CodeExtent` attached to `ty::Region::ReScope`.

Loosened an assertion in `rustc_trans::trans::cleanup` to account for
`DestructionScope`.  (Perhaps this should just be switched entirely
over to `DestructionScope`, rather than allowing for either `Misc` or
`DestructionScope`.)

----

Even though the DestructionScope is new, this particular commit should
not actually change the semantics of any current code.
This commit is contained in:
Felix S. Klock II 2014-11-25 17:02:20 +01:00
parent bdb9f3e266
commit 81383bd869
18 changed files with 253 additions and 73 deletions

View File

@ -349,7 +349,7 @@ fn parse_region_<F>(st: &mut PState, conv: &mut F) -> ty::Region where
}
'f' => {
assert_eq!(next(st), '[');
let scope = parse_scope(st);
let scope = parse_destruction_scope_data(st);
assert_eq!(next(st), '|');
let br = parse_bound_region_(st, conv);
assert_eq!(next(st), ']');
@ -377,6 +377,10 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent {
let node_id = parse_uint(st) as ast::NodeId;
region::CodeExtent::Misc(node_id)
}
'D' => {
let node_id = parse_uint(st) as ast::NodeId;
region::CodeExtent::DestructionScope(node_id)
}
'B' => {
let node_id = parse_uint(st) as ast::NodeId;
let first_stmt_index = parse_uint(st);
@ -389,6 +393,11 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent {
}
}
fn parse_destruction_scope_data(st: &mut PState) -> region::DestructionScopeData {
let node_id = parse_uint(st) as ast::NodeId;
region::DestructionScopeData::new(node_id)
}
fn parse_opt<'a, 'tcx, T, F>(st: &mut PState<'a, 'tcx>, f: F) -> Option<T> where
F: FnOnce(&mut PState<'a, 'tcx>) -> T,
{

View File

@ -251,7 +251,7 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
}
ty::ReFree(ref fr) => {
mywrite!(w, "f[");
enc_scope(w, cx, fr.scope);
enc_destruction_scope_data(w, fr.scope);
mywrite!(w, "|");
enc_bound_region(w, cx, fr.bound_region);
mywrite!(w, "]");
@ -279,9 +279,15 @@ fn enc_scope(w: &mut SeekableMemWriter, _cx: &ctxt, scope: region::CodeExtent) {
region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id),
region::CodeExtent::Remainder(region::BlockRemainder {
block: b, first_statement_index: i }) => mywrite!(w, "B{}{}", b, i),
region::CodeExtent::DestructionScope(node_id) => mywrite!(w, "D{}", node_id),
}
}
fn enc_destruction_scope_data(w: &mut SeekableMemWriter,
d: region::DestructionScopeData) {
mywrite!(w, "{}", d.node_id);
}
fn enc_bound_region(w: &mut SeekableMemWriter, cx: &ctxt, br: ty::BoundRegion) {
match br {
ty::BrAnon(idx) => {

View File

@ -499,6 +499,12 @@ impl tr for region::CodeExtent {
}
}
impl tr for region::DestructionScopeData {
fn tr(&self, dcx: &DecodeContext) -> region::DestructionScopeData {
region::DestructionScopeData { node_id: dcx.tr_id(self.node_id) }
}
}
impl tr for ty::BoundRegion {
fn tr(&self, dcx: &DecodeContext) -> ty::BoundRegion {
match *self {

View File

@ -304,7 +304,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
return None
}
assert!(fr1.scope == fr2.scope);
(fr1.scope.node_id(), fr1, fr2)
(fr1.scope.node_id, fr1, fr2)
},
_ => return None
};

View File

@ -760,11 +760,12 @@ 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, s_id) {
let fr_scope = fr.scope.to_code_extent();
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 => 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:
@ -865,8 +866,9 @@ 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, s_id) {
Some(r_id) if r_id == fr.scope => Ok(s),
let fr_scope = fr.scope.to_code_extent();
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))
}
}
@ -915,7 +917,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
Ok(ty::ReFree(*b))
} else {
this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
a.scope, b.scope)
a.scope.to_code_extent(),
b.scope.to_code_extent())
}
}
}

View File

@ -112,7 +112,7 @@ use self::VarKind::*;
use middle::def::*;
use middle::mem_categorization::Typer;
use middle::pat_util;
use middle::region::CodeExtent;
use middle::region;
use middle::ty;
use middle::ty::ClosureTyper;
use lint;
@ -1514,7 +1514,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
let fn_ret =
ty::liberate_late_bound_regions(
self.ir.tcx,
CodeExtent::from_node_id(body.id),
region::DestructionScopeData::new(body.id),
&self.fn_ret(id));
match fn_ret {

View File

@ -760,7 +760,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
// Region of environment pointer
let env_region = ty::ReFree(ty::FreeRegion {
scope: region::CodeExtent::from_node_id(fn_body_id),
// The environment of a closure is guaranteed to
// outlive any bindings introduced in the body of the
// closure itself.
scope: region::DestructionScopeData::new(fn_body_id),
bound_region: ty::BrEnv
});

View File

@ -27,11 +27,66 @@ use syntax::{ast, visit};
use syntax::ast::{Block, Item, FnDecl, NodeId, Arm, Pat, Stmt, Expr, Local};
use syntax::ast_util::{stmt_id};
use syntax::ast_map;
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.
///
/// `Misc(node_id)`: Any AST node that has any extent at all has the
/// `Misc(node_id)` extent. Other variants represent special cases not
/// immediately derivable from the abstract syntax tree structure.
///
/// `DestructionScope(node_id)` represents the extent of destructors
/// implicitly-attached to `node_id` that run immediately after the
/// expression for `node_id` itself. Not every AST node carries a
/// `DestructionScope`, but those that are `terminating_scopes` do;
/// see discussion with `RegionMaps`.
///
/// `Remainder(BlockRemainder { block, statement_index })` represents
/// the extent of user code running immediately after the initializer
/// expression for the indexed statement, until the end of the block.
///
/// So: the following code can be broken down into the extents beneath:
/// ```
/// let a = f().g( 'b: { let x = d(); let y = d(); x.h(y) } ) ;
/// ```
///
/// +-+ (D12.)
/// +-+ (D11.)
/// +---------+ (R10.)
/// +-+ (D9.)
/// +----------+ (M8.)
/// +----------------------+ (R7.)
/// +-+ (D6.)
/// +----------+ (M5.)
/// +-----------------------------------+ (M4.)
/// +--------------------------------------------------+ (M3.)
/// +--+ (M2.)
/// +-----------------------------------------------------------+ (M1.)
///
/// (M1.): Misc extent of the whole `let a = ...;` statement.
/// (M2.): Misc extent of the `f()` expression.
/// (M3.): Misc extent of the `f().g(..)` expression.
/// (M4.): Misc extent of the block labelled `'b:`.
/// (M5.): Misc extent of the `let x = d();` statement
/// (D6.): DestructionScope for temporaries created during M5.
/// (R7.): Remainder extent for block `'b:`, stmt 0 (let x = ...).
/// (M8.): Misc Extent of the `let y = d();` statement.
/// (D9.): DestructionScope for temporaries created during M8.
/// (R10.): Remainder extent for block `'b:`, stmt 1 (let y = ...).
/// (D11.): DestructionScope for temporaries and bindings from block `'b:`.
/// (D12.): DestructionScope for temporaries created during M1 (e.g. f()).
///
/// Note that while the above picture shows the destruction scopes
/// as following their corresponding misc extents, in the internal
/// data structures of the compiler the destruction scopes are
/// represented as enclosing parents. This is sound because we use the
/// enclosing parent relationship just to ensure that referenced
/// values live long enough; phrased another way, the starting point
/// of each range is not really the important thing in the above
/// picture, but rather the ending point.
///
/// 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
@ -40,7 +95,24 @@ use syntax::visit::{Visitor, FnKind};
RustcDecodable, Debug, Copy)]
pub enum CodeExtent {
Misc(ast::NodeId),
Remainder(BlockRemainder),
DestructionScope(ast::NodeId), // extent of destructors for temporaries of node-id
Remainder(BlockRemainder)
}
/// extent of destructors for temporaries of node-id
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
RustcDecodable, Debug, Copy)]
pub struct DestructionScopeData {
pub node_id: ast::NodeId
}
impl DestructionScopeData {
pub fn new(node_id: ast::NodeId) -> DestructionScopeData {
DestructionScopeData { node_id: node_id }
}
pub fn to_code_extent(&self) -> CodeExtent {
CodeExtent::DestructionScope(self.node_id)
}
}
/// Represents a subscope of `block` for a binding that is introduced
@ -82,6 +154,7 @@ impl CodeExtent {
match *self {
CodeExtent::Misc(node_id) => node_id,
CodeExtent::Remainder(br) => br.block,
CodeExtent::DestructionScope(node_id) => node_id,
}
}
@ -95,6 +168,8 @@ impl CodeExtent {
CodeExtent::Remainder(br) =>
CodeExtent::Remainder(BlockRemainder {
block: f_id(br.block), first_statement_index: br.first_statement_index }),
CodeExtent::DestructionScope(node_id) =>
CodeExtent::DestructionScope(f_id(node_id)),
}
}
@ -105,7 +180,8 @@ impl CodeExtent {
match ast_map.find(self.node_id()) {
Some(ast_map::NodeBlock(ref blk)) => {
match *self {
CodeExtent::Misc(_) => Some(blk.span),
CodeExtent::Misc(_) |
CodeExtent::DestructionScope(_) => Some(blk.span),
CodeExtent::Remainder(r) => {
assert_eq!(r.block, blk.id);
@ -455,7 +531,7 @@ impl RegionMaps {
}
(ty::ReScope(sub_scope), ty::ReFree(ref fr)) => {
self.is_subscope_of(sub_scope, fr.scope)
self.is_subscope_of(sub_scope, fr.scope.to_code_extent())
}
(ty::ReFree(sub_fr), ty::ReFree(super_fr)) => {
@ -567,7 +643,18 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) {
let prev_cx = visitor.cx;
let blk_scope = CodeExtent::Misc(blk.id);
record_superlifetime(visitor, blk_scope, blk.span);
// If block was previously marked as a terminating scope during
// the recursive visit of its parent node in the AST, then we need
// to account for the destruction scope representing the extent of
// the destructors that run immediately after the the block itself
// completes.
if visitor.region_maps.terminating_scopes.borrow().contains(&blk_scope) {
let dtor_scope = CodeExtent::DestructionScope(blk.id);
record_superlifetime(visitor, dtor_scope, blk.span);
visitor.region_maps.record_encl_scope(blk_scope, dtor_scope);
} else {
record_superlifetime(visitor, blk_scope, blk.span);
}
// We treat the tail expression in the block (if any) somewhat
// differently from the statements. The issue has to do with
@ -675,7 +762,9 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) {
// statement plus its destructors, and thus the extent for which
// regions referenced by the destructors need to survive.
visitor.region_maps.mark_as_terminating_scope(stmt_scope);
record_superlifetime(visitor, stmt_scope, stmt.span);
let dtor_scope = CodeExtent::DestructionScope(stmt_id);
visitor.region_maps.record_encl_scope(stmt_scope, dtor_scope);
record_superlifetime(visitor, dtor_scope, stmt.span);
let prev_parent = visitor.cx.parent;
visitor.cx.parent = InnermostEnclosingExpr::Some(stmt_id);
@ -687,15 +776,30 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) {
debug!("resolve_expr(expr.id={:?})", expr.id);
let expr_scope = CodeExtent::Misc(expr.id);
record_superlifetime(visitor, expr_scope, expr.span);
// If expr was previously marked as a terminating scope during the
// recursive visit of its parent node in the AST, then we need to
// account for the destruction scope representing the extent of
// the destructors that run immediately after the the expression
// itself completes.
if visitor.region_maps.terminating_scopes.borrow().contains(&expr_scope) {
let dtor_scope = CodeExtent::DestructionScope(expr.id);
record_superlifetime(visitor, dtor_scope, expr.span);
visitor.region_maps.record_encl_scope(expr_scope, dtor_scope);
} else {
record_superlifetime(visitor, expr_scope, expr.span);
}
let prev_cx = visitor.cx;
visitor.cx.parent = InnermostEnclosingExpr::Some(expr.id);
{
let region_maps = &mut visitor.region_maps;
let terminating = |id| {
let scope = CodeExtent::from_node_id(id);
let terminating = |e: &P<ast::Expr>| {
let scope = CodeExtent::from_node_id(e.id);
region_maps.mark_as_terminating_scope(scope)
};
let terminating_block = |b: &P<ast::Block>| {
let scope = CodeExtent::from_node_id(b.id);
region_maps.mark_as_terminating_scope(scope)
};
match expr.node {
@ -707,26 +811,26 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) {
ast::ExprBinary(codemap::Spanned { node: ast::BiOr, .. }, _, ref r) => {
// For shortcircuiting operators, mark the RHS as a terminating
// scope since it only executes conditionally.
terminating(r.id);
terminating(r);
}
ast::ExprIf(_, ref then, Some(ref otherwise)) => {
terminating(then.id);
terminating(otherwise.id);
terminating_block(then);
terminating(otherwise);
}
ast::ExprIf(ref expr, ref then, None) => {
terminating(expr.id);
terminating(then.id);
terminating(expr);
terminating_block(then);
}
ast::ExprLoop(ref body, _) => {
terminating(body.id);
terminating_block(body);
}
ast::ExprWhile(ref expr, ref body, _) => {
terminating(expr.id);
terminating(body.id);
terminating(expr);
terminating_block(body);
}
ast::ExprMatch(..) => {
@ -1021,6 +1125,9 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
let body_scope = CodeExtent::from_node_id(body.id);
visitor.region_maps.mark_as_terminating_scope(body_scope);
let dtor_scope = CodeExtent::DestructionScope(body.id);
visitor.region_maps.record_encl_scope(body_scope, dtor_scope);
record_superlifetime(visitor, dtor_scope, body.span);
let outer_cx = visitor.cx;

View File

@ -41,7 +41,7 @@ pub enum DefRegion {
/* lifetime decl */ ast::NodeId),
DefLateBoundRegion(ty::DebruijnIndex,
/* lifetime decl */ ast::NodeId),
DefFreeRegion(/* block scope */ region::CodeExtent,
DefFreeRegion(/* block scope */ region::DestructionScopeData,
/* lifetime decl */ ast::NodeId),
}
@ -81,7 +81,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(region::CodeExtent, Scope<'a>),
BlockScope(region::DestructionScopeData, Scope<'a>),
RootScope
}
@ -191,7 +191,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
}
fn visit_block(&mut self, b: &ast::Block) {
self.with(BlockScope(region::CodeExtent::from_node_id(b.id), self.scope),
self.with(BlockScope(region::DestructionScopeData::new(b.id),
self.scope),
|_, this| visit::walk_block(this, b));
}
@ -393,9 +394,13 @@ impl<'a> LifetimeContext<'a> {
}
fn resolve_free_lifetime_ref(&mut self,
scope_data: region::CodeExtent,
scope_data: region::DestructionScopeData,
lifetime_ref: &ast::Lifetime,
scope: Scope) {
debug!("resolve_free_lifetime_ref \
scope_data: {:?} lifetime_ref: {:?} scope: {:?}",
scope_data, lifetime_ref, 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.
@ -403,6 +408,9 @@ impl<'a> LifetimeContext<'a> {
let mut scope = scope;
let mut search_result = None;
loop {
debug!("resolve_free_lifetime_ref \
scope_data: {:?} scope: {:?} search_result: {:?}",
scope_data, scope, search_result);
match *scope {
BlockScope(blk_scope_data, s) => {
scope_data = blk_scope_data;

View File

@ -1174,7 +1174,9 @@ pub enum Region {
/// region parameters.
ReFree(FreeRegion),
/// A concrete region naming some expression within the current function.
/// A concrete region naming some statically determined extent
/// (e.g. an expression or sequence of statements) within the
/// current function.
ReScope(region::CodeExtent),
/// Static data that has an "infinite" lifetime. Top in the region lattice.
@ -1296,7 +1298,7 @@ impl Region {
/// A "free" region `fr` can be interpreted as "some region
/// at least as big as the scope `fr.scope`".
pub struct FreeRegion {
pub scope: region::CodeExtent,
pub scope: region::DestructionScopeData,
pub bound_region: BoundRegion
}
@ -4192,12 +4194,16 @@ pub fn ty_region(tcx: &ctxt,
}
}
pub fn free_region_from_def(free_id: ast::NodeId, def: &RegionParameterDef)
pub fn free_region_from_def(outlives_extent: region::DestructionScopeData,
def: &RegionParameterDef)
-> ty::Region
{
ty::ReFree(ty::FreeRegion { scope: region::CodeExtent::from_node_id(free_id),
bound_region: ty::BrNamed(def.def_id,
def.name) })
let ret =
ty::ReFree(ty::FreeRegion { scope: outlives_extent,
bound_region: ty::BrNamed(def.def_id,
def.name) });
debug!("free_region_from_def returns {:?}", ret);
ret
}
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
@ -6252,9 +6258,11 @@ pub fn construct_free_substs<'a,'tcx>(
let mut types = VecPerParamSpace::empty();
push_types_from_defs(tcx, &mut types, generics.types.as_slice());
let free_id_outlive = region::DestructionScopeData::new(free_id);
// map bound 'a => free 'a
let mut regions = VecPerParamSpace::empty();
push_region_params(&mut regions, free_id, generics.regions.as_slice());
push_region_params(&mut regions, free_id_outlive, generics.regions.as_slice());
return Substs {
types: types,
@ -6262,11 +6270,11 @@ pub fn construct_free_substs<'a,'tcx>(
};
fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
free_id: ast::NodeId,
all_outlive_extent: region::DestructionScopeData,
region_params: &[RegionParameterDef])
{
for r in region_params {
regions.push(r.space, ty::free_region_from_def(free_id, r));
regions.push(r.space, ty::free_region_from_def(all_outlive_extent, r));
}
}
@ -6295,14 +6303,14 @@ pub fn construct_parameter_environment<'a,'tcx>(
//
let free_substs = construct_free_substs(tcx, generics, free_id);
let free_id_scope = region::CodeExtent::from_node_id(free_id);
let free_id_outlive = region::DestructionScopeData::new(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_scope, &ty::Binder(bounds));
let bounds = liberate_late_bound_regions(tcx, free_id_outlive, &ty::Binder(bounds));
let predicates = bounds.predicates.into_vec();
//
@ -6335,7 +6343,7 @@ pub fn construct_parameter_environment<'a,'tcx>(
let unnormalized_env = ty::ParameterEnvironment {
tcx: tcx,
free_substs: free_substs,
implicit_region_bound: ty::ReScope(free_id_scope),
implicit_region_bound: ty::ReScope(free_id_outlive.to_code_extent()),
caller_bounds: predicates,
selection_cache: traits::SelectionCache::new(),
};
@ -6603,14 +6611,14 @@ impl<'tcx> AutoDerefRef<'tcx> {
/// `scope_id`.
pub fn liberate_late_bound_regions<'tcx, T>(
tcx: &ty::ctxt<'tcx>,
scope: region::CodeExtent,
all_outlive_scope: region::DestructionScopeData,
value: &Binder<T>)
-> T
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
replace_late_bound_regions(
tcx, value,
|br| ty::ReFree(ty::FreeRegion{scope: scope, bound_region: br})).0
|br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0
}
pub fn count_late_bound_regions<'tcx, T>(

View File

@ -113,6 +113,10 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
};
let scope_decorated_tag = match scope {
region::CodeExtent::Misc(_) => tag,
region::CodeExtent::DestructionScope(_) => {
new_string = format!("destruction scope surrounding {}", tag);
new_string.as_slice()
}
region::CodeExtent::Remainder(r) => {
new_string = format!("block suffix following statement {}",
r.first_statement_index);
@ -135,7 +139,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
}
};
match cx.map.find(fr.scope.node_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)
@ -921,7 +925,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.node_id(),
self.scope.repr(tcx),
self.bound_region.repr(tcx))
}
}
@ -931,12 +935,23 @@ impl<'tcx> Repr<'tcx> for region::CodeExtent {
match *self {
region::CodeExtent::Misc(node_id) =>
format!("Misc({})", node_id),
region::CodeExtent::DestructionScope(node_id) =>
format!("DestructionScope({})", node_id),
region::CodeExtent::Remainder(rem) =>
format!("Remainder({}, {})", rem.block, rem.first_statement_index),
}
}
}
impl<'tcx> Repr<'tcx> for region::DestructionScopeData {
fn repr(&self, _tcx: &ctxt) -> String {
match *self {
region::DestructionScopeData{ node_id } =>
format!("DestructionScopeData {{ node_id: {} }}", node_id),
}
}
}
impl<'tcx> Repr<'tcx> for ast::DefId {
fn repr(&self, tcx: &ctxt) -> String {
// Unfortunately, there seems to be no way to attempt to print

View File

@ -286,7 +286,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
let loan_scope = match loan_region {
ty::ReScope(scope) => scope,
ty::ReFree(ref fr) => fr.scope,
ty::ReFree(ref fr) => fr.scope.to_code_extent(),
ty::ReStatic => {
// If we get here, an error must have been

View File

@ -15,7 +15,7 @@ use diagnostic::Emitter;
use driver;
use rustc_resolve as resolve;
use rustc_typeck::middle::lang_items;
use rustc_typeck::middle::region::{self, CodeExtent};
use rustc_typeck::middle::region::{self, CodeExtent, DestructionScopeData};
use rustc_typeck::middle::resolve_lifetime;
use rustc_typeck::middle::stability;
use rustc_typeck::middle::subst;
@ -325,7 +325,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
}
pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region {
ty::ReFree(ty::FreeRegion { scope: CodeExtent::from_node_id(nid),
ty::ReFree(ty::FreeRegion { scope: DestructionScopeData::new(nid),
bound_region: ty::BrAnon(id)})
}

View File

@ -130,12 +130,17 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
// this new AST scope had better be its immediate child.
let top_scope = self.top_ast_scope();
if top_scope.is_some() {
assert_eq!(self.ccx
.tcx()
.region_maps
.opt_encl_scope(region::CodeExtent::from_node_id(debug_loc.id))
.map(|s|s.node_id()),
top_scope);
assert!((self.ccx
.tcx()
.region_maps
.opt_encl_scope(region::CodeExtent::from_node_id(debug_loc.id))
.map(|s|s.node_id()) == top_scope)
||
(self.ccx
.tcx()
.region_maps
.opt_encl_scope(region::CodeExtent::DestructionScope(debug_loc.id))
.map(|s|s.node_id()) == top_scope));
}
self.push_scope(CleanupScope::new(AstScopeKind(debug_loc.id),

View File

@ -13,7 +13,7 @@
use super::{check_fn, Expectation, FnCtxt};
use astconv;
use middle::region::CodeExtent;
use middle::region;
use middle::subst;
use middle::ty::{self, ToPolyTraitRef, Ty};
use rscope::RegionScope;
@ -78,7 +78,9 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
fcx.write_ty(expr.id, closure_type);
let fn_sig =
ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
ty::liberate_late_bound_regions(fcx.tcx(),
region::DestructionScopeData::new(body.id),
&fn_ty.sig);
check_fn(fcx.ccx,
ast::Unsafety::Normal,

View File

@ -90,7 +90,7 @@ use middle::infer;
use middle::mem_categorization as mc;
use middle::mem_categorization::McResult;
use middle::pat_util::{self, pat_id_map};
use middle::region::CodeExtent;
use middle::region::{self, CodeExtent};
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
use middle::traits;
use middle::ty::{FnSig, VariantInfo, TypeScheme};
@ -495,7 +495,9 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let fn_sig =
fn_ty.sig.subst(ccx.tcx, &inh.param_env.free_substs);
let fn_sig =
liberate_late_bound_regions(ccx.tcx, CodeExtent::from_node_id(body.id), &fn_sig);
liberate_late_bound_regions(ccx.tcx,
region::DestructionScopeData::new(body.id),
&fn_sig);
let fn_sig =
inh.normalize_associated_types_in(&inh.param_env, body.span, body.id, &fn_sig);
@ -1686,7 +1688,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut bounds_checker = wf::BoundsChecker::new(self,
ast_t.span,
CodeExtent::from_node_id(self.body_id),
self.body_id,
None);
bounds_checker.check_ty(t);

View File

@ -145,7 +145,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
let variants = lookup_fields(fcx);
let mut bounds_checker = BoundsChecker::new(fcx,
item.span,
region::CodeExtent::from_node_id(item.id),
item.id,
Some(&mut this.cache));
for variant in &variants {
for field in &variant.fields {
@ -180,7 +180,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
self.with_fcx(item, |this, fcx| {
let mut bounds_checker = BoundsChecker::new(fcx,
item.span,
region::CodeExtent::from_node_id(item.id),
item.id,
Some(&mut this.cache));
let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id));
@ -196,11 +196,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
item: &ast::Item)
{
self.with_fcx(item, |this, fcx| {
let item_scope = region::CodeExtent::from_node_id(item.id);
let mut bounds_checker = BoundsChecker::new(fcx,
item.span,
item_scope,
item.id,
Some(&mut this.cache));
// Find the impl self type as seen from the "inside" --
@ -383,7 +381,12 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
pub struct BoundsChecker<'cx,'tcx:'cx> {
fcx: &'cx FnCtxt<'cx,'tcx>,
span: Span,
scope: region::CodeExtent,
// This field is often attached to item impls; it is not clear
// that `CodeExtent` is well-defined for such nodes, so pnkfelix
// has left it as a NodeId rather than porting to CodeExtent.
scope: ast::NodeId,
binding_count: uint,
cache: Option<&'cx mut HashSet<Ty<'tcx>>>,
}
@ -391,7 +394,7 @@ pub struct BoundsChecker<'cx,'tcx:'cx> {
impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>,
span: Span,
scope: region::CodeExtent,
scope: ast::NodeId,
cache: Option<&'cx mut HashSet<Ty<'tcx>>>)
-> BoundsChecker<'cx,'tcx> {
BoundsChecker { fcx: fcx, span: span, scope: scope,
@ -446,9 +449,12 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
self.binding_count += 1;
let value = liberate_late_bound_regions(self.fcx.tcx(), self.scope, binder);
debug!("BoundsChecker::fold_binder: late-bound regions replaced: {}",
value.repr(self.tcx()));
let value = liberate_late_bound_regions(
self.fcx.tcx(),
region::DestructionScopeData::new(self.scope),
binder);
debug!("BoundsChecker::fold_binder: late-bound regions replaced: {} at scope: {:?}",
value.repr(self.tcx()), self.scope);
let value = value.fold_with(self);
self.binding_count -= 1;
ty::Binder(value)

View File

@ -1564,7 +1564,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
_ => typ,
};
let body_scope = region::CodeExtent::from_node_id(body_id);
let body_scope = region::DestructionScopeData::new(body_id);
// "Required type" comes from the trait definition. It may
// contain late-bound regions from the method, but not the
@ -1608,7 +1608,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
fn liberate_early_bound_regions<'tcx,T>(
tcx: &ty::ctxt<'tcx>,
scope: region::CodeExtent,
scope: region::DestructionScopeData,
value: &T)
-> T
where T : TypeFoldable<'tcx> + Repr<'tcx>