parent
0c97fcbf66
commit
8f8ebb550c
6 changed files with 250 additions and 6 deletions
|
@ -5,7 +5,8 @@ import metadata::{creader, cstore};
|
|||
import syntax::parse::{parser};
|
||||
import syntax::{ast, codemap};
|
||||
import front::attr;
|
||||
import middle::{trans, resolve, freevars, kind, ty, typeck, fn_usage};
|
||||
import middle::{trans, resolve, freevars, kind, ty, typeck, fn_usage,
|
||||
last_use};
|
||||
import syntax::print::{pp, pprust};
|
||||
import util::{ppaux, filesearch};
|
||||
import back::link;
|
||||
|
@ -138,6 +139,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
|
|||
bind freevars::annotate_freevars(def_map, crate));
|
||||
let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars);
|
||||
time(time_passes, "typechecking", bind typeck::check_crate(ty_cx, crate));
|
||||
let last_uses = time(time_passes, "last use finding",
|
||||
bind last_use::find_last_uses(crate, def_map, ty_cx));
|
||||
time(time_passes, "function usage",
|
||||
bind fn_usage::check_crate_fn_usage(ty_cx, crate));
|
||||
time(time_passes, "alt checking",
|
||||
|
@ -150,7 +153,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
|
|||
let copy_map =
|
||||
time(time_passes, "alias checking",
|
||||
bind middle::alias::check_crate(ty_cx, crate));
|
||||
time(time_passes, "kind checking", bind kind::check_crate(ty_cx, crate));
|
||||
time(time_passes, "kind checking",
|
||||
bind kind::check_crate(ty_cx, last_uses, crate));
|
||||
time(time_passes, "const checking",
|
||||
bind middle::check_const::check_crate(ty_cx, crate));
|
||||
if sess.get_opts().no_trans { ret; }
|
||||
|
|
|
@ -15,11 +15,14 @@ type rval_map = std::map::hashmap<node_id, ()>;
|
|||
|
||||
type ctx = {tcx: ty::ctxt,
|
||||
rval_map: rval_map,
|
||||
last_uses: last_use::last_uses,
|
||||
mutable ret_by_ref: bool};
|
||||
|
||||
fn check_crate(tcx: ty::ctxt, crate: @crate) -> rval_map {
|
||||
fn check_crate(tcx: ty::ctxt, last_uses: last_use::last_uses,
|
||||
crate: @crate) -> rval_map {
|
||||
let ctx = {tcx: tcx,
|
||||
rval_map: std::map::new_int_hash(),
|
||||
last_uses: last_uses,
|
||||
mutable ret_by_ref: false};
|
||||
let visit = visit::mk_vt(@{
|
||||
visit_expr: check_expr,
|
||||
|
@ -118,7 +121,7 @@ fn maybe_copy(cx: ctx, ex: @expr) {
|
|||
}
|
||||
|
||||
fn check_copy_ex(cx: ctx, ex: @expr, _warn: bool) {
|
||||
if ty::expr_is_lval(cx.tcx, ex) {
|
||||
if ty::expr_is_lval(cx.tcx, ex) && !cx.last_uses.contains_key(ex.id) {
|
||||
let ty = ty::expr_ty(cx.tcx, ex);
|
||||
check_copy(cx, ty, ex.span);
|
||||
// FIXME turn this on again once vector types are no longer unique.
|
||||
|
|
219
src/comp/middle/last_use.rs
Normal file
219
src/comp/middle/last_use.rs
Normal file
|
@ -0,0 +1,219 @@
|
|||
import syntax::{visit, ast_util};
|
||||
import syntax::ast::*;
|
||||
import std::list::{list, nil, cons, tail};
|
||||
import std::{vec, list, option};
|
||||
|
||||
// Marks expr_paths that are last uses.
|
||||
type last_uses = std::map::hashmap<node_id, ()>;
|
||||
|
||||
tag seen { unset; seen(node_id); }
|
||||
tag block_type { func; loop; }
|
||||
|
||||
type set = [{def: node_id, exprs: list<node_id>}];
|
||||
type bl = @{type: block_type, mutable second: bool, mutable exits: [set]};
|
||||
|
||||
type ctx = {last_uses: std::map::hashmap<node_id, bool>,
|
||||
def_map: resolve::def_map,
|
||||
tcx: ty::ctxt,
|
||||
// The current set of local last uses
|
||||
mutable current: set,
|
||||
mutable blocks: list<bl>};
|
||||
|
||||
fn find_last_uses(c: @crate, def_map: resolve::def_map, tcx: ty::ctxt)
|
||||
-> last_uses {
|
||||
let v = visit::mk_vt(@{visit_expr: visit_expr,
|
||||
visit_fn: visit_fn
|
||||
with *visit::default_visitor()});
|
||||
let cx = {last_uses: std::map::new_int_hash(),
|
||||
def_map: def_map,
|
||||
tcx: tcx,
|
||||
mutable current: [],
|
||||
mutable blocks: nil};
|
||||
visit::visit_crate(*c, cx, v);
|
||||
let mini_table = std::map::new_int_hash();
|
||||
cx.last_uses.items {|key, val| if val { mini_table.insert(key, ()); }}
|
||||
ret mini_table;
|
||||
}
|
||||
|
||||
fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||
alt ex.node {
|
||||
expr_ret(oexpr) {
|
||||
visit::visit_expr_opt(oexpr, cx, v);
|
||||
if !add_block_exit(cx, func) { leave_fn(cx); }
|
||||
}
|
||||
expr_fail(oexpr) {
|
||||
visit::visit_expr_opt(oexpr, cx, v);
|
||||
leave_fn(cx);
|
||||
}
|
||||
expr_break. { add_block_exit(cx, loop); }
|
||||
expr_while(_, _) | expr_do_while(_, _) {
|
||||
visit_block(loop, cx) {|| visit::visit_expr(ex, cx, v);}
|
||||
}
|
||||
expr_for(_, coll, blk) {
|
||||
v.visit_expr(coll, cx, v);
|
||||
visit_block(loop, cx) {|| visit::visit_block(blk, cx, v);}
|
||||
}
|
||||
expr_ternary(_, _, _) {
|
||||
v.visit_expr(ast_util::ternary_to_if(ex), cx, v);
|
||||
}
|
||||
expr_alt(input, arms) {
|
||||
v.visit_expr(input, cx, v);
|
||||
let before = cx.current, sets = [];
|
||||
for arm in arms {
|
||||
cx.current = before;
|
||||
v.visit_arm(arm, cx, v);
|
||||
sets += [cx.current];
|
||||
}
|
||||
cx.current = join_branches(sets);
|
||||
}
|
||||
expr_if(cond, then, els) {
|
||||
v.visit_expr(cond, cx, v);
|
||||
let cur = cx.current;
|
||||
visit::visit_block(then, cx, v);
|
||||
cx.current <-> cur;
|
||||
visit::visit_expr_opt(els, cx, v);
|
||||
cx.current = join_branches([cur, cx.current]);
|
||||
}
|
||||
expr_path(_) {
|
||||
alt clear_if_path(cx, ex, v, false) {
|
||||
option::some(my_def) {
|
||||
cx.current += [{def: my_def, exprs: cons(ex.id, @nil)}];
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
expr_swap(lhs, rhs) {
|
||||
clear_if_path(cx, lhs, v, false);
|
||||
clear_if_path(cx, rhs, v, false);
|
||||
}
|
||||
expr_move(dest, src) | expr_assign(dest, src) {
|
||||
v.visit_expr(src, cx, v);
|
||||
clear_if_path(cx, dest, v, true);
|
||||
}
|
||||
expr_assign_op(_, dest, src) {
|
||||
v.visit_expr(src, cx, v);
|
||||
v.visit_expr(dest, cx, v);
|
||||
clear_if_path(cx, dest, v, true);
|
||||
}
|
||||
expr_call(f, args, _) {
|
||||
v.visit_expr(f, cx, v);
|
||||
let i = 0u;
|
||||
for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) {
|
||||
alt arg_t.mode {
|
||||
by_mut_ref. { clear_if_path(cx, args[i], v, false); }
|
||||
_ { v.visit_expr(args[i], cx, v); }
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
_ { visit::visit_expr(ex, cx, v); }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn(f: _fn, tps: [ty_param], sp: syntax::codemap::span,
|
||||
ident: fn_ident, id: node_id, cx: ctx, v: visit::vt<ctx>) {
|
||||
if f.proto == proto_block {
|
||||
visit_block(func, cx, {||
|
||||
visit::visit_fn(f, tps, sp, ident, id, cx, v);
|
||||
});
|
||||
} else {
|
||||
let old = nil;
|
||||
cx.blocks <-> old;
|
||||
visit::visit_fn(f, tps, sp, ident, id, cx, v);
|
||||
cx.blocks <-> old;
|
||||
leave_fn(cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_block(tp: block_type, cx: ctx, visit: block()) {
|
||||
let local = @{type: tp, mutable second: false, mutable exits: []};
|
||||
cx.blocks = cons(local, @cx.blocks);
|
||||
visit();
|
||||
local.second = true;
|
||||
visit();
|
||||
cx.blocks = tail(cx.blocks);
|
||||
cx.current = join_branches(local.exits);
|
||||
}
|
||||
|
||||
fn add_block_exit(cx: ctx, tp: block_type) -> bool {
|
||||
let cur = cx.blocks;
|
||||
while cur != nil {
|
||||
alt cur {
|
||||
cons(b, tail) {
|
||||
if (b.type == tp) {
|
||||
if !b.second { b.exits += [cx.current]; }
|
||||
ret true;
|
||||
}
|
||||
cur = *tail;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn join_branches(branches: [set]) -> set {
|
||||
let found: set = [], i = 0u, l = vec::len(branches);
|
||||
for set in branches {
|
||||
i += 1u;
|
||||
for {def, exprs} in set {
|
||||
if !vec::any({|v| v.def == def}, found) {
|
||||
let j = i, ne = exprs;
|
||||
while j < l {
|
||||
for {def: d2, exprs} in branches[j] {
|
||||
if d2 == def {
|
||||
list::iter(exprs) {|e|
|
||||
if !list::has(ne, e) { ne = cons(e, @ne); }
|
||||
}
|
||||
}
|
||||
}
|
||||
j += 1u;
|
||||
}
|
||||
found += [{def: def, exprs: ne}];
|
||||
}
|
||||
}
|
||||
}
|
||||
ret found;
|
||||
}
|
||||
|
||||
fn leave_fn(cx: ctx) {
|
||||
for {def, exprs} in cx.current {
|
||||
list::iter(exprs) {|ex_id|
|
||||
if !cx.last_uses.contains_key(ex_id) {
|
||||
cx.last_uses.insert(ex_id, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_in_current(cx: ctx, my_def: node_id, to: bool) {
|
||||
for {def, exprs} in cx.current {
|
||||
if def == my_def {
|
||||
list::iter(exprs) {|expr|
|
||||
if !to || !cx.last_uses.contains_key(expr) {
|
||||
cx.last_uses.insert(expr, to);
|
||||
}
|
||||
}
|
||||
cx.current = vec::filter({|x| x.def != my_def},
|
||||
copy cx.current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_if_path(cx: ctx, ex: @expr, v: visit::vt<ctx>, to: bool)
|
||||
-> option::t<node_id> {
|
||||
alt ex.node {
|
||||
expr_path(_) {
|
||||
alt cx.def_map.get(ex.id) {
|
||||
def_local(def_id, let_copy.) | def_arg(def_id, by_copy.) |
|
||||
def_arg(def_id, by_move.) {
|
||||
clear_in_current(cx, def_id.node, to);
|
||||
ret option::some(def_id.node);
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
_ { v.visit_expr(ex, cx, v); }
|
||||
}
|
||||
ret option::none;
|
||||
}
|
|
@ -30,6 +30,7 @@ mod middle {
|
|||
mod check_const;
|
||||
mod mut;
|
||||
mod alias;
|
||||
mod last_use;
|
||||
mod kind;
|
||||
mod freevars;
|
||||
mod shape;
|
||||
|
|
|
@ -134,6 +134,23 @@ fn append<T>(l: list<T>, m: list<T>) -> list<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function: iter
|
||||
|
||||
Iterate over a list
|
||||
*/
|
||||
fn iter<copy T>(l: list<T>, f: block(T)) {
|
||||
let cur = l;
|
||||
while cur != nil {
|
||||
alt cur {
|
||||
cons(hd, tl) {
|
||||
f(hd);
|
||||
cur = *tl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -703,8 +703,8 @@ Iterates over vector `v` and, for each element, calls function `f` with the
|
|||
element's value and index.
|
||||
*/
|
||||
fn iter2<T>(v: [const T], f: block(uint, T)) {
|
||||
let i = 0u;
|
||||
for x in v { f(i, x); i += 1u; }
|
||||
let i = 0u, l = len(v);
|
||||
while i < l { f(i, v[i]); i += 1u; }
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Reference in a new issue