Skip to content

Commit

Permalink
make it illegal to implicitly capture mutable variables
Browse files Browse the repository at this point in the history
this is the final part of #1273
  • Loading branch information
nikomatsakis committed May 7, 2012
1 parent d709ed2 commit 8a9df5a
Show file tree
Hide file tree
Showing 32 changed files with 259 additions and 123 deletions.
2 changes: 1 addition & 1 deletion src/librustsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ type capture_item = {
};

#[auto_serialize]
type capture_clause = [capture_item];
type capture_clause = @[capture_item];

/*
// Says whether this is a block the user marked as
Expand Down
9 changes: 5 additions & 4 deletions src/librustsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,8 @@ fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {

let body = parse_block(p);
ret mk_expr(p, lo, body.span.hi,
ast::expr_fn(proto, decl, body, capture_clause + cc_old));
ast::expr_fn(proto, decl, body,
@(*capture_clause + cc_old)));
}

fn parse_fn_block_expr(p: parser) -> @ast::expr {
Expand Down Expand Up @@ -1679,7 +1680,7 @@ fn parse_ty_params(p: parser) -> [ast::ty_param] {
}

// FIXME Remove after snapshot
fn parse_old_skool_capture_clause(p: parser) -> ast::capture_clause {
fn parse_old_skool_capture_clause(p: parser) -> [ast::capture_item] {
fn expect_opt_trailing_semi(p: parser) {
if !eat(p, token::SEMI) {
if p.token != token::RBRACKET {
Expand Down Expand Up @@ -1739,7 +1740,7 @@ fn parse_fn_decl(p: parser, purity: ast::purity,
parse_arg_fn, p).node;

let inputs = either::lefts(args_or_capture_items);
let capture_clause = either::rights(args_or_capture_items);
let capture_clause = @either::rights(args_or_capture_items);

// Use the args list to translate each bound variable
// mentioned in a constraint to an arg index.
Expand Down Expand Up @@ -1778,7 +1779,7 @@ fn parse_fn_block_decl(p: parser) -> (ast::fn_decl, ast::capture_clause) {
purity: ast::impure_fn,
cf: ast::return_val,
constraints: []},
either::rights(inputs_captures));
@either::rights(inputs_captures));
}

fn parse_fn_header(p: parser) -> {ident: ast::ident, tps: [ast::ty_param]} {
Expand Down
4 changes: 2 additions & 2 deletions src/librustsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
// head-box, will be closed by print-block at start
ibox(s, 0u);
word(s.s, proto_to_str(proto));
print_fn_args_and_ret(s, decl, cap_clause);
print_fn_args_and_ret(s, decl, *cap_clause);
space(s.s);
print_block(s, body);
}
Expand All @@ -1028,7 +1028,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
// head-box, will be closed by print-block at start
ibox(s, 0u);
word(s.s, "{");
print_fn_block_args(s, decl, cap_clause);
print_fn_block_args(s, decl, *cap_clause);
print_possibly_embedded_block(s, body, block_block_fn, indent_unit);
}
ast::expr_loop_body(body) {
Expand Down
18 changes: 10 additions & 8 deletions src/librustsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ enum fn_kind {
fk_item_fn(ident, [ty_param]), //< an item declared with fn()
fk_method(ident, [ty_param], @method),
fk_res(ident, [ty_param], region_param),
fk_anon(proto), //< an anonymous function like fn@(...)
fk_fn_block, //< a block {||...}
fk_anon(proto, capture_clause), //< an anonymous function like fn@(...)
fk_fn_block(capture_clause), //< a block {||...}
fk_ctor(ident, [ty_param], node_id /* self id */,
def_id /* parent class id */) // class constructor
}
Expand All @@ -26,15 +26,15 @@ fn name_of_fn(fk: fn_kind) -> ident {
alt fk {
fk_item_fn(name, _) | fk_method(name, _, _) | fk_res(name, _, _)
| fk_ctor(name, _, _, _) { name }
fk_anon(_) | fk_fn_block { "anon" }
fk_anon(*) | fk_fn_block(*) { "anon" }
}
}

fn tps_of_fn(fk: fn_kind) -> [ty_param] {
alt fk {
fk_item_fn(_, tps) | fk_method(_, tps, _) | fk_res(_, tps, _)
| fk_ctor(_, tps, _, _) { tps }
fk_anon(_) | fk_fn_block { [] }
fk_anon(*) | fk_fn_block(*) { [] }
}
}

Expand Down Expand Up @@ -381,11 +381,13 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
v.visit_expr(x, e, v);
for arms.each {|a| v.visit_arm(a, e, v); }
}
expr_fn(proto, decl, body, _) {
v.visit_fn(fk_anon(proto), decl, body, ex.span, ex.id, e, v);
expr_fn(proto, decl, body, cap_clause) {
v.visit_fn(fk_anon(proto, cap_clause), decl, body,
ex.span, ex.id, e, v);
}
expr_fn_block(decl, body, _) {
v.visit_fn(fk_fn_block, decl, body, ex.span, ex.id, e, v);
expr_fn_block(decl, body, cap_clause) {
v.visit_fn(fk_fn_block(cap_clause), decl, body,
ex.span, ex.id, e, v);
}
expr_block(b) { v.visit_block(b, e, v); }
expr_assign(a, b) { v.visit_expr(b, e, v); v.visit_expr(a, e, v); }
Expand Down
2 changes: 1 addition & 1 deletion src/rustc/front/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ fn mk_test_wrapper(cx: test_ctxt,
let wrapper_expr: ast::expr = {
id: cx.sess.next_node_id(),
node: ast::expr_fn(ast::proto_bare, wrapper_decl,
wrapper_body, []),
wrapper_body, @[]),
span: span
};

Expand Down
3 changes: 1 addition & 2 deletions src/rustc/metadata/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,7 @@ fn visit_ids(item: ast::inlined_item, vfn: fn@(ast::node_id)) {
vfn(m.self_id);
vec::iter(tps) {|tp| vfn(tp.id)}
}
visit::fk_anon(_) |
visit::fk_fn_block {
visit::fk_anon(*) | visit::fk_fn_block(*) {
}
}

Expand Down
21 changes: 2 additions & 19 deletions src/rustc/middle/capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@ type capture_map = map::hashmap<ast::def_id, capture_var>;
// errors for any irregularities which we identify.
fn check_capture_clause(tcx: ty::ctxt,
fn_expr_id: ast::node_id,
fn_proto: ast::proto,
cap_clause: ast::capture_clause) {
let freevars = freevars::get_freevars(tcx, fn_expr_id);
let seen_defs = map::int_hash();

let check_capture_item = fn@(cap_item: ast::capture_item) {
for (*cap_clause).each { |cap_item|
let cap_def = tcx.def_map.get(cap_item.id);
if !vec::any(*freevars, {|fv| fv.def == cap_def}) {
tcx.sess.span_warn(
Expand All @@ -52,22 +51,6 @@ fn check_capture_clause(tcx: ty::ctxt,
#fmt("variable '%s' captured more than once",
cap_item.name));
}
};

alt fn_proto {
ast::proto_any | ast::proto_block {
if vec::is_not_empty(cap_clause) {
let cap_item0 = vec::head(cap_clause);
tcx.sess.span_err(
cap_item0.span,
"cannot capture values explicitly with a block closure");
}
}
ast::proto_bare | ast::proto_box | ast::proto_uniq {
for cap_clause.each { |cap_item|
check_capture_item(cap_item);
}
}
}
}

Expand All @@ -80,7 +63,7 @@ fn compute_capture_vars(tcx: ty::ctxt,

// first add entries for anything explicitly named in the cap clause

for cap_clause.each { |cap_item|
for (*cap_clause).each { |cap_item|
let cap_def = tcx.def_map.get(cap_item.id);
let cap_def_id = ast_util::def_id_of_def(cap_def).node;
if cap_item.is_move {
Expand Down
Loading

0 comments on commit 8a9df5a

Please sign in to comment.