Skip to content

Commit 0688f10

Browse files
committed
---
yaml --- r: 5087 b: refs/heads/master c: 6ba4eac h: refs/heads/master i: 5085: 77028bf 5083: 473e381 5079: edee87c 5071: 91ed86e 5055: 7c936de v: v3
1 parent 0e42f9e commit 0688f10

File tree

17 files changed

+222
-256
lines changed

17 files changed

+222
-256
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 2d1dec78e7fd2fa0a569f797d147d5940e81f3d0
2+
refs/heads/master: 6ba4eacddf2a07e13f6589f04303ce7fb4c4d70c

trunk/src/comp/driver/rustc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: &istr,
155155
bind resolve::resolve_crate(sess, ast_map, crate));
156156
let freevars =
157157
time(time_passes, ~"freevar finding",
158-
bind freevars::annotate_freevars(sess, def_map, crate));
158+
bind freevars::annotate_freevars(def_map, crate));
159159
let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars);
160160
time(time_passes, ~"typechecking",
161161
bind typeck::check_crate(ty_cx, crate));
@@ -240,7 +240,7 @@ fn pretty_print_input(sess: session::session, cfg: ast::crate_cfg,
240240
let amap = middle::ast_map::map_crate(*crate);
241241
let {def_map: def_map, ext_map: ext_map} =
242242
resolve::resolve_crate(sess, amap, crate);
243-
let freevars = freevars::annotate_freevars(sess, def_map, crate);
243+
let freevars = freevars::annotate_freevars(def_map, crate);
244244
let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, amap, freevars);
245245
typeck::check_crate(ty_cx, crate);
246246
ann = {pre: ann_paren_for_expr, post: bind ann_typed_post(ty_cx, _)};

trunk/src/comp/middle/alias.rs

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -51,47 +51,23 @@ fn check_crate(tcx: ty::ctxt, crate: &@ast::crate) {
5151
let cx = @{tcx: tcx,
5252
local_map: std::map::new_int_hash(),
5353
mutable next_local: 0u};
54-
let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _),
54+
let v = @{visit_fn: visit_fn,
5555
visit_expr: bind visit_expr(cx, _, _, _),
5656
visit_decl: bind visit_decl(cx, _, _, _)
5757
with *visit::default_visitor::<scope>()};
5858
visit::visit_crate(*crate, @[], visit::mk_vt(v));
5959
tcx.sess.abort_if_errors();
6060
}
6161

62-
fn visit_fn(cx: &@ctx, f: &ast::_fn, _tp: &[ast::ty_param], _sp: &span,
63-
_name: &fn_ident, id: ast::node_id, sc: &scope, v: &vt<scope>) {
62+
fn visit_fn(f: &ast::_fn, _tp: &[ast::ty_param], _sp: &span,
63+
_name: &fn_ident, _id: ast::node_id, sc: &scope, v: &vt<scope>) {
6464
visit::visit_fn_decl(f.decl, sc, v);
65-
let scope =
66-
alt f.proto {
67-
68-
// Blocks need to obey any restrictions from the enclosing scope.
69-
ast::proto_block. {
70-
sc
71-
}
72-
73-
// Closures need to prohibit writing to any of the upvars.
74-
// This doesn't seem like a particularly clean way to do this.
75-
ast::proto_closure. {
76-
let dnums = [];
77-
for each nid in freevars::get_freevar_defs(cx.tcx, id).keys() {
78-
dnums += [nid];
79-
};
80-
// I'm not sure if there is anything sensical to put here
81-
@[@{root_var: none,
82-
local_id: cx.next_local,
83-
bindings: dnums,
84-
unsafe_ty: none,
85-
depends_on: [],
86-
mutable ok: valid}]
87-
}
88-
89-
// Non capturing functions start out fresh.
90-
_ {
91-
@[]
92-
}
93-
};
94-
65+
let scope = alt f.proto {
66+
// Blocks need to obey any restrictions from the enclosing scope.
67+
ast::proto_block. | ast::proto_closure. { sc }
68+
// Non capturing functions start out fresh.
69+
_ { @[] }
70+
};
9571
v.visit_block(f.body, scope, v);
9672
}
9773

@@ -489,7 +465,8 @@ fn ty_can_unsafely_include(cx: &ctx, needle: ty::t, haystack: ty::t,
489465

490466
fn def_is_local(d: &ast::def, objfields_count: bool) -> bool {
491467
ret alt d {
492-
ast::def_local(_) | ast::def_arg(_, _) | ast::def_binding(_) { true }
468+
ast::def_local(_) | ast::def_arg(_, _) | ast::def_binding(_) |
469+
ast::def_upvar(_, _, _) { true }
493470
ast::def_obj_field(_, _) { objfields_count }
494471
_ { false }
495472
};

trunk/src/comp/middle/freevars.rs

Lines changed: 67 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -15,127 +15,99 @@ import middle::resolve;
1515
import syntax::codemap::span;
1616

1717
export annotate_freevars;
18-
export freevar_set;
1918
export freevar_map;
20-
export get_freevar_info;
2119
export get_freevars;
22-
export get_freevar_defs;
2320
export has_freevars;
24-
export is_freevar_of;
25-
export def_lookup;
2621

27-
// Throughout the compiler, variables are generally dealt with using the
28-
// node_ids of the reference sites and not the def_id of the definition
29-
// site. Thus we store a set are the definitions along with a vec of one
30-
// "canonical" referencing node_id per free variable. The set is useful for
31-
// testing membership, the list of referencing sites is what you want for most
32-
// other things.
33-
type freevar_set = hashset<ast::node_id>;
34-
type freevar_info = {defs: freevar_set, refs: @[ast::node_id]};
22+
// A vector of defs representing the free variables referred to in a function.
23+
// (The def_upvar will already have been stripped).
24+
type freevar_info = @[ast::def];
3525
type freevar_map = hashmap<ast::node_id, freevar_info>;
3626

3727
// Searches through part of the AST for all references to locals or
3828
// upvars in this frame and returns the list of definition IDs thus found.
3929
// Since we want to be able to collect upvars in some arbitrary piece
4030
// of the AST, we take a walker function that we invoke with a visitor
4131
// in order to start the search.
42-
fn collect_freevars(def_map: &resolve::def_map, sess: &session::session,
43-
walker: &fn(&visit::vt<()>),
44-
initial_decls: [ast::node_id]) -> freevar_info {
45-
let decls = new_int_hash();
46-
for decl: ast::node_id in initial_decls { set_add(decls, decl); }
32+
fn collect_freevars(def_map: &resolve::def_map,
33+
walker: &fn(&visit::vt<int>)) -> freevar_info {
34+
let seen = new_int_hash();
4735
let refs = @mutable [];
4836

49-
let walk_fn =
50-
lambda (f: &ast::_fn, _tps: &[ast::ty_param], _sp: &span,
51-
_i: &ast::fn_ident, _nid: ast::node_id) {
52-
for a: ast::arg in f.decl.inputs { set_add(decls, a.id); }
53-
};
54-
let walk_expr =
55-
lambda (expr: &@ast::expr) {
56-
alt expr.node {
57-
ast::expr_path(path) {
58-
if !def_map.contains_key(expr.id) {
59-
sess.span_fatal(expr.span,
60-
~"internal error in collect_freevars");
61-
}
62-
alt def_map.get(expr.id) {
63-
ast::def_arg(did, _) { *refs += [expr.id]; }
64-
ast::def_local(did) { *refs += [expr.id]; }
65-
ast::def_binding(did) { *refs += [expr.id]; }
66-
_ {/* no-op */ }
37+
fn ignore_item(_i: &@ast::item, _depth: &int, _v: &visit::vt<int>) {}
38+
39+
let walk_expr = lambda(expr: &@ast::expr, depth: &int,
40+
v: &visit::vt<int>) {
41+
alt expr.node {
42+
ast::expr_fn(f) {
43+
if f.proto == ast::proto_block ||
44+
f.proto == ast::proto_closure {
45+
visit::visit_expr(expr, depth + 1, v);
46+
}
47+
}
48+
ast::expr_for_each(dcl, x, b) {
49+
v.visit_local(dcl, depth, v);
50+
v.visit_expr(x, depth, v);
51+
v.visit_block(b, depth + 1, v);
52+
}
53+
ast::expr_path(path) {
54+
let def = def_map.get(expr.id), i = 0;
55+
while i < depth {
56+
alt {def} {
57+
ast::def_upvar(_, inner, _) {
58+
def = *inner;
59+
}
60+
_ { break; }
6761
}
68-
}
69-
_ { }
62+
i += 1;
7063
}
71-
};
72-
let walk_local =
73-
lambda (local: &@ast::local) {
74-
for each b: @ast::pat in ast_util::pat_bindings(local.node.pat) {
75-
set_add(decls, b.id);
64+
if i == depth { // Made it to end of loop
65+
let dnum = ast_util::def_id_of_def(def).node;
66+
if !seen.contains_key(dnum) {
67+
*refs += [def];
68+
seen.insert(dnum, ());
69+
}
7670
}
77-
};
78-
let walk_pat =
79-
lambda (p: &@ast::pat) {
80-
alt p.node { ast::pat_bind(_) { set_add(decls, p.id); } _ { } }
81-
};
82-
83-
walker(visit::mk_simple_visitor(@{visit_local: walk_local,
84-
visit_pat: walk_pat,
85-
visit_expr: walk_expr,
86-
visit_fn: walk_fn
87-
with
88-
*visit::default_simple_visitor()}));
89-
// Calculate (refs - decls). This is the set of captured upvars.
90-
// We build a vec of the node ids of the uses and a set of the
91-
// node ids of the definitions.
92-
let canonical_refs = [];
93-
let defs = new_int_hash();
94-
for ref_id_: ast::node_id in *refs {
95-
let ref_id = ref_id_;
96-
let def_id = ast_util::def_id_of_def(def_map.get(ref_id)).node;
97-
if !decls.contains_key(def_id) && !defs.contains_key(def_id) {
98-
canonical_refs += [ref_id];
99-
set_add(defs, def_id);
71+
}
72+
_ { visit::visit_expr(expr, depth, v); }
10073
}
101-
}
102-
ret {defs: defs, refs: @canonical_refs};
74+
};
75+
76+
walker(visit::mk_vt(@{visit_item: ignore_item,
77+
visit_expr: walk_expr
78+
with *visit::default_visitor()}));
79+
ret @*refs;
10380
}
10481

10582
// Build a map from every function and for-each body to a set of the
10683
// freevars contained in it. The implementation is not particularly
10784
// efficient as it fully recomputes the free variables at every
10885
// node of interest rather than building up the free variables in
10986
// one pass. This could be improved upon if it turns out to matter.
110-
fn annotate_freevars(sess: &session::session, def_map: &resolve::def_map,
87+
fn annotate_freevars(def_map: &resolve::def_map,
11188
crate: &@ast::crate) -> freevar_map {
11289
let freevars = new_int_hash();
11390

114-
let walk_fn =
115-
lambda (f: &ast::_fn, tps: &[ast::ty_param], sp: &span,
116-
i: &ast::fn_ident, nid: ast::node_id) {
117-
let start_walk =
118-
lambda (v: &visit::vt<()>) {
119-
v.visit_fn(f, tps, sp, i, nid, (), v);
120-
};
121-
let vars = collect_freevars(def_map, sess, start_walk, []);
122-
freevars.insert(nid, vars);
123-
};
124-
let walk_expr =
125-
lambda (expr: &@ast::expr) {
126-
alt expr.node {
127-
ast::expr_for_each(local, _, body) {
128-
let start_walk =
129-
lambda (v: &visit::vt<()>) {
130-
v.visit_block(body, (), v);
131-
};
132-
let bound = ast_util::pat_binding_ids(local.node.pat);
133-
let vars = collect_freevars(def_map, sess, start_walk, bound);
134-
freevars.insert(body.node.id, vars);
135-
}
136-
_ { }
137-
}
91+
let walk_fn = lambda (f: &ast::_fn, tps: &[ast::ty_param], sp: &span,
92+
i: &ast::fn_ident, nid: ast::node_id) {
93+
let start_walk = lambda (v: &visit::vt<int>) {
94+
v.visit_fn(f, tps, sp, i, nid, 1, v);
13895
};
96+
let vars = collect_freevars(def_map, start_walk);
97+
freevars.insert(nid, vars);
98+
};
99+
let walk_expr = lambda (expr: &@ast::expr) {
100+
alt expr.node {
101+
ast::expr_for_each(local, _, body) {
102+
let start_walk = lambda (v: &visit::vt<int>) {
103+
v.visit_block(body, 1, v);
104+
};
105+
let vars = collect_freevars(def_map, start_walk);
106+
freevars.insert(body.node.id, vars);
107+
}
108+
_ { }
109+
}
110+
};
139111

140112
let visitor =
141113
visit::mk_simple_visitor(@{visit_fn: walk_fn, visit_expr: walk_expr
@@ -145,7 +117,7 @@ fn annotate_freevars(sess: &session::session, def_map: &resolve::def_map,
145117
ret freevars;
146118
}
147119

148-
fn get_freevar_info(tcx: &ty::ctxt, fid: ast::node_id) -> freevar_info {
120+
fn get_freevars(tcx: &ty::ctxt, fid: ast::node_id) -> freevar_info {
149121
alt tcx.freevars.find(fid) {
150122
none. {
151123
fail "get_freevars: " + istr::to_estr(int::str(fid))
@@ -154,31 +126,9 @@ fn get_freevar_info(tcx: &ty::ctxt, fid: ast::node_id) -> freevar_info {
154126
some(d) { ret d; }
155127
}
156128
}
157-
fn get_freevar_defs(tcx: &ty::ctxt, fid: ast::node_id) -> freevar_set {
158-
ret get_freevar_info(tcx, fid).defs;
159-
}
160-
fn get_freevars(tcx: &ty::ctxt, fid: ast::node_id) -> @[ast::node_id] {
161-
ret get_freevar_info(tcx, fid).refs;
162-
}
163129
fn has_freevars(tcx: &ty::ctxt, fid: ast::node_id) -> bool {
164-
ret get_freevar_defs(tcx, fid).size() != 0u;
130+
ret std::vec::len(*get_freevars(tcx, fid)) != 0u;
165131
}
166-
fn is_freevar_of(tcx: &ty::ctxt, def: ast::node_id, f: ast::node_id) -> bool {
167-
ret get_freevar_defs(tcx, f).contains_key(def);
168-
}
169-
fn def_lookup(tcx: &ty::ctxt, f: ast::node_id, id: ast::node_id) ->
170-
option::t<ast::def> {
171-
alt tcx.def_map.find(id) {
172-
none. { ret none; }
173-
some(d) {
174-
let did = ast_util::def_id_of_def(d);
175-
if f != -1 && is_freevar_of(tcx, did.node, f) {
176-
ret some(ast::def_upvar(did, @d));
177-
} else { ret some(d); }
178-
}
179-
}
180-
}
181-
182132

183133
// Local Variables:
184134
// mode: rust

trunk/src/comp/middle/mut.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,18 @@ fn check_call(cx: &@ctx, f: &@expr, args: &[@expr]) {
238238
}
239239

240240
fn is_immutable_def(def: &def) -> option::t<istr> {
241-
ret alt def {
241+
alt def {
242242
def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) |
243243
def_use(_) { some(~"static item") }
244244
def_obj_field(_, imm.) { some(~"immutable object field") }
245245
def_arg(_, alias(false)) { some(~"immutable alias") }
246+
def_upvar(_, inner, mut) {
247+
if !mut { some(~"upvar") }
248+
else { is_immutable_def(*inner) }
249+
}
246250
def_binding(_) { some(~"binding") }
247251
_ { none }
248-
};
252+
}
249253
}
250254

251255
// Local Variables:

0 commit comments

Comments
 (0)