2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2012-07-24 10:12:15 -05:00
|
|
|
/*!
|
2012-04-01 16:28:30 -05:00
|
|
|
|
2012-07-24 10:12:15 -05:00
|
|
|
This file actually contains two passes related to regions. The first
|
2013-04-02 00:32:37 -05:00
|
|
|
pass builds up the `scope_map`, which describes the parent links in
|
2012-07-24 10:12:15 -05:00
|
|
|
the region hierarchy. The second pass infers which types must be
|
|
|
|
region parameterized.
|
2012-04-01 16:28:30 -05:00
|
|
|
|
2013-06-06 10:57:37 -05:00
|
|
|
Most of the documentation on regions can be found in
|
|
|
|
`middle/typeck/infer/region_inference.rs`
|
|
|
|
|
2012-04-01 16:28:30 -05:00
|
|
|
*/
|
2012-03-09 18:39:54 -06:00
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2012-10-15 16:56:42 -05:00
|
|
|
use driver::session::Session;
|
2013-10-29 05:08:34 -05:00
|
|
|
use middle::ty::{FreeRegion};
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::ty;
|
2014-02-28 16:34:26 -06:00
|
|
|
use util::nodemap::NodeMap;
|
2012-09-04 13:54:36 -05:00
|
|
|
|
2013-12-21 19:56:52 -06:00
|
|
|
use std::cell::RefCell;
|
2014-02-19 21:29:58 -06:00
|
|
|
use collections::{HashMap, HashSet};
|
2013-08-31 11:13:04 -05:00
|
|
|
use syntax::codemap::Span;
|
2013-08-13 07:36:10 -05:00
|
|
|
use syntax::{ast, visit};
|
2014-01-09 07:05:33 -06:00
|
|
|
use syntax::visit::{Visitor, FnKind};
|
|
|
|
use syntax::ast::{Block, Item, FnDecl, NodeId, Arm, Pat, Stmt, Expr, Local};
|
2014-01-15 13:39:08 -06:00
|
|
|
use syntax::ast_util::{stmt_id};
|
2012-03-09 18:39:54 -06:00
|
|
|
|
2012-08-17 16:09:20 -05:00
|
|
|
/**
|
2013-04-02 00:32:37 -05:00
|
|
|
The region maps encode information about region relationships.
|
|
|
|
|
2014-02-07 09:09:46 -06:00
|
|
|
- `scope_map` maps from a scope id to the enclosing scope id; this is
|
|
|
|
usually corresponding to the lexical nesting, though in the case of
|
|
|
|
closures the parent scope is the innermost conditinal expression or repeating
|
|
|
|
block
|
|
|
|
|
|
|
|
- `var_map` maps from a variable or binding id to the block in which
|
|
|
|
that variable is declared.
|
|
|
|
|
|
|
|
- `free_region_map` maps from a free region `a` to a list of free
|
|
|
|
regions `bs` such that `a <= b for all b in bs`
|
2013-04-02 00:32:37 -05:00
|
|
|
- the free region map is populated during type check as we check
|
|
|
|
each function. See the function `relate_free_regions` for
|
|
|
|
more information.
|
2014-02-07 09:09:46 -06:00
|
|
|
|
|
|
|
- `rvalue_scopes` includes entries for those expressions whose cleanup
|
|
|
|
scope is larger than the default. The map goes from the expression
|
|
|
|
id to the cleanup scope id. For rvalues not present in this table,
|
|
|
|
the appropriate cleanup scope is the innermost enclosing statement,
|
|
|
|
conditional expression, or repeating block (see `terminating_scopes`).
|
|
|
|
|
|
|
|
- `terminating_scopes` is a set containing the ids of each statement,
|
|
|
|
or conditional/repeating expression. These scopes are calling "terminating
|
|
|
|
scopes" because, when attempting to find the scope of a temporary, by
|
|
|
|
default we search up the enclosing scopes until we encounter the
|
|
|
|
terminating scope. A conditional/repeating
|
|
|
|
expression is one which is not guaranteed to execute exactly once
|
|
|
|
upon entering the parent scope. This could be because the expression
|
|
|
|
only executes conditionally, such as the expression `b` in `a && b`,
|
|
|
|
or because the expression may execute many times, such as a loop
|
|
|
|
body. The reason that we distinguish such expressions is that, upon
|
|
|
|
exiting the parent scope, we cannot statically know how many times
|
|
|
|
the expression executed, and thus if the expression creates
|
|
|
|
temporaries we cannot know statically how many such temporaries we
|
|
|
|
would have to cleanup. Therefore we ensure that the temporaries never
|
|
|
|
outlast the conditional/repeating expression, preventing the need
|
|
|
|
for dynamic checks and/or arbitrary amounts of stack space.
|
2012-08-17 16:09:20 -05:00
|
|
|
*/
|
2013-04-02 00:32:37 -05:00
|
|
|
pub struct RegionMaps {
|
2014-02-28 16:34:26 -06:00
|
|
|
priv scope_map: RefCell<NodeMap<ast::NodeId>>,
|
|
|
|
priv var_map: RefCell<NodeMap<ast::NodeId>>,
|
2014-03-04 12:02:49 -06:00
|
|
|
priv free_region_map: RefCell<HashMap<FreeRegion, Vec<FreeRegion> >>,
|
2014-02-28 16:34:26 -06:00
|
|
|
priv rvalue_scopes: RefCell<NodeMap<ast::NodeId>>,
|
2014-01-15 13:39:08 -06:00
|
|
|
priv terminating_scopes: RefCell<HashSet<ast::NodeId>>,
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
2012-03-12 14:43:02 -05:00
|
|
|
|
2013-07-02 14:47:32 -05:00
|
|
|
#[deriving(Clone)]
|
2013-03-15 14:24:24 -05:00
|
|
|
pub struct Context {
|
2013-07-27 03:25:59 -05:00
|
|
|
var_parent: Option<ast::NodeId>,
|
2013-03-15 14:24:24 -05:00
|
|
|
|
|
|
|
// Innermost enclosing expression
|
2013-07-27 03:25:59 -05:00
|
|
|
parent: Option<ast::NodeId>,
|
2012-08-17 16:09:20 -05:00
|
|
|
}
|
2012-03-12 14:43:02 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
struct RegionResolutionVisitor<'a> {
|
2013-09-25 03:59:56 -05:00
|
|
|
sess: Session,
|
|
|
|
|
|
|
|
// Generated maps:
|
2014-01-15 13:39:08 -06:00
|
|
|
region_maps: &'a RegionMaps,
|
2013-09-25 03:59:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl RegionMaps {
|
2013-12-21 20:03:06 -06:00
|
|
|
pub fn relate_free_regions(&self, sub: FreeRegion, sup: FreeRegion) {
|
2013-12-21 19:58:40 -06:00
|
|
|
let mut free_region_map = self.free_region_map.borrow_mut();
|
|
|
|
match free_region_map.get().find_mut(&sub) {
|
2013-04-02 00:32:37 -05:00
|
|
|
Some(sups) => {
|
2013-07-04 21:13:26 -05:00
|
|
|
if !sups.iter().any(|x| x == &sup) {
|
2013-04-02 00:32:37 -05:00
|
|
|
sups.push(sup);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
None => {}
|
2012-03-11 15:28:43 -05:00
|
|
|
}
|
2013-04-02 00:32:37 -05:00
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("relate_free_regions(sub={:?}, sup={:?})", sub, sup);
|
2013-04-02 00:32:37 -05:00
|
|
|
|
2014-03-04 12:02:49 -06:00
|
|
|
free_region_map.get().insert(sub, vec!(sup));
|
2012-03-11 15:28:43 -05:00
|
|
|
}
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
pub fn record_encl_scope(&self, sub: ast::NodeId, sup: ast::NodeId) {
|
|
|
|
debug!("record_encl_scope(sub={}, sup={})", sub, sup);
|
2013-03-15 14:24:24 -05:00
|
|
|
assert!(sub != sup);
|
2012-10-19 08:01:01 -05:00
|
|
|
|
2013-12-21 19:56:52 -06:00
|
|
|
let mut scope_map = self.scope_map.borrow_mut();
|
|
|
|
scope_map.get().insert(sub, sup);
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
pub fn record_var_scope(&self, var: ast::NodeId, lifetime: ast::NodeId) {
|
|
|
|
debug!("record_var_scope(sub={}, sup={})", var, lifetime);
|
|
|
|
assert!(var != lifetime);
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut var_map = self.var_map.borrow_mut();
|
|
|
|
var_map.get().insert(var, lifetime);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: ast::NodeId) {
|
|
|
|
debug!("record_rvalue_scope(sub={}, sup={})", var, lifetime);
|
|
|
|
assert!(var != lifetime);
|
|
|
|
|
|
|
|
let mut rvalue_scopes = self.rvalue_scopes.borrow_mut();
|
|
|
|
rvalue_scopes.get().insert(var, lifetime);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn mark_as_terminating_scope(&self, scope_id: ast::NodeId) {
|
|
|
|
/*!
|
|
|
|
* Records that a scope is a TERMINATING SCOPE. Whenever we
|
|
|
|
* create automatic temporaries -- e.g. by an
|
|
|
|
* expression like `a().f` -- they will be freed within
|
|
|
|
* the innermost terminating scope.
|
|
|
|
*/
|
|
|
|
|
|
|
|
debug!("record_terminating_scope(scope_id={})", scope_id);
|
|
|
|
let mut terminating_scopes = self.terminating_scopes.borrow_mut();
|
|
|
|
terminating_scopes.get().insert(scope_id);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn opt_encl_scope(&self, id: ast::NodeId) -> Option<ast::NodeId> {
|
2013-04-02 00:32:37 -05:00
|
|
|
//! Returns the narrowest scope that encloses `id`, if any.
|
|
|
|
|
2013-12-21 19:56:52 -06:00
|
|
|
let scope_map = self.scope_map.borrow();
|
|
|
|
scope_map.get().find(&id).map(|x| *x)
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn encl_scope(&self, id: ast::NodeId) -> ast::NodeId {
|
2013-04-02 00:32:37 -05:00
|
|
|
//! Returns the narrowest scope that encloses `id`, if any.
|
|
|
|
|
2013-12-21 19:56:52 -06:00
|
|
|
let scope_map = self.scope_map.borrow();
|
|
|
|
match scope_map.get().find(&id) {
|
2013-04-02 00:32:37 -05:00
|
|
|
Some(&r) => r,
|
2014-02-06 03:38:08 -06:00
|
|
|
None => { fail!("no enclosing scope for id {}", id); }
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
pub fn var_scope(&self, var_id: ast::NodeId) -> ast::NodeId {
|
|
|
|
/*!
|
|
|
|
* Returns the lifetime of the local variable `var_id`
|
|
|
|
*/
|
|
|
|
|
|
|
|
let var_map = self.var_map.borrow();
|
|
|
|
match var_map.get().find(&var_id) {
|
|
|
|
Some(&r) => r,
|
2014-02-06 03:38:08 -06:00
|
|
|
None => { fail!("no enclosing scope for id {}", var_id); }
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option<ast::NodeId> {
|
|
|
|
//! Returns the scope when temp created by expr_id will be cleaned up
|
|
|
|
|
|
|
|
// check for a designated rvalue scope
|
|
|
|
let rvalue_scopes = self.rvalue_scopes.borrow();
|
|
|
|
match rvalue_scopes.get().find(&expr_id) {
|
|
|
|
Some(&s) => {
|
|
|
|
debug!("temporary_scope({}) = {} [custom]", expr_id, s);
|
|
|
|
return Some(s);
|
|
|
|
}
|
|
|
|
None => { }
|
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
// else, locate the innermost terminating scope
|
2014-01-27 16:09:57 -06:00
|
|
|
// if there's one. Static items, for instance, won't
|
|
|
|
// have an enclusing scope, hence no scope will be
|
|
|
|
// returned.
|
|
|
|
let mut id = match self.opt_encl_scope(expr_id) {
|
|
|
|
Some(i) => i,
|
|
|
|
None => { return None; }
|
|
|
|
};
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let terminating_scopes = self.terminating_scopes.borrow();
|
|
|
|
while !terminating_scopes.get().contains(&id) {
|
|
|
|
match self.opt_encl_scope(id) {
|
|
|
|
Some(p) => {
|
|
|
|
id = p;
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
debug!("temporary_scope({}) = None", expr_id);
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
debug!("temporary_scope({}) = {} [enclosing]", expr_id, id);
|
|
|
|
return Some(id);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn encl_region(&self, id: ast::NodeId) -> ty::Region {
|
2013-04-02 00:32:37 -05:00
|
|
|
//! Returns the narrowest scope region that encloses `id`, if any.
|
2012-10-19 08:01:01 -05:00
|
|
|
|
2013-10-29 09:34:11 -05:00
|
|
|
ty::ReScope(self.encl_scope(id))
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
pub fn var_region(&self, id: ast::NodeId) -> ty::Region {
|
|
|
|
//! Returns the lifetime of the variable `id`.
|
|
|
|
|
|
|
|
ty::ReScope(self.var_scope(id))
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn scopes_intersect(&self, scope1: ast::NodeId, scope2: ast::NodeId)
|
2013-05-31 17:17:22 -05:00
|
|
|
-> bool {
|
|
|
|
self.is_subscope_of(scope1, scope2) ||
|
|
|
|
self.is_subscope_of(scope2, scope1)
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn is_subscope_of(&self,
|
2013-07-27 03:25:59 -05:00
|
|
|
subscope: ast::NodeId,
|
|
|
|
superscope: ast::NodeId)
|
2013-05-31 17:17:22 -05:00
|
|
|
-> bool {
|
2013-04-02 00:32:37 -05:00
|
|
|
/*!
|
2013-03-15 14:24:24 -05:00
|
|
|
* Returns true if `subscope` is equal to or is lexically
|
2013-04-02 00:32:37 -05:00
|
|
|
* nested inside `superscope` and false otherwise.
|
|
|
|
*/
|
|
|
|
|
2013-03-15 14:24:24 -05:00
|
|
|
let mut s = subscope;
|
|
|
|
while superscope != s {
|
2013-12-21 19:56:52 -06:00
|
|
|
let scope_map = self.scope_map.borrow();
|
|
|
|
match scope_map.get().find(&s) {
|
2013-03-15 14:24:24 -05:00
|
|
|
None => {
|
2014-01-15 13:39:08 -06:00
|
|
|
debug!("is_subscope_of({}, {}, s={})=false",
|
2013-03-15 14:24:24 -05:00
|
|
|
subscope, superscope, s);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Some(&scope) => s = scope
|
2012-10-19 08:01:01 -05:00
|
|
|
}
|
2012-07-26 10:51:57 -05:00
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
debug!("is_subscope_of({}, {})=true",
|
2013-03-15 14:24:24 -05:00
|
|
|
subscope, superscope);
|
|
|
|
|
2013-04-02 00:32:37 -05:00
|
|
|
return true;
|
|
|
|
}
|
2012-07-26 10:51:57 -05:00
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
|
2013-04-02 00:32:37 -05:00
|
|
|
/*!
|
|
|
|
* Determines whether two free regions have a subregion relationship
|
|
|
|
* by walking the graph encoded in `free_region_map`. Note that
|
|
|
|
* it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
|
|
|
|
* (that is, the user can give two different names to the same lifetime).
|
|
|
|
*/
|
|
|
|
|
|
|
|
if sub == sup {
|
|
|
|
return true;
|
|
|
|
}
|
2012-03-26 17:07:15 -05:00
|
|
|
|
2013-04-02 00:32:37 -05:00
|
|
|
// Do a little breadth-first-search here. The `queue` list
|
|
|
|
// doubles as a way to detect if we've seen a particular FR
|
|
|
|
// before. Note that we expect this graph to be an *extremely
|
|
|
|
// shallow* tree.
|
2014-03-04 12:02:49 -06:00
|
|
|
let mut queue = vec!(sub);
|
2013-04-02 00:32:37 -05:00
|
|
|
let mut i = 0;
|
|
|
|
while i < queue.len() {
|
2013-12-21 19:58:40 -06:00
|
|
|
let free_region_map = self.free_region_map.borrow();
|
|
|
|
match free_region_map.get().find(&queue[i]) {
|
2013-04-02 00:32:37 -05:00
|
|
|
Some(parents) => {
|
2013-08-03 11:45:23 -05:00
|
|
|
for parent in parents.iter() {
|
2013-04-02 00:32:37 -05:00
|
|
|
if *parent == sup {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-04 21:13:26 -05:00
|
|
|
if !queue.iter().any(|x| x == parent) {
|
2013-04-02 00:32:37 -05:00
|
|
|
queue.push(*parent);
|
|
|
|
}
|
|
|
|
}
|
2012-03-26 17:07:15 -05:00
|
|
|
}
|
2013-04-02 00:32:37 -05:00
|
|
|
None => {}
|
2012-03-26 17:07:15 -05:00
|
|
|
}
|
2013-04-02 00:32:37 -05:00
|
|
|
i += 1;
|
2012-03-26 17:07:15 -05:00
|
|
|
}
|
2013-04-02 00:32:37 -05:00
|
|
|
return false;
|
2012-03-26 17:07:15 -05:00
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn is_subregion_of(&self,
|
|
|
|
sub_region: ty::Region,
|
|
|
|
super_region: ty::Region)
|
|
|
|
-> bool {
|
2013-04-02 00:32:37 -05:00
|
|
|
/*!
|
|
|
|
* Determines whether one region is a subregion of another. This is
|
|
|
|
* intended to run *after inference* and sadly the logic is somewhat
|
|
|
|
* duplicated with the code in infer.rs.
|
|
|
|
*/
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
|
2013-04-02 00:32:37 -05:00
|
|
|
sub_region, super_region);
|
|
|
|
|
|
|
|
sub_region == super_region || {
|
|
|
|
match (sub_region, super_region) {
|
2013-10-29 09:34:11 -05:00
|
|
|
(_, ty::ReStatic) => {
|
2013-04-02 00:32:37 -05:00
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2013-10-29 09:34:11 -05:00
|
|
|
(ty::ReScope(sub_scope), ty::ReScope(super_scope)) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.is_subscope_of(sub_scope, super_scope)
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
2012-03-26 17:07:15 -05:00
|
|
|
|
2013-10-29 09:34:11 -05:00
|
|
|
(ty::ReScope(sub_scope), ty::ReFree(ref fr)) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.is_subscope_of(sub_scope, fr.scope_id)
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
2012-04-01 16:28:30 -05:00
|
|
|
|
2013-10-29 09:34:11 -05:00
|
|
|
(ty::ReFree(sub_fr), ty::ReFree(super_fr)) => {
|
2013-04-02 00:32:37 -05:00
|
|
|
self.sub_free_region(sub_fr, super_fr)
|
|
|
|
}
|
2012-04-01 16:28:30 -05:00
|
|
|
|
2013-04-02 00:32:37 -05:00
|
|
|
_ => {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-04-26 18:02:01 -05:00
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn nearest_common_ancestor(&self,
|
2013-07-27 03:25:59 -05:00
|
|
|
scope_a: ast::NodeId,
|
|
|
|
scope_b: ast::NodeId)
|
|
|
|
-> Option<ast::NodeId> {
|
2013-04-02 00:32:37 -05:00
|
|
|
/*!
|
|
|
|
* Finds the nearest common ancestor (if any) of two scopes. That
|
|
|
|
* is, finds the smallest scope which is greater than or equal to
|
|
|
|
* both `scope_a` and `scope_b`.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if scope_a == scope_b { return Some(scope_a); }
|
|
|
|
|
|
|
|
let a_ancestors = ancestors_of(self, scope_a);
|
|
|
|
let b_ancestors = ancestors_of(self, scope_b);
|
2013-05-14 04:52:12 -05:00
|
|
|
let mut a_index = a_ancestors.len() - 1u;
|
|
|
|
let mut b_index = b_ancestors.len() - 1u;
|
2013-04-02 00:32:37 -05:00
|
|
|
|
|
|
|
// Here, ~[ab]_ancestors is a vector going from narrow to broad.
|
|
|
|
// The end of each vector will be the item where the scope is
|
|
|
|
// defined; if there are any common ancestors, then the tails of
|
|
|
|
// the vector will be the same. So basically we want to walk
|
|
|
|
// backwards from the tail of each vector and find the first point
|
|
|
|
// where they diverge. If one vector is a suffix of the other,
|
|
|
|
// then the corresponding scope is a superscope of the other.
|
|
|
|
|
2012-04-26 18:02:01 -05:00
|
|
|
if a_ancestors[a_index] != b_ancestors[b_index] {
|
2013-04-02 00:32:37 -05:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
loop {
|
|
|
|
// Loop invariant: a_ancestors[a_index] == b_ancestors[b_index]
|
|
|
|
// for all indices between a_index and the end of the array
|
|
|
|
if a_index == 0u { return Some(scope_a); }
|
|
|
|
if b_index == 0u { return Some(scope_b); }
|
|
|
|
a_index -= 1u;
|
|
|
|
b_index -= 1u;
|
|
|
|
if a_ancestors[a_index] != b_ancestors[b_index] {
|
|
|
|
return Some(a_ancestors[a_index + 1u]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
fn ancestors_of(this: &RegionMaps, scope: ast::NodeId)
|
2014-03-04 12:02:49 -06:00
|
|
|
-> Vec<ast::NodeId> {
|
2013-10-21 15:08:31 -05:00
|
|
|
// debug!("ancestors_of(scope={})", scope);
|
2014-03-04 12:02:49 -06:00
|
|
|
let mut result = vec!(scope);
|
2013-04-02 00:32:37 -05:00
|
|
|
let mut scope = scope;
|
|
|
|
loop {
|
2013-12-21 19:56:52 -06:00
|
|
|
let scope_map = this.scope_map.borrow();
|
|
|
|
match scope_map.get().find(&scope) {
|
2013-04-02 00:32:37 -05:00
|
|
|
None => return result,
|
|
|
|
Some(&superscope) => {
|
|
|
|
result.push(superscope);
|
|
|
|
scope = superscope;
|
|
|
|
}
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
// debug!("ancestors_of_loop(scope={})", scope);
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
2012-04-26 18:02:01 -05:00
|
|
|
}
|
2012-03-26 17:07:15 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 10:12:15 -05:00
|
|
|
/// Records the current parent (if any) as the parent of `child_id`.
|
2014-01-15 13:39:08 -06:00
|
|
|
fn record_superlifetime(visitor: &mut RegionResolutionVisitor,
|
|
|
|
cx: Context,
|
|
|
|
child_id: ast::NodeId,
|
|
|
|
_sp: Span) {
|
|
|
|
for &parent_id in cx.parent.iter() {
|
|
|
|
visitor.region_maps.record_encl_scope(child_id, parent_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Records the lifetime of a local variable as `cx.var_parent`
|
|
|
|
fn record_var_lifetime(visitor: &mut RegionResolutionVisitor,
|
|
|
|
cx: Context,
|
|
|
|
var_id: ast::NodeId,
|
|
|
|
_sp: Span) {
|
|
|
|
match cx.var_parent {
|
|
|
|
Some(parent_id) => {
|
|
|
|
visitor.region_maps.record_var_scope(var_id, parent_id);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
// this can happen in extern fn declarations like
|
|
|
|
//
|
|
|
|
// extern fn isalnum(c: c_int) -> c_int
|
|
|
|
}
|
2012-03-09 18:39:54 -06:00
|
|
|
}
|
2012-03-12 14:43:02 -05:00
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
fn resolve_block(visitor: &mut RegionResolutionVisitor,
|
2014-01-06 06:00:46 -06:00
|
|
|
blk: &ast::Block,
|
2013-08-13 07:36:10 -05:00
|
|
|
cx: Context) {
|
2014-01-15 13:39:08 -06:00
|
|
|
debug!("resolve_block(blk.id={})", blk.id);
|
2012-03-09 18:39:54 -06:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
// Record the parent of this block.
|
|
|
|
record_superlifetime(visitor, cx, blk.id, blk.span);
|
|
|
|
|
|
|
|
// We treat the tail expression in the block (if any) somewhat
|
|
|
|
// differently from the statements. The issue has to do with
|
|
|
|
// temporary lifetimes. If the user writes:
|
|
|
|
//
|
|
|
|
// {
|
|
|
|
// ... (&foo()) ...
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
|
|
|
|
let subcx = Context {var_parent: Some(blk.id), parent: Some(blk.id)};
|
|
|
|
visit::walk_block(visitor, blk, subcx);
|
2012-03-09 18:39:54 -06:00
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
fn resolve_arm(visitor: &mut RegionResolutionVisitor,
|
2013-09-01 20:45:37 -05:00
|
|
|
arm: &ast::Arm,
|
2013-08-13 07:36:10 -05:00
|
|
|
cx: Context) {
|
2014-01-15 13:39:08 -06:00
|
|
|
visitor.region_maps.mark_as_terminating_scope(arm.body.id);
|
|
|
|
|
|
|
|
match arm.guard {
|
|
|
|
Some(expr) => {
|
|
|
|
visitor.region_maps.mark_as_terminating_scope(expr.id);
|
|
|
|
}
|
|
|
|
None => { }
|
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
visit::walk_arm(visitor, arm, cx);
|
2012-03-11 14:05:17 -05:00
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
fn resolve_pat(visitor: &mut RegionResolutionVisitor,
|
2013-11-25 12:22:21 -06:00
|
|
|
pat: &ast::Pat,
|
2013-08-13 07:36:10 -05:00
|
|
|
cx: Context) {
|
2014-01-15 13:39:08 -06:00
|
|
|
record_superlifetime(visitor, cx, pat.id, pat.span);
|
|
|
|
|
|
|
|
// If this is a binding (or maybe a binding, I'm too lazy to check
|
|
|
|
// the def map) then record the lifetime of that binding.
|
|
|
|
match pat.node {
|
|
|
|
ast::PatIdent(..) => {
|
|
|
|
record_var_lifetime(visitor, cx, pat.id, pat.span);
|
|
|
|
}
|
|
|
|
_ => { }
|
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
visit::walk_pat(visitor, pat, cx);
|
2012-03-11 14:05:17 -05:00
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
fn resolve_stmt(visitor: &mut RegionResolutionVisitor,
|
2014-01-06 06:00:46 -06:00
|
|
|
stmt: &ast::Stmt,
|
2013-08-13 07:36:10 -05:00
|
|
|
cx: Context) {
|
2014-01-15 13:39:08 -06:00
|
|
|
let stmt_id = stmt_id(stmt);
|
|
|
|
debug!("resolve_stmt(stmt.id={})", stmt_id);
|
|
|
|
|
|
|
|
visitor.region_maps.mark_as_terminating_scope(stmt_id);
|
|
|
|
record_superlifetime(visitor, cx, stmt_id, stmt.span);
|
|
|
|
|
|
|
|
let subcx = Context {parent: Some(stmt_id), ..cx};
|
|
|
|
visit::walk_stmt(visitor, stmt, subcx);
|
2012-08-17 16:09:20 -05:00
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
fn resolve_expr(visitor: &mut RegionResolutionVisitor,
|
2014-01-06 06:00:46 -06:00
|
|
|
expr: &ast::Expr,
|
2013-08-13 07:36:10 -05:00
|
|
|
cx: Context) {
|
2014-01-15 13:39:08 -06:00
|
|
|
debug!("resolve_expr(expr.id={})", expr.id);
|
|
|
|
|
|
|
|
record_superlifetime(visitor, cx, expr.id, expr.span);
|
2012-07-26 10:51:57 -05:00
|
|
|
|
|
|
|
let mut new_cx = cx;
|
2013-03-15 14:24:24 -05:00
|
|
|
new_cx.parent = Some(expr.id);
|
2012-08-06 14:34:08 -05:00
|
|
|
match expr.node {
|
2014-01-15 13:39:08 -06:00
|
|
|
// Conditional or repeating scopes are always terminating
|
|
|
|
// scopes, meaning that temporaries cannot outlive them.
|
|
|
|
// This ensures fixed size stacks.
|
|
|
|
|
2014-02-26 08:06:45 -06:00
|
|
|
ast::ExprBinary(ast::BiAnd, _, r) |
|
|
|
|
ast::ExprBinary(ast::BiOr, _, r) => {
|
2014-01-15 13:39:08 -06:00
|
|
|
// 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::ExprIf(_, then, Some(otherwise)) => {
|
|
|
|
visitor.region_maps.mark_as_terminating_scope(then.id);
|
|
|
|
visitor.region_maps.mark_as_terminating_scope(otherwise.id);
|
|
|
|
}
|
|
|
|
|
2014-02-09 06:44:10 -06:00
|
|
|
ast::ExprIf(expr, then, None) => {
|
|
|
|
visitor.region_maps.mark_as_terminating_scope(expr.id);
|
2014-01-15 13:39:08 -06:00
|
|
|
visitor.region_maps.mark_as_terminating_scope(then.id);
|
|
|
|
}
|
|
|
|
|
2014-02-09 06:44:10 -06:00
|
|
|
ast::ExprLoop(body, _) => {
|
|
|
|
visitor.region_maps.mark_as_terminating_scope(body.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprWhile(expr, body) => {
|
|
|
|
visitor.region_maps.mark_as_terminating_scope(expr.id);
|
2014-01-15 13:39:08 -06:00
|
|
|
visitor.region_maps.mark_as_terminating_scope(body.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprMatch(..) => {
|
|
|
|
new_cx.var_parent = Some(expr.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprAssignOp(..) | ast::ExprIndex(..) |
|
2013-11-28 14:22:53 -06:00
|
|
|
ast::ExprUnary(..) | ast::ExprCall(..) | ast::ExprMethodCall(..) => {
|
2013-05-06 13:02:28 -05:00
|
|
|
// FIXME(#6268) Nested method calls
|
2013-03-15 14:24:24 -05:00
|
|
|
//
|
|
|
|
// 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 explanantion of why this distinction is
|
|
|
|
// important.
|
|
|
|
//
|
2014-01-15 13:39:08 -06:00
|
|
|
// record_superlifetime(new_cx, expr.callee_id);
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
_ => {}
|
2012-07-26 10:51:57 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
visit::walk_expr(visitor, expr, new_cx);
|
2012-03-11 19:01:28 -05:00
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
fn resolve_local(visitor: &mut RegionResolutionVisitor,
|
2014-01-06 06:00:46 -06:00
|
|
|
local: &ast::Local,
|
2013-08-13 07:36:10 -05:00
|
|
|
cx: Context) {
|
2014-01-15 13:39:08 -06:00
|
|
|
debug!("resolve_local(local.id={},local.init={})",
|
|
|
|
local.id,local.init.is_some());
|
|
|
|
|
|
|
|
let blk_id = match cx.var_parent {
|
|
|
|
Some(id) => id,
|
|
|
|
None => {
|
|
|
|
visitor.sess.span_bug(
|
|
|
|
local.span,
|
2014-02-06 03:38:08 -06:00
|
|
|
"local without enclosing block");
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// As an exception to the normal rules governing temporary
|
|
|
|
// lifetimes, initializers in a let have a temporary lifetime
|
|
|
|
// of the enclosing block. This means that e.g. a program
|
|
|
|
// like the following is legal:
|
|
|
|
//
|
|
|
|
// let ref x = HashMap::new();
|
|
|
|
//
|
|
|
|
// Because the hash map will be freed in the enclosing block.
|
|
|
|
//
|
|
|
|
// We express the rules more formally based on 3 grammars (defined
|
|
|
|
// fully in the helpers below that implement them):
|
|
|
|
//
|
|
|
|
// 1. `E&`, which matches expressions like `&<rvalue>` that
|
|
|
|
// own a pointer into the stack.
|
|
|
|
//
|
|
|
|
// 2. `P&`, which matches patterns like `ref x` or `(ref x, ref
|
|
|
|
// y)` that produce ref bindings into the value they are
|
|
|
|
// matched against or something (at least partially) owned by
|
|
|
|
// the value they are matched against. (By partially owned,
|
|
|
|
// I mean that creating a binding into a ref-counted or managed value
|
|
|
|
// would still count.)
|
|
|
|
//
|
|
|
|
// 3. `ET`, which matches both rvalues like `foo()` as well as lvalues
|
|
|
|
// based on rvalues like `foo().x[2].y`.
|
|
|
|
//
|
|
|
|
// A subexpression `<rvalue>` that appears in a let initializer
|
|
|
|
// `let pat [: ty] = expr` has an extended temporary lifetime if
|
|
|
|
// any of the following conditions are met:
|
|
|
|
//
|
|
|
|
// A. `pat` matches `P&` and `expr` matches `ET`
|
|
|
|
// (covers cases where `pat` creates ref bindings into an rvalue
|
|
|
|
// produced by `expr`)
|
|
|
|
// B. `ty` is a borrowed pointer and `expr` matches `ET`
|
|
|
|
// (covers cases where coercion creates a borrow)
|
|
|
|
// C. `expr` matches `E&`
|
|
|
|
// (covers cases `expr` borrows an rvalue that is then assigned
|
|
|
|
// to memory (at least partially) owned by the binding)
|
|
|
|
//
|
|
|
|
// Here are some examples hopefully giving an intution where each
|
|
|
|
// rule comes into play and why:
|
|
|
|
//
|
|
|
|
// Rule A. `let (ref x, ref y) = (foo().x, 44)`. The rvalue `(22, 44)`
|
|
|
|
// would have an extended lifetime, but not `foo()`.
|
|
|
|
//
|
|
|
|
// Rule B. `let x: &[...] = [foo().x]`. The rvalue `[foo().x]`
|
|
|
|
// would have an extended lifetime, but not `foo()`.
|
|
|
|
//
|
|
|
|
// Rule C. `let x = &foo().x`. The rvalue ``foo()` would have extended
|
|
|
|
// lifetime.
|
|
|
|
//
|
|
|
|
// In some cases, multiple rules may apply (though not to the same
|
|
|
|
// rvalue). For example:
|
|
|
|
//
|
|
|
|
// let ref x = [&a(), &b()];
|
|
|
|
//
|
|
|
|
// Here, the expression `[...]` has an extended lifetime due to rule
|
|
|
|
// A, but the inner rvalues `a()` and `b()` have an extended lifetime
|
|
|
|
// due to rule C.
|
|
|
|
//
|
2014-01-15 18:44:38 -06:00
|
|
|
// FIXME(#6308) -- Note that `[]` patterns work more smoothly post-DST.
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
match local.init {
|
|
|
|
Some(expr) => {
|
|
|
|
record_rvalue_scope_if_borrow_expr(visitor, expr, blk_id);
|
|
|
|
|
|
|
|
if is_binding_pat(local.pat) || is_borrowed_ty(local.ty) {
|
|
|
|
record_rvalue_scope(visitor, expr, blk_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None => { }
|
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
visit::walk_local(visitor, local, cx);
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
fn is_binding_pat(pat: &ast::Pat) -> bool {
|
|
|
|
/*!
|
|
|
|
* True if `pat` match the `P&` nonterminal:
|
|
|
|
*
|
|
|
|
* P& = ref X
|
|
|
|
* | StructName { ..., P&, ... }
|
2014-01-17 07:10:42 -06:00
|
|
|
* | VariantName(..., P&, ...)
|
2014-01-15 13:39:08 -06:00
|
|
|
* | [ ..., P&, ... ]
|
|
|
|
* | ( ..., P&, ... )
|
|
|
|
* | ~P&
|
|
|
|
* | box P&
|
|
|
|
*/
|
|
|
|
|
|
|
|
match pat.node {
|
|
|
|
ast::PatIdent(ast::BindByRef(_), _, _) => true,
|
|
|
|
|
|
|
|
ast::PatStruct(_, ref field_pats, _) => {
|
|
|
|
field_pats.iter().any(|fp| is_binding_pat(fp.pat))
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::PatVec(ref pats1, ref pats2, ref pats3) => {
|
|
|
|
pats1.iter().any(|&p| is_binding_pat(p)) ||
|
|
|
|
pats2.iter().any(|&p| is_binding_pat(p)) ||
|
|
|
|
pats3.iter().any(|&p| is_binding_pat(p))
|
|
|
|
}
|
|
|
|
|
2014-01-17 07:10:42 -06:00
|
|
|
ast::PatEnum(_, Some(ref subpats)) |
|
2014-01-15 13:39:08 -06:00
|
|
|
ast::PatTup(ref subpats) => {
|
|
|
|
subpats.iter().any(|&p| is_binding_pat(p))
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::PatUniq(subpat) => {
|
|
|
|
is_binding_pat(subpat)
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_borrowed_ty(ty: &ast::Ty) -> bool {
|
|
|
|
/*!
|
|
|
|
* True if `ty` is a borrowed pointer type
|
|
|
|
* like `&int` or `&[...]`.
|
|
|
|
*/
|
|
|
|
|
|
|
|
match ty.node {
|
|
|
|
ast::TyRptr(..) => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_rvalue_scope_if_borrow_expr(visitor: &mut RegionResolutionVisitor,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
blk_id: ast::NodeId) {
|
|
|
|
/*!
|
|
|
|
* If `expr` matches the `E&` grammar, then records an extended
|
|
|
|
* rvalue scope as appropriate:
|
|
|
|
*
|
|
|
|
* E& = & ET
|
|
|
|
* | StructName { ..., f: E&, ... }
|
|
|
|
* | [ ..., E&, ... ]
|
|
|
|
* | ( ..., E&, ... )
|
|
|
|
* | {...; E&}
|
|
|
|
* | ~E&
|
|
|
|
* | E& as ...
|
|
|
|
* | ( E& )
|
|
|
|
*/
|
|
|
|
|
|
|
|
match expr.node {
|
|
|
|
ast::ExprAddrOf(_, subexpr) => {
|
|
|
|
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
|
|
|
|
record_rvalue_scope(visitor, subexpr, blk_id);
|
|
|
|
}
|
|
|
|
ast::ExprStruct(_, ref fields, _) => {
|
|
|
|
for field in fields.iter() {
|
|
|
|
record_rvalue_scope_if_borrow_expr(
|
|
|
|
visitor, field.expr, blk_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::ExprVstore(subexpr, _) => {
|
|
|
|
visitor.region_maps.record_rvalue_scope(subexpr.id, blk_id);
|
|
|
|
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
|
|
|
|
}
|
|
|
|
ast::ExprVec(ref subexprs, _) |
|
|
|
|
ast::ExprTup(ref subexprs) => {
|
|
|
|
for &subexpr in subexprs.iter() {
|
|
|
|
record_rvalue_scope_if_borrow_expr(
|
|
|
|
visitor, subexpr, blk_id);
|
|
|
|
}
|
|
|
|
}
|
2014-02-26 08:06:45 -06:00
|
|
|
ast::ExprUnary(ast::UnUniq, subexpr) => {
|
2014-01-15 13:39:08 -06:00
|
|
|
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
|
|
|
|
}
|
|
|
|
ast::ExprCast(subexpr, _) |
|
|
|
|
ast::ExprParen(subexpr) => {
|
|
|
|
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id)
|
|
|
|
}
|
|
|
|
ast::ExprBlock(ref block) => {
|
|
|
|
match block.expr {
|
|
|
|
Some(subexpr) => {
|
|
|
|
record_rvalue_scope_if_borrow_expr(
|
|
|
|
visitor, subexpr, blk_id);
|
|
|
|
}
|
|
|
|
None => { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_rvalue_scope<'a>(visitor: &mut RegionResolutionVisitor,
|
|
|
|
expr: &'a ast::Expr,
|
|
|
|
blk_id: ast::NodeId) {
|
|
|
|
/*!
|
|
|
|
* Applied to an expression `expr` if `expr` -- or something
|
|
|
|
* owned or partially owned by `expr` -- is going to be
|
|
|
|
* indirectly referenced by a variable in a let statement. In
|
|
|
|
* that case, the "temporary lifetime" or `expr` is extended
|
|
|
|
* to be the block enclosing the `let` statement.
|
|
|
|
*
|
|
|
|
* More formally, if `expr` matches the grammar `ET`, record
|
|
|
|
* the rvalue scope of the matching `<rvalue>` as `blk_id`:
|
|
|
|
*
|
|
|
|
* ET = *ET
|
|
|
|
* | ET[...]
|
|
|
|
* | ET.f
|
|
|
|
* | (ET)
|
|
|
|
* | <rvalue>
|
|
|
|
*
|
|
|
|
* Note: ET is intended to match "rvalues or
|
|
|
|
* lvalues based on rvalues".
|
|
|
|
*/
|
|
|
|
|
|
|
|
let mut expr = expr;
|
|
|
|
loop {
|
|
|
|
// Note: give all the expressions matching `ET` with the
|
|
|
|
// extended temporary lifetime, not just the innermost rvalue,
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
match expr.node {
|
|
|
|
ast::ExprAddrOf(_, ref subexpr) |
|
2014-02-26 08:06:45 -06:00
|
|
|
ast::ExprUnary(ast::UnDeref, ref subexpr) |
|
2014-01-15 13:39:08 -06:00
|
|
|
ast::ExprField(ref subexpr, _, _) |
|
2014-02-26 08:06:45 -06:00
|
|
|
ast::ExprIndex(ref subexpr, _) |
|
2014-01-15 13:39:08 -06:00
|
|
|
ast::ExprParen(ref subexpr) => {
|
2014-01-15 18:44:38 -06:00
|
|
|
let subexpr: &'a @Expr = subexpr; // FIXME(#11586)
|
2014-01-15 13:39:08 -06:00
|
|
|
expr = &**subexpr;
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-14 13:41:20 -05:00
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
fn resolve_item(visitor: &mut RegionResolutionVisitor,
|
2014-01-09 07:05:33 -06:00
|
|
|
item: &ast::Item,
|
2013-08-13 07:36:10 -05:00
|
|
|
cx: Context) {
|
2012-03-09 18:39:54 -06:00
|
|
|
// Items create a new outer block scope as far as we're concerned.
|
2013-03-15 14:24:24 -05:00
|
|
|
let new_cx = Context {var_parent: None, parent: None, ..cx};
|
2013-08-13 07:36:10 -05:00
|
|
|
visit::walk_item(visitor, item, new_cx);
|
2012-03-09 18:39:54 -06:00
|
|
|
}
|
|
|
|
|
2013-08-13 07:36:10 -05:00
|
|
|
fn resolve_fn(visitor: &mut RegionResolutionVisitor,
|
2014-01-09 07:05:33 -06:00
|
|
|
fk: &FnKind,
|
|
|
|
decl: &ast::FnDecl,
|
2014-01-06 06:00:46 -06:00
|
|
|
body: &ast::Block,
|
2013-08-31 11:13:04 -05:00
|
|
|
sp: Span,
|
2013-07-27 03:25:59 -05:00
|
|
|
id: ast::NodeId,
|
2013-08-13 07:36:10 -05:00
|
|
|
cx: Context) {
|
2014-01-15 13:39:08 -06:00
|
|
|
debug!("region::resolve_fn(id={}, \
|
2013-09-28 00:38:08 -05:00
|
|
|
span={:?}, \
|
2014-01-15 13:39:08 -06:00
|
|
|
body.id={}, \
|
|
|
|
cx.parent={})",
|
2013-06-04 23:43:41 -05:00
|
|
|
id,
|
2013-09-25 03:59:56 -05:00
|
|
|
visitor.sess.codemap.span_to_str(sp),
|
2013-07-16 13:08:35 -05:00
|
|
|
body.id,
|
2013-06-04 23:43:41 -05:00
|
|
|
cx.parent);
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
visitor.region_maps.mark_as_terminating_scope(body.id);
|
|
|
|
|
2013-03-15 14:24:24 -05:00
|
|
|
// The arguments and `self` are parented to the body of the fn.
|
2013-07-16 13:08:35 -05:00
|
|
|
let decl_cx = Context {parent: Some(body.id),
|
2014-01-15 13:39:08 -06:00
|
|
|
var_parent: Some(body.id)};
|
2013-08-13 07:36:10 -05:00
|
|
|
visit::walk_fn_decl(visitor, decl, decl_cx);
|
2013-01-23 20:15:06 -06:00
|
|
|
|
2013-03-15 14:24:24 -05:00
|
|
|
// The body of the fn itself is either a root scope (top-level fn)
|
|
|
|
// or it continues with the inherited scope (closures).
|
|
|
|
let body_cx = match *fk {
|
2014-01-09 07:05:33 -06:00
|
|
|
visit::FkItemFn(..) | visit::FkMethod(..) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
Context {parent: None, var_parent: None, ..cx}
|
|
|
|
}
|
2014-02-07 09:09:46 -06:00
|
|
|
visit::FkFnBlock(..) => {
|
|
|
|
// FIXME(#3696) -- at present we are place the closure body
|
|
|
|
// within the region hierarchy exactly where it appears lexically.
|
|
|
|
// This is wrong because the closure may live longer
|
|
|
|
// than the enclosing expression. We should probably fix this,
|
|
|
|
// but the correct fix is a bit subtle, and I am also not sure
|
|
|
|
// that the present approach is unsound -- it may not permit
|
|
|
|
// any illegal programs. See issue for more details.
|
|
|
|
cx
|
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
};
|
2013-08-13 07:36:10 -05:00
|
|
|
visitor.visit_block(body, body_cx);
|
|
|
|
}
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
impl<'a> Visitor<Context> for RegionResolutionVisitor<'a> {
|
2013-08-13 07:36:10 -05:00
|
|
|
|
2014-01-06 06:00:46 -06:00
|
|
|
fn visit_block(&mut self, b: &Block, cx: Context) {
|
2013-08-13 07:36:10 -05:00
|
|
|
resolve_block(self, b, cx);
|
|
|
|
}
|
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
fn visit_item(&mut self, i: &Item, cx: Context) {
|
2013-08-13 07:36:10 -05:00
|
|
|
resolve_item(self, i, cx);
|
|
|
|
}
|
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl,
|
2014-01-06 06:00:46 -06:00
|
|
|
b: &Block, s: Span, n: NodeId, cx: Context) {
|
2013-08-13 07:36:10 -05:00
|
|
|
resolve_fn(self, fk, fd, b, s, n, cx);
|
|
|
|
}
|
2014-01-06 06:00:46 -06:00
|
|
|
fn visit_arm(&mut self, a: &Arm, cx: Context) {
|
2013-08-13 07:36:10 -05:00
|
|
|
resolve_arm(self, a, cx);
|
|
|
|
}
|
2014-01-06 06:00:46 -06:00
|
|
|
fn visit_pat(&mut self, p: &Pat, cx: Context) {
|
2013-08-13 07:36:10 -05:00
|
|
|
resolve_pat(self, p, cx);
|
|
|
|
}
|
2014-01-06 06:00:46 -06:00
|
|
|
fn visit_stmt(&mut self, s: &Stmt, cx: Context) {
|
2013-08-13 07:36:10 -05:00
|
|
|
resolve_stmt(self, s, cx);
|
|
|
|
}
|
2014-01-06 06:00:46 -06:00
|
|
|
fn visit_expr(&mut self, ex: &Expr, cx: Context) {
|
2013-08-13 07:36:10 -05:00
|
|
|
resolve_expr(self, ex, cx);
|
|
|
|
}
|
2014-01-06 06:00:46 -06:00
|
|
|
fn visit_local(&mut self, l: &Local, cx: Context) {
|
2013-08-13 07:36:10 -05:00
|
|
|
resolve_local(self, l, cx);
|
|
|
|
}
|
2012-04-26 18:02:01 -05:00
|
|
|
}
|
|
|
|
|
2014-02-05 15:15:24 -06:00
|
|
|
pub fn resolve_crate(sess: Session, krate: &ast::Crate) -> RegionMaps {
|
2014-01-15 13:39:08 -06:00
|
|
|
let maps = RegionMaps {
|
2014-02-28 16:34:26 -06:00
|
|
|
scope_map: RefCell::new(NodeMap::new()),
|
|
|
|
var_map: RefCell::new(NodeMap::new()),
|
2014-01-15 13:39:08 -06:00
|
|
|
free_region_map: RefCell::new(HashMap::new()),
|
2014-02-28 16:34:26 -06:00
|
|
|
rvalue_scopes: RefCell::new(NodeMap::new()),
|
2014-01-15 13:39:08 -06:00
|
|
|
terminating_scopes: RefCell::new(HashSet::new()),
|
|
|
|
};
|
|
|
|
{
|
|
|
|
let mut visitor = RegionResolutionVisitor {
|
|
|
|
sess: sess,
|
|
|
|
region_maps: &maps
|
|
|
|
};
|
|
|
|
let cx = Context { parent: None, var_parent: None };
|
2014-02-05 15:15:24 -06:00
|
|
|
visit::walk_crate(&mut visitor, krate, cx);
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
return maps;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn resolve_inlined_item(sess: Session,
|
|
|
|
region_maps: &RegionMaps,
|
|
|
|
item: &ast::InlinedItem) {
|
|
|
|
let cx = Context {parent: None,
|
|
|
|
var_parent: None};
|
2013-09-25 03:59:56 -05:00
|
|
|
let mut visitor = RegionResolutionVisitor {
|
|
|
|
sess: sess,
|
2014-01-15 13:39:08 -06:00
|
|
|
region_maps: region_maps,
|
2013-09-25 03:59:56 -05:00
|
|
|
};
|
2014-01-15 13:39:08 -06:00
|
|
|
visit::walk_inlined_item(&mut visitor, item, cx);
|
2012-03-09 18:39:54 -06:00
|
|
|
}
|
2013-06-12 12:16:30 -05:00
|
|
|
|