diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs index d07e862ceb96..88a763fb638f 100644 --- a/src/comp/middle/kind.rs +++ b/src/comp/middle/kind.rs @@ -42,7 +42,8 @@ fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, last_uses: last_uses}; let visit = visit::mk_vt(@{ visit_expr: check_expr, - visit_stmt: check_stmt + visit_stmt: check_stmt, + visit_fn_body: check_fn_body with *visit::default_visitor() }); visit::visit_crate(*crate, ctx, visit); @@ -50,18 +51,61 @@ fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, ret ctx.rval_map; } -fn check_expr(e: @expr, cx: ctx, v: visit::vt) { +// Yields the appropriate function to check the kind of closed over +// variables. `id` is the node_id for some expression that creates the +// closure. +fn with_closure_check_fn(cx: ctx, id: node_id, + b: block(fn(ctx, ty::t, sp: span))) { + let fty = ty::node_id_to_monotype(cx.tcx, id); + alt ty::ty_fn_proto(cx.tcx, fty) { + proto_send. { b(check_send); } + proto_shared(_) { b(check_copy); } + proto_block. | proto_bare. { /* no check needed */ } + } +} - fn check_free_vars(e: @expr, - cx: ctx, - check_fn: fn(ctx, ty::t, sp: span)) { - for @{def, span} in *freevars::get_freevars(cx.tcx, e.id) { +// Check that the free variables used in a shared/sendable closure conform +// to the copy/move kind bounds. Then recursively check the function body. +fn check_fn_body(decl: fn_decl, body: blk, sp: span, i: fn_ident, id: node_id, + cx: ctx, v: visit::vt) { + + // n.b.: This could be the body of either a fn decl or a fn expr. In the + // former case, the prototype will be proto_bare and no check occurs. In + // the latter case, we do not check the variables that in the capture + // clause (as we don't have access to that here) but just those that + // appear free. The capture clauses are checked below, in check_expr(). + // + // We could do this check also in check_expr(), but it seems more + // "future-proof" to do it this way, as check_fn_body() is supposed to be + // the common flow point for all functions that appear in the AST. + + with_closure_check_fn(cx, id) { |check_fn| + for @{def, span} in *freevars::get_freevars(cx.tcx, id) { let id = ast_util::def_id_of_def(def).node; let ty = ty::node_id_to_type(cx.tcx, id); check_fn(cx, ty, span); } } + visit::visit_fn_body(decl, body, sp, i, id, cx, v); +} + +fn check_fn_cap_clause(_cx: ctx, + _id: node_id, + _cap_clause: capture_clause) { +// let freevars = freevars::get_freevars(cx.tcx, i); +// let contains_var = lambda(id: def_id) -> bool { +// vec::any(freevars, { |freevar| +// ast_util::def_id_of_def(freevar).node == def_id +// }) +// } +// with_closure_check_fn(cx, id) { |check_fn| +// let check_var = lambda( +// } +} + +fn check_expr(e: @expr, cx: ctx, v: visit::vt) { + alt e.node { expr_assign(_, ex) | expr_assign_op(_, _, ex) | expr_block({node: {expr: some(ex), _}, _}) | @@ -121,13 +165,9 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt) { none. {} } } - expr_fn({proto: proto_send., _}, captures) { // NDM captures - check_free_vars(e, cx, check_send); - } - expr_fn({proto: proto_shared(_), _}, captures) { // NDM captures - check_free_vars(e, cx, check_copy); - } expr_ternary(_, a, b) { maybe_copy(cx, a); maybe_copy(cx, b); } + expr_fn(_, cap_clause) { check_fn_cap_clause(cx, e.id, *cap_clause); } + _ { } } visit::visit_expr(e, cx, v); diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs index 3f0d7a27a515..be3769a4ba1f 100644 --- a/src/comp/syntax/visit.rs +++ b/src/comp/syntax/visit.rs @@ -39,6 +39,7 @@ type visitor = visit_fn_block: fn@(fn_decl, blk, span, node_id, E, vt), // Invoked by both visit_fn_proto and visit_fn_block above. + // Intended to be a common flow point for all fn decls in AST. visit_fn_body: fn@(fn_decl, blk, span, fn_ident, node_id, E, vt)}; fn default_visitor() -> visitor {