Skip to content
83 changes: 49 additions & 34 deletions src/librustc/middle/borrowck/check_loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ use syntax::ast::{m_mutbl, m_imm, m_const};
use syntax::ast;
use syntax::ast_util;
use syntax::codemap::span;
use syntax::oldvisit;
use syntax::visit;
use syntax::visit::Visitor;
use util::ppaux::Repr;

#[deriving(Clone)]
Expand All @@ -39,6 +40,27 @@ struct CheckLoanCtxt<'self> {
reported: @mut HashSet<ast::NodeId>,
}

struct CheckLoanVisitor;

impl<'self> Visitor<CheckLoanCtxt<'self>> for CheckLoanVisitor {
fn visit_expr<'a>(&mut self, ex:@ast::expr, e:CheckLoanCtxt<'a>) {
check_loans_in_expr(self, ex, e);
}
fn visit_local(&mut self, l:@ast::Local, e:CheckLoanCtxt) {
check_loans_in_local(self, l, e);
}
fn visit_block(&mut self, b:&ast::Block, e:CheckLoanCtxt) {
check_loans_in_block(self, b, e);
}
fn visit_pat(&mut self, p:@ast::pat, e:CheckLoanCtxt) {
check_loans_in_pat(self, p, e);
}
fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
b:&ast::Block, s:span, n:ast::NodeId, e:CheckLoanCtxt) {
check_loans_in_fn(self, fk, fd, b, s, n, e);
}
}

pub fn check_loans(bccx: @BorrowckCtxt,
dfcx_loans: &LoanDataFlow,
move_data: move_data::FlowedMoveData,
Expand All @@ -54,15 +76,8 @@ pub fn check_loans(bccx: @BorrowckCtxt,
reported: @mut HashSet::new(),
};

let vt = oldvisit::mk_vt(@oldvisit::Visitor {
visit_expr: check_loans_in_expr,
visit_local: check_loans_in_local,
visit_block: check_loans_in_block,
visit_pat: check_loans_in_pat,
visit_fn: check_loans_in_fn,
.. *oldvisit::default_visitor()
});
(vt.visit_block)(body, (clcx, vt));
let mut vt = CheckLoanVisitor;
vt.visit_block(body, clcx);
}

enum MoveError {
Expand Down Expand Up @@ -626,27 +641,27 @@ impl<'self> CheckLoanCtxt<'self> {
}
}

fn check_loans_in_fn<'a>(fk: &oldvisit::fn_kind,
fn check_loans_in_fn<'a>(visitor: &mut CheckLoanVisitor,
fk: &visit::fn_kind,
decl: &ast::fn_decl,
body: &ast::Block,
sp: span,
id: ast::NodeId,
(this, visitor): (CheckLoanCtxt<'a>,
oldvisit::vt<CheckLoanCtxt<'a>>)) {
this: CheckLoanCtxt<'a>) {
match *fk {
oldvisit::fk_item_fn(*) |
oldvisit::fk_method(*) => {
visit::fk_item_fn(*) |
visit::fk_method(*) => {
// Don't process nested items.
return;
}

oldvisit::fk_anon(*) |
oldvisit::fk_fn_block(*) => {
visit::fk_anon(*) |
visit::fk_fn_block(*) => {
check_captured_variables(this, id, sp);
}
}

oldvisit::visit_fn(fk, decl, body, sp, id, (this, visitor));
visit::walk_fn(visitor, fk, decl, body, sp, id, this);

fn check_captured_variables(this: CheckLoanCtxt,
closure_id: ast::NodeId,
Expand Down Expand Up @@ -689,16 +704,16 @@ fn check_loans_in_fn<'a>(fk: &oldvisit::fn_kind,
}
}

fn check_loans_in_local<'a>(local: @ast::Local,
(this, vt): (CheckLoanCtxt<'a>,
oldvisit::vt<CheckLoanCtxt<'a>>)) {
oldvisit::visit_local(local, (this, vt));
fn check_loans_in_local<'a>(vt: &mut CheckLoanVisitor,
local: @ast::Local,
this: CheckLoanCtxt<'a>) {
visit::walk_local(vt, local, this);
}

fn check_loans_in_expr<'a>(expr: @ast::expr,
(this, vt): (CheckLoanCtxt<'a>,
oldvisit::vt<CheckLoanCtxt<'a>>)) {
oldvisit::visit_expr(expr, (this, vt));
fn check_loans_in_expr<'a>(vt: &mut CheckLoanVisitor,
expr: @ast::expr,
this: CheckLoanCtxt<'a>) {
visit::walk_expr(vt, expr, this);

debug!("check_loans_in_expr(expr=%s)",
expr.repr(this.tcx()));
Expand Down Expand Up @@ -749,19 +764,19 @@ fn check_loans_in_expr<'a>(expr: @ast::expr,
}
}

fn check_loans_in_pat<'a>(pat: @ast::pat,
(this, vt): (CheckLoanCtxt<'a>,
oldvisit::vt<CheckLoanCtxt<'a>>))
fn check_loans_in_pat<'a>(vt: &mut CheckLoanVisitor,
pat: @ast::pat,
this: CheckLoanCtxt<'a>)
{
this.check_for_conflicting_loans(pat.id);
this.check_move_out_from_id(pat.id, pat.span);
oldvisit::visit_pat(pat, (this, vt));
visit::walk_pat(vt, pat, this);
}

fn check_loans_in_block<'a>(blk: &ast::Block,
(this, vt): (CheckLoanCtxt<'a>,
oldvisit::vt<CheckLoanCtxt<'a>>))
fn check_loans_in_block<'a>(vt: &mut CheckLoanVisitor,
blk: &ast::Block,
this: CheckLoanCtxt<'a>)
{
oldvisit::visit_block(blk, (this, vt));
visit::walk_block(vt, blk, this);
this.check_for_conflicting_loans(blk.id);
}
23 changes: 14 additions & 9 deletions src/librustc/middle/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ use syntax::ast::{Crate, NodeId, item, item_fn};
use syntax::ast_map;
use syntax::attr;
use syntax::codemap::span;
use syntax::oldvisit::{default_visitor, mk_vt, vt, Visitor, visit_crate};
use syntax::oldvisit::{visit_item};
use syntax::parse::token::special_idents;
use syntax::visit;
use syntax::visit::Visitor;
use std::util;

struct EntryContext {
Expand All @@ -39,7 +39,13 @@ struct EntryContext {
non_main_fns: ~[(NodeId, span)],
}

type EntryVisitor = vt<@mut EntryContext>;
struct EntryVisitor;

impl Visitor<@mut EntryContext> for EntryVisitor {
fn visit_item(&mut self, item:@item, ctxt:@mut EntryContext) {
find_item(item, ctxt, self);
}
}

pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map) {

Expand All @@ -65,15 +71,14 @@ pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map)
non_main_fns: ~[],
};

visit_crate(crate, (ctxt, mk_vt(@Visitor {
visit_item: |item, (ctxt, visitor)| find_item(item, ctxt, visitor),
.. *default_visitor()
})));
let mut v = EntryVisitor;

visit::walk_crate(&mut v, crate, ctxt);

configure_main(ctxt);
}

fn find_item(item: @item, ctxt: @mut EntryContext, visitor: EntryVisitor) {
fn find_item(item: @item, ctxt: @mut EntryContext, visitor: &mut EntryVisitor) {
match item.node {
item_fn(*) => {
if item.ident == special_idents::main {
Expand Down Expand Up @@ -120,7 +125,7 @@ fn find_item(item: @item, ctxt: @mut EntryContext, visitor: EntryVisitor) {
_ => ()
}

visit_item(item, (ctxt, visitor));
visit::walk_item(visitor, item, ctxt);
}

fn configure_main(ctxt: @mut EntryContext) {
Expand Down
98 changes: 61 additions & 37 deletions src/librustc/middle/freevars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use middle::ty;

use std::hashmap::HashMap;
use syntax::codemap::span;
use syntax::{ast, ast_util, oldvisit};
use syntax::{ast, ast_util};
use syntax::visit;
use syntax::visit::Visitor;
use syntax::ast::{item};

// A vector of defs representing the free variables referred to in a function.
// (The def_upvar will already have been stripped).
Expand All @@ -29,27 +32,27 @@ pub struct freevar_entry {
pub type freevar_info = @~[@freevar_entry];
pub type freevar_map = @mut HashMap<ast::NodeId, freevar_info>;

// Searches through part of the AST for all references to locals or
// upvars in this frame and returns the list of definition IDs thus found.
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block)
-> freevar_info {
let seen = @mut HashMap::new();
let refs = @mut ~[];
struct CollectFreevarsVisitor {
seen: @mut HashMap<ast::NodeId, ()>,
refs: @mut ~[@freevar_entry],
def_map: resolve::DefMap,
}

impl Visitor<int> for CollectFreevarsVisitor {

fn ignore_item(_i: @ast::item, (_depth, _v): (int, oldvisit::vt<int>)) { }
fn visit_item(&mut self, _:@item, _:int) {
// ignore_item
}

fn visit_expr(&mut self, expr:@ast::expr, depth:int) {

let walk_expr: @fn(expr: @ast::expr, (int, oldvisit::vt<int>)) =
|expr, (depth, v)| {
match expr.node {
ast::expr_fn_block(*) => {
oldvisit::visit_expr(expr, (depth + 1, v))
visit::walk_expr(self, expr, depth + 1)
}
ast::expr_path(*) | ast::expr_self => {
let mut i = 0;
match def_map.find(&expr.id) {
match self.def_map.find(&expr.id) {
None => fail!("path not found"),
Some(&df) => {
let mut def = df;
Expand All @@ -62,28 +65,58 @@ fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block)
}
if i == depth { // Made it to end of loop
let dnum = ast_util::def_id_of_def(def).node;
if !seen.contains_key(&dnum) {
refs.push(@freevar_entry {
if !self.seen.contains_key(&dnum) {
self.refs.push(@freevar_entry {
def: def,
span: expr.span,
});
seen.insert(dnum, ());
self.seen.insert(dnum, ());
}
}
}
}
}
_ => oldvisit::visit_expr(expr, (depth, v))
_ => visit::walk_expr(self, expr, depth)
}
};
}

let v = oldvisit::mk_vt(@oldvisit::Visitor {visit_item: ignore_item,
visit_expr: walk_expr,
.. *oldvisit::default_visitor()});
(v.visit_block)(blk, (1, v));

}

// Searches through part of the AST for all references to locals or
// upvars in this frame and returns the list of definition IDs thus found.
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block)
-> freevar_info {
let seen = @mut HashMap::new();
let refs = @mut ~[];

let mut v = CollectFreevarsVisitor {
seen: seen,
refs: refs,
def_map: def_map,
};

v.visit_block(blk, 1);
return @(*refs).clone();
}

struct AnnotateFreevarsVisitor {
def_map: resolve::DefMap,
freevars: freevar_map,
}

impl Visitor<()> for AnnotateFreevarsVisitor {
fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
blk:&ast::Block, s:span, nid:ast::NodeId, _:()) {
let vars = collect_freevars(self.def_map, blk);
self.freevars.insert(nid, vars);
visit::walk_fn(self, fk, fd, blk, s, nid, ());
}
}

// 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
Expand All @@ -93,20 +126,11 @@ pub fn annotate_freevars(def_map: resolve::DefMap, crate: &ast::Crate) ->
freevar_map {
let freevars = @mut HashMap::new();

let walk_fn: @fn(&oldvisit::fn_kind,
&ast::fn_decl,
&ast::Block,
span,
ast::NodeId) = |_, _, blk, _, nid| {
let vars = collect_freevars(def_map, blk);
freevars.insert(nid, vars);
let mut visitor = AnnotateFreevarsVisitor {
def_map: def_map,
freevars: freevars,
};

let visitor =
oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor {
visit_fn: walk_fn,
.. *oldvisit::default_simple_visitor()});
oldvisit::visit_crate(crate, ((), visitor));
visit::walk_crate(&mut visitor, crate, ());

return freevars;
}
Expand Down
Loading