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;
|
2012-09-04 13:54:36 -05:00
|
|
|
use metadata::csearch;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::resolve;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::ty::{region_variance, rv_covariant, rv_invariant};
|
2013-04-02 00:32:37 -05:00
|
|
|
use middle::ty::{rv_contravariant, FreeRegion};
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::ty;
|
2012-09-04 13:54:36 -05:00
|
|
|
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::hashmap::{HashMap, HashSet};
|
2012-12-13 15:05:22 -06:00
|
|
|
use syntax::ast_map;
|
|
|
|
use syntax::codemap::span;
|
|
|
|
use syntax::print::pprust;
|
2013-05-14 19:27:27 -05:00
|
|
|
use syntax::parse::token;
|
2013-02-27 18:41:02 -06:00
|
|
|
use syntax::parse::token::special_idents;
|
2013-07-19 20:42:11 -05:00
|
|
|
use syntax::{ast, oldvisit};
|
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.
|
|
|
|
|
|
|
|
- `scope_map` maps from:
|
|
|
|
- an expression to the expression or block encoding the maximum
|
|
|
|
(static) lifetime of a value produced by that expression. This is
|
|
|
|
generally the innermost call, statement, match, or block.
|
|
|
|
- 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`
|
|
|
|
- the free region map is populated during type check as we check
|
|
|
|
each function. See the function `relate_free_regions` for
|
|
|
|
more information.
|
2013-03-15 14:24:24 -05:00
|
|
|
- `cleanup_scopes` includes scopes where trans cleanups occur
|
|
|
|
- this is intended to reflect the current state of trans, not
|
|
|
|
necessarily how I think things ought to work
|
2012-08-17 16:09:20 -05:00
|
|
|
*/
|
2013-04-02 00:32:37 -05:00
|
|
|
pub struct RegionMaps {
|
2013-07-27 03:25:59 -05:00
|
|
|
priv scope_map: HashMap<ast::NodeId, ast::NodeId>,
|
2013-04-02 00:32:37 -05:00
|
|
|
priv free_region_map: HashMap<FreeRegion, ~[FreeRegion]>,
|
2013-07-27 03:25:59 -05:00
|
|
|
priv cleanup_scopes: 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 {
|
2012-10-15 16:56:42 -05:00
|
|
|
sess: Session,
|
2012-09-07 16:50:47 -05:00
|
|
|
def_map: resolve::DefMap,
|
2012-08-17 16:09:20 -05:00
|
|
|
|
|
|
|
// Generated maps:
|
2013-04-02 00:32:37 -05:00
|
|
|
region_maps: @mut RegionMaps,
|
2012-04-01 16:28:30 -05:00
|
|
|
|
2013-03-15 14:24:24 -05:00
|
|
|
// Scope where variables should be parented to
|
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
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl RegionMaps {
|
|
|
|
pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
|
2013-04-02 00:32:37 -05:00
|
|
|
match self.free_region_map.find_mut(&sub) {
|
|
|
|
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
|
|
|
|
|
|
|
debug!("relate_free_regions(sub=%?, sup=%?)", sub, sup);
|
|
|
|
|
|
|
|
self.free_region_map.insert(sub, ~[sup]);
|
2012-03-11 15:28:43 -05:00
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn record_parent(&mut self, sub: ast::NodeId, sup: ast::NodeId) {
|
2013-04-02 00:32:37 -05:00
|
|
|
debug!("record_parent(sub=%?, sup=%?)", sub, sup);
|
2013-03-15 14:24:24 -05:00
|
|
|
assert!(sub != sup);
|
2012-10-19 08:01:01 -05:00
|
|
|
|
2013-04-02 00:32:37 -05:00
|
|
|
self.scope_map.insert(sub, sup);
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn record_cleanup_scope(&mut self, scope_id: ast::NodeId) {
|
2013-03-15 14:24:24 -05:00
|
|
|
//! Records that a scope is a CLEANUP SCOPE. This is invoked
|
|
|
|
//! from within regionck. We wait until regionck because we do
|
|
|
|
//! not know which operators are overloaded until that point,
|
|
|
|
//! and only overloaded operators result in cleanup scopes.
|
|
|
|
|
|
|
|
self.cleanup_scopes.insert(scope_id);
|
|
|
|
}
|
|
|
|
|
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-08-04 16:59:36 -05:00
|
|
|
self.scope_map.find(&id).map_move(|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.
|
|
|
|
|
|
|
|
match self.scope_map.find(&id) {
|
|
|
|
Some(&r) => r,
|
2013-05-05 17:18:51 -05:00
|
|
|
None => { fail!("No enclosing scope for id %?", id); }
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn is_cleanup_scope(&self, scope_id: ast::NodeId) -> bool {
|
2013-03-15 14:24:24 -05:00
|
|
|
self.cleanup_scopes.contains(&scope_id)
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn cleanup_scope(&self, expr_id: ast::NodeId) -> ast::NodeId {
|
2013-03-15 14:24:24 -05:00
|
|
|
//! Returns the scope when temps in expr will be cleaned up
|
|
|
|
|
|
|
|
let mut id = self.encl_scope(expr_id);
|
|
|
|
while !self.cleanup_scopes.contains(&id) {
|
|
|
|
id = self.encl_scope(id);
|
|
|
|
}
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
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-04-02 00:32:37 -05:00
|
|
|
ty::re_scope(self.encl_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 {
|
|
|
|
match self.scope_map.find(&s) {
|
|
|
|
None => {
|
|
|
|
debug!("is_subscope_of(%?, %?, s=%?)=false",
|
|
|
|
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
|
|
|
|
|
|
|
debug!("is_subscope_of(%?, %?)=true",
|
|
|
|
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.
|
|
|
|
let mut queue = ~[sub];
|
|
|
|
let mut i = 0;
|
|
|
|
while i < queue.len() {
|
|
|
|
match self.free_region_map.find(&queue[i]) {
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
debug!("is_subregion_of(sub_region=%?, super_region=%?)",
|
|
|
|
sub_region, super_region);
|
|
|
|
|
|
|
|
sub_region == super_region || {
|
|
|
|
match (sub_region, super_region) {
|
|
|
|
(_, ty::re_static) => {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
(ty::re_scope(sub_scope), ty::re_scope(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-04-02 00:32:37 -05:00
|
|
|
(ty::re_scope(sub_scope), ty::re_free(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-04-02 00:32:37 -05:00
|
|
|
(ty::re_free(sub_fr), ty::re_free(super_fr)) => {
|
|
|
|
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)
|
|
|
|
-> ~[ast::NodeId]
|
2013-04-02 00:32:37 -05:00
|
|
|
{
|
2013-03-15 14:24:24 -05:00
|
|
|
// debug!("ancestors_of(scope=%d)", scope);
|
2013-04-02 00:32:37 -05:00
|
|
|
let mut result = ~[scope];
|
|
|
|
let mut scope = scope;
|
|
|
|
loop {
|
2013-05-10 17:15:06 -05:00
|
|
|
match this.scope_map.find(&scope) {
|
2013-04-02 00:32:37 -05:00
|
|
|
None => return result,
|
|
|
|
Some(&superscope) => {
|
|
|
|
result.push(superscope);
|
|
|
|
scope = superscope;
|
|
|
|
}
|
|
|
|
}
|
2013-03-15 14:24:24 -05:00
|
|
|
// debug!("ancestors_of_loop(scope=%d)", 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`.
|
2013-07-27 03:25:59 -05:00
|
|
|
fn parent_to_expr(cx: Context, child_id: ast::NodeId, sp: span) {
|
2013-06-04 23:43:41 -05:00
|
|
|
debug!("region::parent_to_expr(span=%?)",
|
|
|
|
cx.sess.codemap.span_to_str(sp));
|
2013-08-03 11:45:23 -05:00
|
|
|
for parent_id in cx.parent.iter() {
|
2013-04-02 00:32:37 -05:00
|
|
|
cx.region_maps.record_parent(child_id, *parent_id);
|
2012-03-09 18:39:54 -06:00
|
|
|
}
|
2012-03-12 14:43:02 -05:00
|
|
|
}
|
|
|
|
|
2013-07-19 20:42:11 -05:00
|
|
|
fn resolve_block(blk: &ast::Block,
|
|
|
|
(cx, visitor): (Context, oldvisit::vt<Context>)) {
|
2012-03-12 14:43:02 -05:00
|
|
|
// Record the parent of this block.
|
2013-07-16 13:08:35 -05:00
|
|
|
parent_to_expr(cx, blk.id, blk.span);
|
2012-03-09 18:39:54 -06:00
|
|
|
|
2012-03-12 14:43:02 -05:00
|
|
|
// Descend.
|
2013-07-16 13:08:35 -05:00
|
|
|
let new_cx = Context {var_parent: Some(blk.id),
|
|
|
|
parent: Some(blk.id),
|
2013-03-15 14:24:24 -05:00
|
|
|
..cx};
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_block(blk, (new_cx, visitor));
|
2012-03-09 18:39:54 -06:00
|
|
|
}
|
|
|
|
|
2013-07-19 20:42:11 -05:00
|
|
|
fn resolve_arm(arm: &ast::arm,
|
|
|
|
(cx, visitor): (Context, oldvisit::vt<Context>)) {
|
|
|
|
oldvisit::visit_arm(arm, (cx, visitor));
|
2012-03-11 14:05:17 -05:00
|
|
|
}
|
|
|
|
|
2013-07-19 20:42:11 -05:00
|
|
|
fn resolve_pat(pat: @ast::pat,
|
|
|
|
(cx, visitor): (Context, oldvisit::vt<Context>)) {
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(cx.var_parent, cx.parent);
|
2013-06-04 23:43:41 -05:00
|
|
|
parent_to_expr(cx, pat.id, pat.span);
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_pat(pat, (cx, visitor));
|
2012-03-11 14:05:17 -05:00
|
|
|
}
|
|
|
|
|
2013-07-19 20:42:11 -05:00
|
|
|
fn resolve_stmt(stmt: @ast::stmt,
|
|
|
|
(cx, visitor): (Context, oldvisit::vt<Context>)) {
|
2012-08-17 16:09:20 -05:00
|
|
|
match stmt.node {
|
2013-03-15 14:24:24 -05:00
|
|
|
ast::stmt_decl(*) => {
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_stmt(stmt, (cx, visitor));
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
|
|
|
ast::stmt_expr(_, stmt_id) |
|
|
|
|
ast::stmt_semi(_, stmt_id) => {
|
2013-06-04 23:43:41 -05:00
|
|
|
parent_to_expr(cx, stmt_id, stmt.span);
|
2013-03-15 14:24:24 -05:00
|
|
|
let expr_cx = Context {parent: Some(stmt_id), ..cx};
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_stmt(stmt, (expr_cx, visitor));
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
2013-05-19 00:07:44 -05:00
|
|
|
ast::stmt_mac(*) => cx.sess.bug("unexpanded macro")
|
2012-08-17 16:09:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-19 20:42:11 -05:00
|
|
|
fn resolve_expr(expr: @ast::expr,
|
|
|
|
(cx, visitor): (Context, oldvisit::vt<Context>)) {
|
2013-06-04 23:43:41 -05:00
|
|
|
parent_to_expr(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 {
|
2013-03-15 14:24:24 -05:00
|
|
|
ast::expr_assign_op(*) | ast::expr_index(*) | ast::expr_binary(*) |
|
|
|
|
ast::expr_unary(*) | ast::expr_call(*) | ast::expr_method_call(*) => {
|
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.
|
|
|
|
//
|
|
|
|
// parent_to_expr(new_cx, expr.callee_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::expr_match(*) => {
|
|
|
|
new_cx.var_parent = Some(expr.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => {}
|
2012-07-26 10:51:57 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_expr(expr, (new_cx, visitor));
|
2012-03-11 19:01:28 -05:00
|
|
|
}
|
|
|
|
|
2013-07-19 00:38:55 -05:00
|
|
|
fn resolve_local(local: @ast::Local,
|
2013-07-19 20:42:11 -05:00
|
|
|
(cx, visitor): (Context, oldvisit::vt<Context>)) {
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(cx.var_parent, cx.parent);
|
2013-07-19 00:38:55 -05:00
|
|
|
parent_to_expr(cx, local.id, local.span);
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_local(local, (cx, visitor));
|
2012-03-14 13:41:20 -05:00
|
|
|
}
|
|
|
|
|
2013-07-19 20:42:11 -05:00
|
|
|
fn resolve_item(item: @ast::item,
|
|
|
|
(cx, visitor): (Context, oldvisit::vt<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-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_item(item, (new_cx, visitor));
|
2012-03-09 18:39:54 -06:00
|
|
|
}
|
|
|
|
|
2013-07-19 20:42:11 -05:00
|
|
|
fn resolve_fn(fk: &oldvisit::fn_kind,
|
2013-06-27 08:04:22 -05:00
|
|
|
decl: &ast::fn_decl,
|
2013-07-19 00:38:55 -05:00
|
|
|
body: &ast::Block,
|
2013-06-27 08:04:22 -05:00
|
|
|
sp: span,
|
2013-07-27 03:25:59 -05:00
|
|
|
id: ast::NodeId,
|
2013-06-27 08:04:22 -05:00
|
|
|
(cx, visitor): (Context,
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::vt<Context>)) {
|
2013-06-04 23:43:41 -05:00
|
|
|
debug!("region::resolve_fn(id=%?, \
|
|
|
|
span=%?, \
|
2013-07-16 13:08:35 -05:00
|
|
|
body.id=%?, \
|
2013-06-04 23:43:41 -05:00
|
|
|
cx.parent=%?)",
|
|
|
|
id,
|
|
|
|
cx.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
|
|
|
|
|
|
|
// 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),
|
|
|
|
var_parent: Some(body.id),
|
2013-03-15 14:24:24 -05:00
|
|
|
..cx};
|
2013-02-18 23:25:44 -06:00
|
|
|
match *fk {
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::fk_method(_, _, method) => {
|
2013-07-16 13:08:35 -05:00
|
|
|
cx.region_maps.record_parent(method.self_id, body.id);
|
2013-01-23 20:15:06 -06:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_fn_decl(decl, (decl_cx, visitor));
|
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 {
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::fk_item_fn(*) |
|
|
|
|
oldvisit::fk_method(*) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
Context {parent: None, var_parent: None, ..cx}
|
|
|
|
}
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::fk_anon(*) |
|
|
|
|
oldvisit::fk_fn_block(*) => {
|
2013-03-15 14:24:24 -05:00
|
|
|
cx
|
|
|
|
}
|
|
|
|
};
|
2013-06-11 21:55:16 -05:00
|
|
|
(visitor.visit_block)(body, (body_cx, visitor));
|
2012-04-26 18:02:01 -05:00
|
|
|
}
|
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn resolve_crate(sess: Session,
|
|
|
|
def_map: resolve::DefMap,
|
2013-07-19 00:38:55 -05:00
|
|
|
crate: &ast::Crate) -> @mut RegionMaps
|
2013-04-02 00:32:37 -05:00
|
|
|
{
|
|
|
|
let region_maps = @mut RegionMaps {
|
|
|
|
scope_map: HashMap::new(),
|
2013-03-15 14:24:24 -05:00
|
|
|
free_region_map: HashMap::new(),
|
|
|
|
cleanup_scopes: HashSet::new(),
|
2013-04-02 00:32:37 -05:00
|
|
|
};
|
2013-03-15 14:24:24 -05:00
|
|
|
let cx = Context {sess: sess,
|
|
|
|
def_map: def_map,
|
|
|
|
region_maps: region_maps,
|
|
|
|
parent: None,
|
|
|
|
var_parent: None};
|
2013-07-19 20:42:11 -05:00
|
|
|
let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
|
2012-03-09 18:39:54 -06:00
|
|
|
visit_block: resolve_block,
|
|
|
|
visit_item: resolve_item,
|
2012-04-26 18:02:01 -05:00
|
|
|
visit_fn: resolve_fn,
|
2012-03-11 14:05:17 -05:00
|
|
|
visit_arm: resolve_arm,
|
2012-03-11 19:01:28 -05:00
|
|
|
visit_pat: resolve_pat,
|
2012-08-17 16:09:20 -05:00
|
|
|
visit_stmt: resolve_stmt,
|
2012-03-14 13:41:20 -05:00
|
|
|
visit_expr: resolve_expr,
|
2012-09-04 15:29:32 -05:00
|
|
|
visit_local: resolve_local,
|
2013-07-19 20:42:11 -05:00
|
|
|
.. *oldvisit::default_visitor()
|
2012-03-09 18:39:54 -06:00
|
|
|
});
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_crate(crate, (cx, visitor));
|
2013-04-02 00:32:37 -05:00
|
|
|
return region_maps;
|
2012-03-09 18:39:54 -06:00
|
|
|
}
|
2013-06-12 12:16:30 -05:00
|
|
|
|
2012-07-11 12:28:30 -05:00
|
|
|
// ___________________________________________________________________________
|
|
|
|
// Determining region parameterization
|
|
|
|
//
|
|
|
|
// Infers which type defns must be region parameterized---this is done
|
|
|
|
// by scanning their contents to see whether they reference a region
|
|
|
|
// type, directly or indirectly. This is a fixed-point computation.
|
|
|
|
//
|
|
|
|
// We do it in two passes. First we walk the AST and construct a map
|
|
|
|
// from each type defn T1 to other defns which make use of it. For example,
|
|
|
|
// if we have a type like:
|
|
|
|
//
|
|
|
|
// type S = *int;
|
|
|
|
// type T = S;
|
|
|
|
//
|
|
|
|
// Then there would be a map entry from S to T. During the same walk,
|
|
|
|
// we also construct add any types that reference regions to a set and
|
|
|
|
// a worklist. We can then process the worklist, propagating indirect
|
|
|
|
// dependencies until a fixed point is reached.
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub type region_paramd_items = @mut HashMap<ast::NodeId, region_variance>;
|
2012-07-11 12:28:30 -05:00
|
|
|
|
2013-03-20 10:40:02 -05:00
|
|
|
#[deriving(Eq)]
|
2013-01-30 15:44:24 -06:00
|
|
|
pub struct region_dep {
|
2013-01-25 18:57:39 -06:00
|
|
|
ambient_variance: region_variance,
|
2013-07-27 03:25:59 -05:00
|
|
|
id: ast::NodeId
|
2012-09-19 20:00:26 -05:00
|
|
|
}
|
2012-08-27 18:26:35 -05:00
|
|
|
|
2013-02-04 16:02:01 -06:00
|
|
|
pub struct DetermineRpCtxt {
|
2012-10-15 16:56:42 -05:00
|
|
|
sess: Session,
|
2012-07-11 12:28:30 -05:00
|
|
|
ast_map: ast_map::map,
|
2012-08-29 15:26:26 -05:00
|
|
|
def_map: resolve::DefMap,
|
2012-07-11 12:28:30 -05:00
|
|
|
region_paramd_items: region_paramd_items,
|
2013-07-27 03:25:59 -05:00
|
|
|
dep_map: @mut HashMap<ast::NodeId, @mut ~[region_dep]>,
|
|
|
|
worklist: ~[ast::NodeId],
|
2012-07-11 12:28:30 -05:00
|
|
|
|
2012-07-12 16:01:23 -05:00
|
|
|
// the innermost enclosing item id
|
2013-07-27 03:25:59 -05:00
|
|
|
item_id: ast::NodeId,
|
2012-07-12 16:01:23 -05:00
|
|
|
|
|
|
|
// true when we are within an item but not within a method.
|
2013-02-26 13:37:31 -06:00
|
|
|
// see long discussion on region_is_relevant().
|
2013-02-04 16:02:01 -06:00
|
|
|
anon_implies_rp: bool,
|
2012-08-09 11:59:50 -05:00
|
|
|
|
|
|
|
// encodes the context of the current type; invariant if
|
|
|
|
// mutable, covariant otherwise
|
2013-02-04 16:02:01 -06:00
|
|
|
ambient_variance: region_variance,
|
2012-07-11 17:00:40 -05:00
|
|
|
}
|
2013-06-12 12:16:30 -05:00
|
|
|
|
2013-04-17 11:15:37 -05:00
|
|
|
pub fn join_variance(variance1: region_variance,
|
|
|
|
variance2: region_variance)
|
2013-01-30 15:44:24 -06:00
|
|
|
-> region_variance {
|
2012-08-09 11:59:50 -05:00
|
|
|
match (variance1, variance2) {
|
|
|
|
(rv_invariant, _) => {rv_invariant}
|
|
|
|
(_, rv_invariant) => {rv_invariant}
|
|
|
|
(rv_covariant, rv_contravariant) => {rv_invariant}
|
|
|
|
(rv_contravariant, rv_covariant) => {rv_invariant}
|
|
|
|
(rv_covariant, rv_covariant) => {rv_covariant}
|
|
|
|
(rv_contravariant, rv_contravariant) => {rv_contravariant}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Combines the ambient variance with the variance of a
|
|
|
|
/// particular site to yield the final variance of the reference.
|
|
|
|
///
|
|
|
|
/// Example: if we are checking function arguments then the ambient
|
2013-03-14 13:22:51 -05:00
|
|
|
/// variance is contravariant. If we then find a `&'r T` pointer, `r`
|
2012-08-09 11:59:50 -05:00
|
|
|
/// appears in a co-variant position. This implies that this
|
|
|
|
/// occurrence of `r` is contra-variant with respect to the current
|
|
|
|
/// item, and hence the function returns `rv_contravariant`.
|
2013-04-17 11:15:37 -05:00
|
|
|
pub fn add_variance(ambient_variance: region_variance,
|
|
|
|
variance: region_variance)
|
2013-01-30 15:44:24 -06:00
|
|
|
-> region_variance {
|
2012-08-09 11:59:50 -05:00
|
|
|
match (ambient_variance, variance) {
|
|
|
|
(rv_invariant, _) => rv_invariant,
|
|
|
|
(_, rv_invariant) => rv_invariant,
|
|
|
|
(rv_covariant, c) => c,
|
|
|
|
(c, rv_covariant) => c,
|
|
|
|
(rv_contravariant, rv_contravariant) => rv_covariant
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl DetermineRpCtxt {
|
|
|
|
pub fn add_variance(&self, variance: region_variance) -> region_variance {
|
2012-08-09 11:59:50 -05:00
|
|
|
add_variance(self.ambient_variance, variance)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Records that item `id` is region-parameterized with the
|
|
|
|
/// variance `variance`. If `id` was already parameterized, then
|
|
|
|
/// the new variance is joined with the old variance.
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn add_rp(&mut self, id: ast::NodeId, variance: region_variance) {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(id != 0);
|
2013-08-04 16:59:36 -05:00
|
|
|
let old_variance = self.region_paramd_items.find(&id).map_move(|x| *x);
|
2012-08-09 11:59:50 -05:00
|
|
|
let joined_variance = match old_variance {
|
2012-08-20 14:23:37 -05:00
|
|
|
None => variance,
|
|
|
|
Some(v) => join_variance(v, variance)
|
2012-08-09 11:59:50 -05:00
|
|
|
};
|
|
|
|
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("add_rp() variance for %s: %? == %? ^ %?",
|
2012-08-09 11:59:50 -05:00
|
|
|
ast_map::node_id_to_str(self.ast_map, id,
|
2013-05-14 19:27:27 -05:00
|
|
|
token::get_ident_interner()),
|
2012-08-22 19:24:52 -05:00
|
|
|
joined_variance, old_variance, variance);
|
2012-08-09 11:59:50 -05:00
|
|
|
|
2012-08-20 14:23:37 -05:00
|
|
|
if Some(joined_variance) != old_variance {
|
2013-02-04 16:02:01 -06:00
|
|
|
let region_paramd_items = self.region_paramd_items;
|
|
|
|
region_paramd_items.insert(id, joined_variance);
|
2012-07-11 12:28:30 -05:00
|
|
|
self.worklist.push(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-09 11:59:50 -05:00
|
|
|
/// Indicates that the region-parameterization of the current item
|
|
|
|
/// is dependent on the region-parameterization of the item
|
|
|
|
/// `from`. Put another way, it indicates that the current item
|
|
|
|
/// contains a value of type `from`, so if `from` is
|
|
|
|
/// region-parameterized, so is the current item.
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn add_dep(&mut self, from: ast::NodeId) {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("add dependency from %d -> %d (%s -> %s) with variance %?",
|
2012-08-09 11:59:50 -05:00
|
|
|
from, self.item_id,
|
2012-07-18 18:18:02 -05:00
|
|
|
ast_map::node_id_to_str(self.ast_map, from,
|
2013-05-14 19:27:27 -05:00
|
|
|
token::get_ident_interner()),
|
2012-08-09 11:59:50 -05:00
|
|
|
ast_map::node_id_to_str(self.ast_map, self.item_id,
|
2013-05-14 19:27:27 -05:00
|
|
|
token::get_ident_interner()),
|
2013-06-27 19:41:35 -05:00
|
|
|
self.ambient_variance);
|
2013-06-27 08:04:22 -05:00
|
|
|
let vec = do self.dep_map.find_or_insert_with(from) |_| {
|
|
|
|
@mut ~[]
|
2012-07-11 12:28:30 -05:00
|
|
|
};
|
2013-01-25 18:57:39 -06:00
|
|
|
let dep = region_dep {
|
|
|
|
ambient_variance: self.ambient_variance,
|
|
|
|
id: self.item_id
|
|
|
|
};
|
2013-07-04 21:13:26 -05:00
|
|
|
if !vec.iter().any(|x| x == &dep) { vec.push(dep); }
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
|
2012-07-12 16:01:23 -05:00
|
|
|
// Determines whether a reference to a region that appears in the
|
2013-02-26 13:37:31 -06:00
|
|
|
// AST implies that the enclosing type is region-parameterized (RP).
|
|
|
|
// This point is subtle. Here are some examples to make it more
|
2012-07-12 16:01:23 -05:00
|
|
|
// concrete.
|
|
|
|
//
|
|
|
|
// 1. impl foo for &int { ... }
|
2013-03-14 13:22:51 -05:00
|
|
|
// 2. impl foo for &'self int { ... }
|
|
|
|
// 3. impl foo for bar { fn m(@self) -> &'self int { ... } }
|
|
|
|
// 4. impl foo for bar { fn m(&self) -> &'self int { ... } }
|
2013-02-26 13:37:31 -06:00
|
|
|
// 5. impl foo for bar { fn m(&self) -> &int { ... } }
|
2012-07-12 16:01:23 -05:00
|
|
|
//
|
|
|
|
// In case 1, the anonymous region is being referenced,
|
|
|
|
// but it appears in a context where the anonymous region
|
2013-02-26 13:37:31 -06:00
|
|
|
// resolves to self, so the impl foo is RP.
|
2012-07-12 16:01:23 -05:00
|
|
|
//
|
|
|
|
// In case 2, the self parameter is written explicitly.
|
|
|
|
//
|
2013-02-26 13:37:31 -06:00
|
|
|
// In case 3, the method refers to the region `self`, so that
|
|
|
|
// implies that the impl must be region parameterized. (If the
|
|
|
|
// type bar is not region parameterized, that is an error, because
|
|
|
|
// the self region is effectively unconstrained, but that is
|
|
|
|
// detected elsewhere).
|
|
|
|
//
|
|
|
|
// In case 4, the method refers to the region `self`, but the
|
|
|
|
// `self` region is bound by the `&self` receiver, and so this
|
|
|
|
// does not require that `bar` be RP.
|
2012-07-12 16:01:23 -05:00
|
|
|
//
|
2013-02-26 13:37:31 -06:00
|
|
|
// In case 5, the anonymous region is referenced, but it
|
2012-07-12 16:01:23 -05:00
|
|
|
// bound by the method, so it does not refer to self. This impl
|
|
|
|
// need not be region parameterized.
|
|
|
|
//
|
2013-02-26 13:37:31 -06:00
|
|
|
// Normally, & or &self implies that the enclosing item is RP.
|
|
|
|
// However, within a function, & is always bound. Within a method
|
|
|
|
// with &self type, &self is also bound. We detect those last two
|
|
|
|
// cases via flags (anon_implies_rp and self_implies_rp) that are
|
|
|
|
// true when the anon or self region implies RP.
|
2013-07-05 07:33:52 -05:00
|
|
|
pub fn region_is_relevant(&self, r: &Option<ast::Lifetime>) -> bool {
|
2013-02-27 18:41:02 -06:00
|
|
|
match r {
|
2013-07-05 07:33:52 -05:00
|
|
|
&None => {
|
2013-02-27 18:41:02 -06:00
|
|
|
self.anon_implies_rp
|
|
|
|
}
|
2013-07-05 07:33:52 -05:00
|
|
|
&Some(ref l) if l.ident == special_idents::statik => {
|
2013-02-27 18:41:02 -06:00
|
|
|
false
|
|
|
|
}
|
2013-07-05 07:33:52 -05:00
|
|
|
&Some(ref l) if l.ident == special_idents::self_ => {
|
2013-04-10 15:11:27 -05:00
|
|
|
true
|
2013-02-27 18:41:02 -06:00
|
|
|
}
|
2013-07-05 07:33:52 -05:00
|
|
|
&Some(_) => {
|
2013-02-27 18:41:02 -06:00
|
|
|
false
|
|
|
|
}
|
2012-08-23 18:22:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn with(@mut self,
|
2013-07-27 03:25:59 -05:00
|
|
|
item_id: ast::NodeId,
|
2013-05-31 17:17:22 -05:00
|
|
|
anon_implies_rp: bool,
|
|
|
|
f: &fn()) {
|
2012-07-11 12:28:30 -05:00
|
|
|
let old_item_id = self.item_id;
|
|
|
|
let old_anon_implies_rp = self.anon_implies_rp;
|
|
|
|
self.item_id = item_id;
|
|
|
|
self.anon_implies_rp = anon_implies_rp;
|
2013-04-10 15:11:27 -05:00
|
|
|
debug!("with_item_id(%d, %b)",
|
2013-02-26 13:37:31 -06:00
|
|
|
item_id,
|
2013-04-10 15:11:27 -05:00
|
|
|
anon_implies_rp);
|
2012-12-23 16:41:37 -06:00
|
|
|
let _i = ::util::common::indenter();
|
2012-07-11 12:28:30 -05:00
|
|
|
f();
|
|
|
|
self.item_id = old_item_id;
|
|
|
|
self.anon_implies_rp = old_anon_implies_rp;
|
|
|
|
}
|
2012-08-09 11:59:50 -05:00
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn with_ambient_variance(@mut self,
|
|
|
|
variance: region_variance,
|
|
|
|
f: &fn()) {
|
2012-08-09 11:59:50 -05:00
|
|
|
let old_ambient_variance = self.ambient_variance;
|
|
|
|
self.ambient_variance = self.add_variance(variance);
|
|
|
|
f();
|
|
|
|
self.ambient_variance = old_ambient_variance;
|
|
|
|
}
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
fn determine_rp_in_item(item: @ast::item,
|
|
|
|
(cx, visitor): (@mut DetermineRpCtxt,
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::vt<@mut DetermineRpCtxt>)) {
|
2013-04-10 15:11:27 -05:00
|
|
|
do cx.with(item.id, true) {
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_item(item, (cx, visitor));
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-19 20:42:11 -05:00
|
|
|
fn determine_rp_in_fn(fk: &oldvisit::fn_kind,
|
2013-06-27 08:04:22 -05:00
|
|
|
decl: &ast::fn_decl,
|
2013-07-19 00:38:55 -05:00
|
|
|
body: &ast::Block,
|
2013-06-27 08:04:22 -05:00
|
|
|
_: span,
|
2013-07-27 03:25:59 -05:00
|
|
|
_: ast::NodeId,
|
2013-06-27 08:04:22 -05:00
|
|
|
(cx, visitor): (@mut DetermineRpCtxt,
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::vt<@mut DetermineRpCtxt>)) {
|
2013-04-10 15:11:27 -05:00
|
|
|
do cx.with(cx.item_id, false) {
|
2012-08-09 11:59:50 -05:00
|
|
|
do cx.with_ambient_variance(rv_contravariant) {
|
2013-08-03 11:45:23 -05:00
|
|
|
for a in decl.inputs.iter() {
|
2013-07-05 23:57:11 -05:00
|
|
|
(visitor.visit_ty)(&a.ty, (cx, visitor));
|
2012-11-29 19:51:16 -06:00
|
|
|
}
|
2012-08-09 11:59:50 -05:00
|
|
|
}
|
2013-07-05 23:57:11 -05:00
|
|
|
(visitor.visit_ty)(&decl.output, (cx, visitor));
|
2013-07-19 20:42:11 -05:00
|
|
|
let generics = oldvisit::generics_of_fn(fk);
|
2013-06-11 21:55:16 -05:00
|
|
|
(visitor.visit_generics)(&generics, (cx, visitor));
|
|
|
|
(visitor.visit_block)(body, (cx, visitor));
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
fn determine_rp_in_ty_method(ty_m: &ast::TypeMethod,
|
2013-07-19 20:42:11 -05:00
|
|
|
(cx, visitor):
|
|
|
|
(@mut DetermineRpCtxt,
|
|
|
|
oldvisit::vt<@mut DetermineRpCtxt>)) {
|
2013-04-10 15:11:27 -05:00
|
|
|
do cx.with(cx.item_id, false) {
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_ty_method(ty_m, (cx, visitor));
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-05 23:57:11 -05:00
|
|
|
fn determine_rp_in_ty(ty: &ast::Ty,
|
2013-06-27 08:04:22 -05:00
|
|
|
(cx, visitor): (@mut DetermineRpCtxt,
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::vt<@mut DetermineRpCtxt>)) {
|
2013-01-19 19:06:36 -06:00
|
|
|
// we are only interested in types that will require an item to
|
2012-07-11 12:28:30 -05:00
|
|
|
// be region-parameterized. if cx.item_id is zero, then this type
|
|
|
|
// is not a member of a type defn nor is it a constitutent of an
|
|
|
|
// impl etc. So we can ignore it and its components.
|
2012-08-01 19:30:05 -05:00
|
|
|
if cx.item_id == 0 { return; }
|
2012-07-11 12:28:30 -05:00
|
|
|
|
2013-03-14 13:22:51 -05:00
|
|
|
// if this type directly references a region pointer like &'r ty,
|
|
|
|
// add to the worklist/set. Note that &'r ty is contravariant with
|
|
|
|
// respect to &r, because &'r ty can be used whereever a *smaller*
|
2012-08-09 11:59:50 -05:00
|
|
|
// region is expected (and hence is a supertype of those
|
|
|
|
// locations)
|
2013-02-04 16:02:01 -06:00
|
|
|
let sess = cx.sess;
|
2012-08-06 14:34:08 -05:00
|
|
|
match ty.node {
|
2013-07-05 07:33:52 -05:00
|
|
|
ast::ty_rptr(ref r, _) => {
|
2012-11-04 22:41:00 -06:00
|
|
|
debug!("referenced rptr type %s",
|
2013-02-04 16:02:01 -06:00
|
|
|
pprust::ty_to_str(ty, sess.intr()));
|
2012-08-09 11:59:50 -05:00
|
|
|
|
2012-11-04 22:41:00 -06:00
|
|
|
if cx.region_is_relevant(r) {
|
2013-03-15 14:24:24 -05:00
|
|
|
let rv = cx.add_variance(rv_contravariant);
|
|
|
|
cx.add_rp(cx.item_id, rv)
|
2012-11-04 22:41:00 -06:00
|
|
|
}
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
|
2013-01-31 19:12:29 -06:00
|
|
|
ast::ty_closure(ref f) => {
|
2012-11-04 22:41:00 -06:00
|
|
|
debug!("referenced fn type: %s",
|
2013-02-04 16:02:01 -06:00
|
|
|
pprust::ty_to_str(ty, sess.intr()));
|
2012-11-04 22:41:00 -06:00
|
|
|
match f.region {
|
2013-02-27 18:41:02 -06:00
|
|
|
Some(_) => {
|
2013-07-05 07:33:52 -05:00
|
|
|
if cx.region_is_relevant(&f.region) {
|
2013-03-15 14:24:24 -05:00
|
|
|
let rv = cx.add_variance(rv_contravariant);
|
|
|
|
cx.add_rp(cx.item_id, rv)
|
2012-11-04 22:41:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
2013-01-31 19:12:29 -06:00
|
|
|
if f.sigil == ast::BorrowedSigil && cx.anon_implies_rp {
|
2013-03-15 14:24:24 -05:00
|
|
|
let rv = cx.add_variance(rv_contravariant);
|
|
|
|
cx.add_rp(cx.item_id, rv)
|
2012-11-04 22:41:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-10 20:15:08 -05:00
|
|
|
|
2012-11-04 22:41:00 -06:00
|
|
|
_ => {}
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// if this references another named type, add the dependency
|
|
|
|
// to the dep_map. If the type is not defined in this crate,
|
|
|
|
// then check whether it is region-parameterized and consider
|
|
|
|
// that as a direct dependency.
|
2012-08-06 14:34:08 -05:00
|
|
|
match ty.node {
|
2013-07-05 20:38:56 -05:00
|
|
|
ast::ty_path(ref path, _, id) => {
|
2013-02-05 21:41:45 -06:00
|
|
|
match cx.def_map.find(&id) {
|
2013-03-27 09:26:57 -05:00
|
|
|
Some(&ast::def_ty(did)) |
|
|
|
|
Some(&ast::def_trait(did)) |
|
|
|
|
Some(&ast::def_struct(did)) => {
|
2013-07-27 03:25:59 -05:00
|
|
|
if did.crate == ast::LOCAL_CRATE {
|
2013-07-05 07:33:52 -05:00
|
|
|
if cx.region_is_relevant(&path.rp) {
|
2012-08-23 18:22:23 -05:00
|
|
|
cx.add_dep(did.node);
|
|
|
|
}
|
2012-07-11 12:28:30 -05:00
|
|
|
} else {
|
2013-02-04 16:02:01 -06:00
|
|
|
let cstore = sess.cstore;
|
2012-08-09 11:59:50 -05:00
|
|
|
match csearch::get_region_param(cstore, did) {
|
2012-08-20 14:23:37 -05:00
|
|
|
None => {}
|
|
|
|
Some(variance) => {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("reference to external, rp'd type %s",
|
2013-02-04 16:02:01 -06:00
|
|
|
pprust::ty_to_str(ty, sess.intr()));
|
2013-07-05 07:33:52 -05:00
|
|
|
if cx.region_is_relevant(&path.rp) {
|
2013-03-15 14:24:24 -05:00
|
|
|
let rv = cx.add_variance(variance);
|
|
|
|
cx.add_rp(cx.item_id, rv)
|
2012-08-23 18:22:23 -05:00
|
|
|
}
|
2012-08-09 11:59:50 -05:00
|
|
|
}
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => {}
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => {}
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
match ty.node {
|
2013-07-05 23:57:11 -05:00
|
|
|
ast::ty_box(ref mt) | ast::ty_uniq(ref mt) | ast::ty_vec(ref mt) |
|
|
|
|
ast::ty_rptr(_, ref mt) | ast::ty_ptr(ref mt) => {
|
2013-06-11 21:55:16 -05:00
|
|
|
visit_mt(mt, (cx, visitor));
|
2012-08-09 11:59:50 -05:00
|
|
|
}
|
|
|
|
|
2013-07-05 20:38:56 -05:00
|
|
|
ast::ty_path(ref path, _, _) => {
|
2012-08-09 11:59:50 -05:00
|
|
|
// type parameters are---for now, anyway---always invariant
|
|
|
|
do cx.with_ambient_variance(rv_invariant) {
|
2013-08-03 11:45:23 -05:00
|
|
|
for tp in path.types.iter() {
|
2013-07-05 23:57:11 -05:00
|
|
|
(visitor.visit_ty)(tp, (cx, visitor));
|
2012-08-09 11:59:50 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-31 19:12:29 -06:00
|
|
|
ast::ty_closure(@ast::TyClosure {decl: ref decl, _}) |
|
|
|
|
ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => {
|
2012-08-09 11:59:50 -05:00
|
|
|
// fn() binds the & region, so do not consider &T types that
|
|
|
|
// appear *inside* a fn() type to affect the enclosing item:
|
2013-04-10 15:11:27 -05:00
|
|
|
do cx.with(cx.item_id, false) {
|
2012-08-09 11:59:50 -05:00
|
|
|
// parameters are contravariant
|
|
|
|
do cx.with_ambient_variance(rv_contravariant) {
|
2013-08-03 11:45:23 -05:00
|
|
|
for a in decl.inputs.iter() {
|
2013-07-05 23:57:11 -05:00
|
|
|
(visitor.visit_ty)(&a.ty, (cx, visitor));
|
2012-08-09 11:59:50 -05:00
|
|
|
}
|
|
|
|
}
|
2013-07-05 23:57:11 -05:00
|
|
|
(visitor.visit_ty)(&decl.output, (cx, visitor));
|
2012-07-27 16:51:46 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-09 11:59:50 -05:00
|
|
|
|
2012-07-27 16:51:46 -05:00
|
|
|
_ => {
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_ty(ty, (cx, visitor));
|
2012-07-27 16:51:46 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-09 11:59:50 -05:00
|
|
|
|
2013-07-05 23:57:11 -05:00
|
|
|
fn visit_mt(mt: &ast::mt,
|
2013-06-11 21:55:16 -05:00
|
|
|
(cx, visitor): (@mut DetermineRpCtxt,
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::vt<@mut DetermineRpCtxt>)) {
|
2012-08-09 11:59:50 -05:00
|
|
|
// mutability is invariant
|
|
|
|
if mt.mutbl == ast::m_mutbl {
|
|
|
|
do cx.with_ambient_variance(rv_invariant) {
|
2013-06-11 21:55:16 -05:00
|
|
|
(visitor.visit_ty)(mt.ty, (cx, visitor));
|
2012-08-09 11:59:50 -05:00
|
|
|
}
|
|
|
|
} else {
|
2013-06-11 21:55:16 -05:00
|
|
|
(visitor.visit_ty)(mt.ty, (cx, visitor));
|
2012-08-09 11:59:50 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
fn determine_rp_in_struct_field(
|
2013-02-04 16:02:01 -06:00
|
|
|
cm: @ast::struct_field,
|
2013-06-11 21:55:16 -05:00
|
|
|
(cx, visitor): (@mut DetermineRpCtxt,
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::vt<@mut DetermineRpCtxt>)) {
|
|
|
|
oldvisit::visit_struct_field(cm, (cx, visitor));
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
2013-06-12 12:16:30 -05:00
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn determine_rp_in_crate(sess: Session,
|
|
|
|
ast_map: ast_map::map,
|
2013-04-17 11:15:37 -05:00
|
|
|
def_map: resolve::DefMap,
|
2013-07-19 00:38:55 -05:00
|
|
|
crate: &ast::Crate)
|
2013-01-30 15:44:24 -06:00
|
|
|
-> region_paramd_items {
|
2013-02-04 16:02:01 -06:00
|
|
|
let cx = @mut DetermineRpCtxt {
|
|
|
|
sess: sess,
|
|
|
|
ast_map: ast_map,
|
|
|
|
def_map: def_map,
|
2013-04-03 08:28:36 -05:00
|
|
|
region_paramd_items: @mut HashMap::new(),
|
|
|
|
dep_map: @mut HashMap::new(),
|
2013-02-04 16:02:01 -06:00
|
|
|
worklist: ~[],
|
|
|
|
item_id: 0,
|
|
|
|
anon_implies_rp: false,
|
|
|
|
ambient_variance: rv_covariant
|
|
|
|
};
|
2012-07-11 12:28:30 -05:00
|
|
|
|
2012-08-09 11:59:50 -05:00
|
|
|
// Gather up the base set, worklist and dep_map
|
2013-07-19 20:42:11 -05:00
|
|
|
let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
|
2012-07-11 12:28:30 -05:00
|
|
|
visit_fn: determine_rp_in_fn,
|
|
|
|
visit_item: determine_rp_in_item,
|
|
|
|
visit_ty: determine_rp_in_ty,
|
|
|
|
visit_ty_method: determine_rp_in_ty_method,
|
2012-08-09 11:59:50 -05:00
|
|
|
visit_struct_field: determine_rp_in_struct_field,
|
2013-07-19 20:42:11 -05:00
|
|
|
.. *oldvisit::default_visitor()
|
2012-07-11 12:28:30 -05:00
|
|
|
});
|
2013-07-19 20:42:11 -05:00
|
|
|
oldvisit::visit_crate(crate, (cx, visitor));
|
2012-07-11 12:28:30 -05:00
|
|
|
|
2012-08-09 11:59:50 -05:00
|
|
|
// Propagate indirect dependencies
|
|
|
|
//
|
|
|
|
// Each entry in the worklist is the id of an item C whose region
|
|
|
|
// parameterization has been updated. So we pull ids off of the
|
|
|
|
// worklist, find the current variance, and then iterate through
|
|
|
|
// all of the dependent items (that is, those items that reference
|
|
|
|
// C). For each dependent item D, we combine the variance of C
|
|
|
|
// with the ambient variance where the reference occurred and then
|
|
|
|
// update the region-parameterization of D to reflect the result.
|
2013-03-16 13:11:31 -05:00
|
|
|
{
|
|
|
|
let cx = &mut *cx;
|
|
|
|
while cx.worklist.len() != 0 {
|
|
|
|
let c_id = cx.worklist.pop();
|
2013-05-05 11:17:59 -05:00
|
|
|
let c_variance = cx.region_paramd_items.get_copy(&c_id);
|
2013-03-16 13:11:31 -05:00
|
|
|
debug!("popped %d from worklist", c_id);
|
|
|
|
match cx.dep_map.find(&c_id) {
|
|
|
|
None => {}
|
|
|
|
Some(deps) => {
|
2013-08-03 11:45:23 -05:00
|
|
|
for dep in deps.iter() {
|
2013-03-16 13:11:31 -05:00
|
|
|
let v = add_variance(dep.ambient_variance, c_variance);
|
|
|
|
cx.add_rp(dep.id, v);
|
|
|
|
}
|
|
|
|
}
|
2012-07-11 12:28:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-09 11:59:50 -05:00
|
|
|
debug!("%s", {
|
|
|
|
debug!("Region variance results:");
|
2013-02-04 16:02:01 -06:00
|
|
|
let region_paramd_items = cx.region_paramd_items;
|
2013-08-03 11:45:23 -05:00
|
|
|
for (&key, &value) in region_paramd_items.iter() {
|
2012-08-09 11:59:50 -05:00
|
|
|
debug!("item %? (%s) is parameterized with variance %?",
|
|
|
|
key,
|
|
|
|
ast_map::node_id_to_str(ast_map, key,
|
2013-05-14 19:27:27 -05:00
|
|
|
token::get_ident_interner()),
|
2012-08-09 11:59:50 -05:00
|
|
|
value);
|
|
|
|
}
|
|
|
|
"----"
|
|
|
|
});
|
|
|
|
|
2012-07-11 12:28:30 -05:00
|
|
|
// return final set
|
2012-08-01 19:30:05 -05:00
|
|
|
return cx.region_paramd_items;
|
2012-07-14 14:45:45 -05:00
|
|
|
}
|