Prohibit assignment to upvars in lambdas. Closes #805.
This commit is contained in:
parent
a26c027731
commit
c5d55ef918
4 changed files with 58 additions and 5 deletions
|
@ -57,7 +57,29 @@ fn visit_fn(cx: &@ctx, f: &ast::_fn, tp: &ast::ty_param[], sp: &span,
|
||||||
for arg_: ast::arg in f.decl.inputs {
|
for arg_: ast::arg in f.decl.inputs {
|
||||||
cx.local_map.insert(arg_.id, arg(arg_.mode));
|
cx.local_map.insert(arg_.id, arg(arg_.mode));
|
||||||
}
|
}
|
||||||
v.visit_block(f.body, @~[], v);
|
let scope = alt (f.proto) {
|
||||||
|
// Blocks need to obey any restrictions from the enclosing scope.
|
||||||
|
ast::proto_block. { sc }
|
||||||
|
// Closures need to prohibit writing to any of the upvars.
|
||||||
|
// This doesn't seem like a particularly clean way to do this.
|
||||||
|
ast::proto_closure. {
|
||||||
|
let dnums = ~[];
|
||||||
|
for each nid in freevars::get_freevar_defs(cx.tcx, id).keys() {
|
||||||
|
dnums += ~[nid];
|
||||||
|
}
|
||||||
|
@~[@{root_vars: ~[],
|
||||||
|
// I'm not sure if there is anything sensical to put here
|
||||||
|
block_defnum: 0,
|
||||||
|
bindings: dnums,
|
||||||
|
tys: ~[],
|
||||||
|
depends_on: ~[],
|
||||||
|
mutable ok: valid}]
|
||||||
|
}
|
||||||
|
// Non capturing functions start out fresh.
|
||||||
|
_ { @~[] }
|
||||||
|
};
|
||||||
|
|
||||||
|
v.visit_block(f.body, scope, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_item(cx: &@ctx, i: &@ast::item, sc: &scope, v: &vt[scope]) {
|
fn visit_item(cx: &@ctx, i: &@ast::item, sc: &scope, v: &vt[scope]) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ export freevar_set;
|
||||||
export freevar_map;
|
export freevar_map;
|
||||||
export get_freevar_info;
|
export get_freevar_info;
|
||||||
export get_freevars;
|
export get_freevars;
|
||||||
export get_freevar_refs;
|
export get_freevar_defs;
|
||||||
export has_freevars;
|
export has_freevars;
|
||||||
export is_freevar_of;
|
export is_freevar_of;
|
||||||
export def_lookup;
|
export def_lookup;
|
||||||
|
@ -145,17 +145,17 @@ fn get_freevar_info(tcx: &ty::ctxt, fid: ast::node_id) -> freevar_info {
|
||||||
some(d) { ret d; }
|
some(d) { ret d; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_freevar_refs(tcx: &ty::ctxt, fid: ast::node_id) -> freevar_set {
|
fn get_freevar_defs(tcx: &ty::ctxt, fid: ast::node_id) -> freevar_set {
|
||||||
ret get_freevar_info(tcx, fid).defs;
|
ret get_freevar_info(tcx, fid).defs;
|
||||||
}
|
}
|
||||||
fn get_freevars(tcx: &ty::ctxt, fid: ast::node_id) -> @ast::node_id[] {
|
fn get_freevars(tcx: &ty::ctxt, fid: ast::node_id) -> @ast::node_id[] {
|
||||||
ret get_freevar_info(tcx, fid).refs;
|
ret get_freevar_info(tcx, fid).refs;
|
||||||
}
|
}
|
||||||
fn has_freevars(tcx: &ty::ctxt, fid: ast::node_id) -> bool {
|
fn has_freevars(tcx: &ty::ctxt, fid: ast::node_id) -> bool {
|
||||||
ret get_freevar_refs(tcx, fid).size() != 0u;
|
ret get_freevar_defs(tcx, fid).size() != 0u;
|
||||||
}
|
}
|
||||||
fn is_freevar_of(tcx: &ty::ctxt, def: ast::node_id, f: ast::node_id) -> bool {
|
fn is_freevar_of(tcx: &ty::ctxt, def: ast::node_id, f: ast::node_id) -> bool {
|
||||||
ret get_freevar_refs(tcx, f).contains_key(def);
|
ret get_freevar_defs(tcx, f).contains_key(def);
|
||||||
}
|
}
|
||||||
fn def_lookup(tcx: &ty::ctxt, f: ast::node_id, id: ast::node_id) ->
|
fn def_lookup(tcx: &ty::ctxt, f: ast::node_id, id: ast::node_id) ->
|
||||||
option::t[ast::def] {
|
option::t[ast::def] {
|
||||||
|
|
16
src/test/compile-fail/lambda-mutate-nested.rs
Normal file
16
src/test/compile-fail/lambda-mutate-nested.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// error-pattern:assigning to immutable alias
|
||||||
|
// Make sure that nesting a block within a lambda doesn't let us
|
||||||
|
// mutate upvars from a lambda.
|
||||||
|
fn main() {
|
||||||
|
let i = 0;
|
||||||
|
let ctr = lambda() -> int {
|
||||||
|
block() { i = i + 1; }();
|
||||||
|
ret i;
|
||||||
|
};
|
||||||
|
log_err ctr();
|
||||||
|
log_err ctr();
|
||||||
|
log_err ctr();
|
||||||
|
log_err ctr();
|
||||||
|
log_err ctr();
|
||||||
|
log_err i;
|
||||||
|
}
|
15
src/test/compile-fail/lambda-mutate.rs
Normal file
15
src/test/compile-fail/lambda-mutate.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// error-pattern:assigning to immutable alias
|
||||||
|
// Make sure we can't write to upvars from lambdas
|
||||||
|
fn main() {
|
||||||
|
let i = 0;
|
||||||
|
let ctr = lambda() -> int {
|
||||||
|
i = i + 1;
|
||||||
|
ret i;
|
||||||
|
};
|
||||||
|
log_err ctr();
|
||||||
|
log_err ctr();
|
||||||
|
log_err ctr();
|
||||||
|
log_err ctr();
|
||||||
|
log_err ctr();
|
||||||
|
log_err i;
|
||||||
|
}
|
Loading…
Reference in a new issue