rustc: move freevar finding to resolve.

This commit is contained in:
Eduard Burtescu 2014-09-18 05:45:21 +03:00
parent 5c192ae123
commit 7c5df404b0
13 changed files with 183 additions and 306 deletions

View File

@ -17,7 +17,7 @@ use lint;
use llvm::{ContextRef, ModuleRef};
use metadata::common::LinkMeta;
use metadata::creader;
use middle::{trans, freevars, stability, kind, ty, typeck, reachable};
use middle::{trans, stability, kind, ty, typeck, reachable};
use middle::dependency_format;
use middle;
use plugin::load::Plugins;
@ -378,11 +378,13 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
middle::lang_items::collect_language_items(krate, &sess));
let middle::resolve::CrateMap {
def_map: def_map,
exp_map2: exp_map2,
trait_map: trait_map,
external_exports: external_exports,
last_private_map: last_private_map
def_map,
freevars,
capture_mode_map,
exp_map2,
trait_map,
external_exports,
last_private_map
} =
time(time_passes, "resolution", (), |_|
middle::resolve::resolve_crate(&sess, &lang_items, krate));
@ -401,10 +403,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
plugin::build::find_plugin_registrar(
sess.diagnostic(), krate)));
let (freevars, capture_modes) =
time(time_passes, "freevar finding", (), |_|
freevars::annotate_freevars(&def_map, krate));
let region_map = time(time_passes, "region resolution", (), |_|
middle::region::resolve_crate(&sess, krate));
@ -423,7 +421,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
named_region_map,
ast_map,
freevars,
capture_modes,
capture_mode_map,
region_map,
lang_items,
stability_index);

View File

@ -93,7 +93,6 @@ pub mod middle {
pub mod effect;
pub mod entry;
pub mod expr_use_visitor;
pub mod freevars;
pub mod graph;
pub mod intrinsicck;
pub mod kind;

View File

@ -16,7 +16,6 @@
use middle::mem_categorization as mc;
use middle::def;
use middle::freevars;
use middle::mem_categorization::Typer;
use middle::pat_util;
use middle::ty;

View File

@ -1,128 +0,0 @@
// Copyright 2012-2014 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.
// A pass that annotates for each loops and functions with the free
// variables that they contain.
#![allow(non_camel_case_types)]
use middle::def;
use middle::resolve;
use middle::ty;
use util::nodemap::{NodeMap, NodeSet};
use syntax::ast;
use syntax::codemap::Span;
use syntax::visit::Visitor;
use syntax::visit;
struct CollectFreevarsVisitor<'a, 'b:'a> {
node_id: ast::NodeId,
seen: NodeSet,
cx: &'a mut AnnotateFreevarsVisitor<'b>,
depth: u32
}
impl<'a, 'b, 'v> Visitor<'v> for CollectFreevarsVisitor<'a, 'b> {
fn visit_item(&mut self, _: &ast::Item) {
// ignore_item
}
fn visit_expr(&mut self, expr: &ast::Expr) {
match expr.node {
ast::ExprProc(..) => {
self.cx.capture_mode_map.insert(expr.id, ast::CaptureByValue);
self.depth += 1;
visit::walk_expr(self, expr);
self.depth -= 1;
}
ast::ExprFnBlock(_, _, _) => {
// NOTE(stage0): After snapshot, change to:
//
//self.cx.capture_mode_map.insert(expr.id, capture_clause);
self.cx.capture_mode_map.insert(expr.id, ast::CaptureByRef);
self.depth += 1;
visit::walk_expr(self, expr);
self.depth -= 1;
}
ast::ExprUnboxedFn(capture_clause, _, _, _) => {
self.cx.capture_mode_map.insert(expr.id, capture_clause);
self.depth += 1;
visit::walk_expr(self, expr);
self.depth -= 1;
}
ast::ExprPath(..) => {
let def = *self.cx.def_map.borrow().find(&expr.id)
.expect("path not found");
let dnum = def.def_id().node;
if self.seen.contains(&dnum) {
return;
}
let def = match def {
def::DefUpvar(_, _, depth, _, _) => {
if depth < self.depth {
return;
}
let mut def = def;
for _ in range(0, depth - self.depth) {
match def {
def::DefUpvar(_, inner, _, _, _) => { def = *inner; }
_ => unreachable!()
}
}
def
},
_ => return
};
self.cx.freevars.find_or_insert(self.node_id, vec![]).push(ty::Freevar {
def: def,
span: expr.span,
});
self.seen.insert(dnum);
}
_ => visit::walk_expr(self, expr)
}
}
}
struct AnnotateFreevarsVisitor<'a> {
def_map: &'a resolve::DefMap,
freevars: ty::FreevarMap,
capture_mode_map: ty::CaptureModeMap,
}
impl<'a, 'v> Visitor<'v> for AnnotateFreevarsVisitor<'a> {
fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
blk: &'v ast::Block, s: Span, nid: ast::NodeId) {
CollectFreevarsVisitor {
node_id: nid,
seen: NodeSet::new(),
cx: self,
depth: 0
}.visit_block(blk);
visit::walk_fn(self, fk, fd, blk, s);
}
}
// Build a map from every function and for-each body to a set of the
// freevars contained in it. The implementation is not particularly
// efficient as it fully recomputes the free variables at every
// node of interest rather than building up the free variables in
// one pass. This could be improved upon if it turns out to matter.
pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate)
-> (ty::FreevarMap, ty::CaptureModeMap) {
let mut visitor = AnnotateFreevarsVisitor {
def_map: def_map,
freevars: NodeMap::new(),
capture_mode_map: NodeMap::new(),
};
visit::walk_crate(&mut visitor, krate);
(visitor.freevars, visitor.capture_mode_map)
}

View File

@ -103,7 +103,6 @@
*/
use middle::def::*;
use middle::freevars;
use middle::mem_categorization::Typer;
use middle::pat_util;
use middle::ty;

View File

@ -63,7 +63,6 @@
#![allow(non_camel_case_types)]
use middle::def;
use middle::freevars;
use middle::ty;
use middle::typeck;
use util::nodemap::{DefIdMap, NodeMap};

View File

@ -19,7 +19,8 @@ use middle::lang_items::LanguageItems;
use middle::pat_util::pat_bindings;
use middle::subst::{ParamSpace, FnSpace, TypeSpace};
use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory};
use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
use middle::ty::{CaptureModeMap, Freevar, FreevarMap};
use util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap};
use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
use syntax::ast::{DeclItem, DefId, Expr, ExprAgain, ExprBreak, ExprField};
@ -279,11 +280,7 @@ enum RibKind {
// We passed through a closure scope at the given node ID.
// Translate upvars as appropriate.
ClosureRibKind(NodeId /* func id */),
// We passed through a proc or unboxed closure scope at the given node ID.
// Translate upvars as appropriate.
ProcRibKind(NodeId /* func id */, NodeId /* body id */),
ClosureRibKind(NodeId /* func id */, NodeId /* body id if proc or unboxed */),
// We passed through an impl or trait and are now in one of its
// methods. Allow references to ty params that impl or trait
@ -895,6 +892,9 @@ struct Resolver<'a> {
primitive_type_table: PrimitiveTypeTable,
def_map: DefMap,
freevars: RefCell<FreevarMap>,
freevars_seen: RefCell<NodeMap<NodeSet>>,
capture_mode_map: RefCell<CaptureModeMap>,
export_map2: ExportMap2,
trait_map: TraitMap,
external_exports: ExternalExports,
@ -1000,6 +1000,9 @@ impl<'a> Resolver<'a> {
primitive_type_table: PrimitiveTypeTable::new(),
def_map: RefCell::new(NodeMap::new()),
freevars: RefCell::new(NodeMap::new()),
freevars_seen: RefCell::new(NodeMap::new()),
capture_mode_map: RefCell::new(NodeMap::new()),
export_map2: RefCell::new(NodeMap::new()),
trait_map: NodeMap::new(),
used_imports: HashSet::new(),
@ -3831,75 +3834,56 @@ impl<'a> Resolver<'a> {
self.current_module = orig_module;
}
/// Wraps the given definition in the appropriate number of `def_upvar`
/// Wraps the given definition in the appropriate number of `DefUpvar`
/// wrappers.
fn upvarify(&self,
ribs: &[Rib],
rib_index: uint,
def_like: DefLike,
span: Span)
-> Option<DefLike> {
let mut def;
let is_ty_param;
match def_like {
DlDef(d @ DefLocal(..)) | DlDef(d @ DefUpvar(..)) => {
def = d;
is_ty_param = false;
DlDef(d @ DefUpvar(..)) => {
self.session.span_bug(span,
format!("unexpected {} in bindings", d).as_slice())
}
DlDef(d @ DefTyParam(..)) |
DlDef(d @ DefSelfTy(..)) => {
def = d;
is_ty_param = true;
}
_ => {
return Some(def_like);
}
}
let mut rib_index = rib_index + 1;
while rib_index < ribs.len() {
match ribs[rib_index].kind {
DlDef(d @ DefLocal(_)) => {
let node_id = d.def_id().node;
let mut def = d;
let mut depth = 0;
let mut last_proc_body_id = ast::DUMMY_NODE_ID;
for rib in ribs.iter() {
match rib.kind {
NormalRibKind => {
// Nothing to do. Continue.
}
ClosureRibKind(function_id) => {
if !is_ty_param {
let (depth, block_id) = match def {
DefUpvar(_, _, depth, _, block_id) => (depth + 1, block_id),
_ => (0, ast::DUMMY_NODE_ID)
};
def = DefUpvar(def.def_id().node, box(GC) def, depth, function_id, block_id);
ClosureRibKind(function_id, maybe_proc_body) => {
let prev_def = def;
if maybe_proc_body != ast::DUMMY_NODE_ID {
last_proc_body_id = maybe_proc_body;
}
def = DefUpvar(node_id, box(GC) def,
depth, function_id, last_proc_body_id);
depth += 1;
let mut seen = self.freevars_seen.borrow_mut();
let seen = seen.find_or_insert(function_id, NodeSet::new());
if seen.contains(&node_id) {
continue;
}
ProcRibKind(function_id, block_id) => {
if !is_ty_param {
let depth = match def {
DefUpvar(_, _, depth, _, _) => depth + 1,
_ => 0
};
def = DefUpvar(def.def_id().node, box(GC) def, depth, function_id, block_id);
}
self.freevars.borrow_mut().find_or_insert(function_id, vec![])
.push(Freevar { def: prev_def, span: span });
seen.insert(node_id);
}
MethodRibKind(item_id, _) => {
// If the def is a ty param, and came from the parent
// item, it's ok
match def {
DefTyParam(_, did, _) if {
self.def_map.borrow().find(&did.node).map(|x| *x)
self.def_map.borrow().find_copy(&did.node)
== Some(DefTyParamBinder(item_id))
} => {
// ok
}
DefSelfTy(did) if {
did == item_id
} => {
// ok
}
} => {} // ok
DefSelfTy(did) if did == item_id => {} // ok
_ => {
if !is_ty_param {
// This was an attempt to access an upvar inside a
// named function item. This is not allowed, so we
// report an error.
@ -3908,22 +3892,12 @@ impl<'a> Resolver<'a> {
span,
"can't capture dynamic environment in a fn item; \
use the || { ... } closure form instead");
} else {
// This was an attempt to use a type parameter outside
// its scope.
self.resolve_error(span,
"can't use type parameters from \
outer function; try using a local \
type parameter instead");
}
return None;
}
}
}
ItemRibKind => {
if !is_ty_param {
// This was an attempt to access an upvar inside a
// named function item. This is not allowed, so we
// report an error.
@ -3932,7 +3906,38 @@ impl<'a> Resolver<'a> {
span,
"can't capture dynamic environment in a fn item; \
use the || { ... } closure form instead");
} else {
return None;
}
ConstantItemRibKind => {
// Still doesn't deal with upvars
self.resolve_error(span,
"attempt to use a non-constant \
value in a constant");
}
}
}
Some(DlDef(def))
}
DlDef(def @ DefTyParam(..)) |
DlDef(def @ DefSelfTy(..)) => {
for rib in ribs.iter() {
match rib.kind {
NormalRibKind | ClosureRibKind(..) => {
// Nothing to do. Continue.
}
MethodRibKind(item_id, _) => {
// If the def is a ty param, and came from the parent
// item, it's ok
match def {
DefTyParam(_, did, _) if {
self.def_map.borrow().find_copy(&did.node)
== Some(DefTyParamBinder(item_id))
} => {} // ok
DefSelfTy(did) if did == item_id => {} // ok
_ => {
// This was an attempt to use a type parameter outside
// its scope.
@ -3940,30 +3945,35 @@ impl<'a> Resolver<'a> {
"can't use type parameters from \
outer function; try using a local \
type parameter instead");
return None;
}
}
}
ItemRibKind => {
// This was an attempt to use a type parameter outside
// its scope.
self.resolve_error(span,
"can't use type parameters from \
outer function; try using a local \
type parameter instead");
return None;
}
ConstantItemRibKind => {
if is_ty_param {
// see #9186
self.resolve_error(span,
"cannot use an outer type \
parameter in this context");
} else {
// Still doesn't deal with upvars
self.resolve_error(span,
"attempt to use a non-constant \
value in a constant");
}
}
}
rib_index += 1;
}
return Some(DlDef(def));
Some(DlDef(def))
}
_ => Some(def_like)
}
}
fn search_ribs(&self,
@ -3971,16 +3981,12 @@ impl<'a> Resolver<'a> {
name: Name,
span: Span)
-> Option<DefLike> {
// FIXME #4950: This should not use a while loop.
// FIXME #4950: Try caching?
let mut i = ribs.len();
while i != 0 {
i -= 1;
let binding_opt = ribs[i].bindings.borrow().find_copy(&name);
match binding_opt {
for (i, rib) in ribs.iter().enumerate().rev() {
match rib.bindings.borrow().find_copy(&name) {
Some(def_like) => {
return self.upvarify(ribs, i, def_like, span);
return self.upvarify(ribs.slice_from(i + 1), def_like, span);
}
None => {
// Continue.
@ -3988,7 +3994,7 @@ impl<'a> Resolver<'a> {
}
}
return None;
None
}
fn resolve_crate(&mut self, krate: &ast::Crate) {
@ -5773,13 +5779,23 @@ impl<'a> Resolver<'a> {
}
ExprFnBlock(_, ref fn_decl, ref block) => {
self.resolve_function(ClosureRibKind(expr.id),
// NOTE(stage0): After snapshot, change to:
//
//self.capture_mode_map.borrow_mut().insert(expr.id, capture_clause);
self.capture_mode_map.borrow_mut().insert(expr.id, ast::CaptureByRef);
self.resolve_function(ClosureRibKind(expr.id, ast::DUMMY_NODE_ID),
Some(&**fn_decl), NoTypeParameters,
&**block);
}
ExprProc(ref fn_decl, ref block) |
ExprUnboxedFn(_, _, ref fn_decl, ref block) => {
self.resolve_function(ProcRibKind(expr.id, block.id),
ExprProc(ref fn_decl, ref block) => {
self.capture_mode_map.borrow_mut().insert(expr.id, ast::CaptureByValue);
self.resolve_function(ClosureRibKind(expr.id, block.id),
Some(&**fn_decl), NoTypeParameters,
&**block);
}
ExprUnboxedFn(capture_clause, _, ref fn_decl, ref block) => {
self.capture_mode_map.borrow_mut().insert(expr.id, capture_clause);
self.resolve_function(ClosureRibKind(expr.id, block.id),
Some(&**fn_decl), NoTypeParameters,
&**block);
}
@ -6210,6 +6226,8 @@ impl<'a> Resolver<'a> {
pub struct CrateMap {
pub def_map: DefMap,
pub freevars: RefCell<FreevarMap>,
pub capture_mode_map: RefCell<CaptureModeMap>,
pub exp_map2: ExportMap2,
pub trait_map: TraitMap,
pub external_exports: ExternalExports,
@ -6223,13 +6241,13 @@ pub fn resolve_crate(session: &Session,
-> CrateMap {
let mut resolver = Resolver::new(session, krate.span);
resolver.resolve(krate);
let Resolver { def_map, export_map2, trait_map, last_private,
external_exports, .. } = resolver;
CrateMap {
def_map: def_map,
exp_map2: export_map2,
trait_map: trait_map,
external_exports: external_exports,
last_private_map: last_private,
def_map: resolver.def_map,
freevars: resolver.freevars,
capture_mode_map: resolver.capture_mode_map,
exp_map2: resolver.export_map2,
trait_map: resolver.trait_map,
external_exports: resolver.external_exports,
last_private_map: resolver.last_private,
}
}

View File

@ -14,7 +14,6 @@ use back::link::mangle_internal_name_by_path_and_seq;
use driver::config::FullDebugInfo;
use llvm::ValueRef;
use middle::def;
use middle::freevars;
use middle::mem_categorization::Typer;
use middle::trans::adt;
use middle::trans::base::*;

View File

@ -17,7 +17,6 @@ use llvm;
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef};
use llvm::{True, False, Bool};
use middle::def;
use middle::freevars;
use middle::lang_items::LangItem;
use middle::mem_categorization as mc;
use middle::subst;

View File

@ -1461,8 +1461,8 @@ pub fn mk_ctxt<'tcx>(s: Session,
dm: resolve::DefMap,
named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map<'tcx>,
freevars: FreevarMap,
capture_modes: CaptureModeMap,
freevars: RefCell<FreevarMap>,
capture_modes: RefCell<CaptureModeMap>,
region_maps: middle::region::RegionMaps,
lang_items: middle::lang_items::LanguageItems,
stability: stability::Index) -> ctxt<'tcx> {
@ -1483,7 +1483,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
object_cast_map: RefCell::new(NodeMap::new()),
map: map,
intrinsic_defs: RefCell::new(DefIdMap::new()),
freevars: RefCell::new(freevars),
freevars: freevars,
tcache: RefCell::new(DefIdMap::new()),
rcache: RefCell::new(HashMap::new()),
short_names_cache: RefCell::new(HashMap::new()),
@ -1520,7 +1520,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
node_lint_levels: RefCell::new(HashMap::new()),
transmute_restrictions: RefCell::new(Vec::new()),
stability: RefCell::new(stability),
capture_modes: RefCell::new(capture_modes),
capture_modes: capture_modes,
associated_types: RefCell::new(DefIdMap::new()),
trait_associated_types: RefCell::new(DefIdMap::new()),
}
@ -4755,7 +4755,7 @@ pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId)
-> Vec<UnboxedClosureUpvar> {
if closure_id.krate == ast::LOCAL_CRATE {
match tcx.freevars.borrow().find(&closure_id.node) {
None => tcx.sess.bug("no freevars for unboxed closure?!"),
None => vec![],
Some(ref freevars) => {
freevars.iter().map(|freevar| {
let freevar_def_id = freevar.def.def_id();
@ -5701,7 +5701,7 @@ pub type CaptureModeMap = NodeMap<ast::CaptureClause>;
pub fn with_freevars<T>(tcx: &ty::ctxt, fid: ast::NodeId, f: |&[Freevar]| -> T) -> T {
match tcx.freevars.borrow().find(&fid) {
None => fail!("with_freevars: {} has no freevars", fid),
None => f(&[]),
Some(d) => f(d.as_slice())
}
}

View File

@ -79,7 +79,6 @@ type parameter).
use middle::const_eval;
use middle::def;
use middle::freevars;
use middle::lang_items::IteratorItem;
use middle::mem_categorization::McResult;
use middle::mem_categorization;

View File

@ -119,7 +119,6 @@ and report an error, and it just seems like more mess in the end.)
*/
use middle::def;
use middle::freevars;
use middle::mem_categorization as mc;
use middle::ty::{ReScope};
use middle::ty;

View File

@ -22,7 +22,6 @@ use driver::diagnostic;
use driver::diagnostic::Emitter;
use driver::driver;
use driver::session;
use middle::freevars;
use middle::lang_items;
use middle::region;
use middle::resolve;
@ -125,10 +124,8 @@ fn test_env(_test_name: &str,
// run just enough stuff to build a tcx:
let lang_items = lang_items::collect_language_items(krate, &sess);
let resolve::CrateMap { def_map: def_map, .. } =
let resolve::CrateMap { def_map, freevars, capture_mode_map, .. } =
resolve::resolve_crate(&sess, &lang_items, krate);
let (freevars_map, captures_map) = freevars::annotate_freevars(&def_map,
krate);
let named_region_map = resolve_lifetime::krate(&sess, krate);
let region_map = region::resolve_crate(&sess, krate);
let stability_index = stability::Index::build(krate);
@ -138,8 +135,8 @@ fn test_env(_test_name: &str,
def_map,
named_region_map,
ast_map,
freevars_map,
captures_map,
freevars,
capture_mode_map,
region_map,
lang_items,
stability_index);