diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 3616ba9e867e..4e9d1c4d343d 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -61,7 +61,7 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_map) { copy_map: std::map::new_int_hash(), ref_map: std::map::new_int_hash(), mutable silent: false}; - let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _), + let v = @{visit_fn_body: bind visit_fn_body(cx, _, _, _, _, _, _, _), visit_expr: bind visit_expr(cx, _, _, _), visit_block: bind visit_block(cx, _, _, _) with *visit::default_visitor::()}; @@ -71,10 +71,12 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_map) { ret (cx.copy_map, cx.ref_map); } -fn visit_fn(cx: @ctx, f: ast::_fn, _tp: [ast::ty_param], sp: span, - _name: fn_ident, id: ast::node_id, sc: scope, v: vt) { - visit::visit_fn_decl(f.decl, sc, v); - let args = ty::ty_fn_args(cx.tcx, ty::node_id_to_type(cx.tcx, id)); +fn visit_fn_body(cx: @ctx, decl: ast::fn_decl, body: ast::blk, + sp: span, _name: ast::fn_ident, + id: ast::node_id, sc: scope, v: vt) { + visit::visit_fn_decl(decl, sc, v); + let fty = ty::node_id_to_type(cx.tcx, id); + let args = ty::ty_fn_args(cx.tcx, fty); for arg in args { if arg.mode == ast::by_val && ty::type_has_dynamic_size(cx.tcx, arg.ty) { @@ -84,11 +86,12 @@ fn visit_fn(cx: @ctx, f: ast::_fn, _tp: [ast::ty_param], sp: span, // Blocks need to obey any restrictions from the enclosing scope, and may // be called multiple times. - if f.proto == ast::proto_block { - check_loop(*cx, sc) {|| v.visit_block(f.body, sc, v);} + let proto = ty::ty_fn_proto(cx.tcx, fty); + if proto == ast::proto_block { + check_loop(*cx, sc) {|| v.visit_block(body, sc, v);} } else { let sc = {bs: [], invalid: @mutable list::nil}; - v.visit_block(f.body, sc, v); + v.visit_block(body, sc, v); } } diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs index 0d0eb0869896..a18267569a3c 100644 --- a/src/comp/middle/ast_map.rs +++ b/src/comp/middle/ast_map.rs @@ -32,7 +32,7 @@ fn map_crate(c: crate) -> map { (@{visit_item: bind map_item(cx, _), visit_native_item: bind map_native_item(cx, _), visit_expr: bind map_expr(cx, _), - visit_fn: bind map_fn(cx, _, _, _, _, _), + visit_fn_body: bind map_fn_body(cx, _, _, _, _, _), visit_local: bind map_local(cx, _), visit_arm: bind map_arm(cx, _) with *visit::default_simple_visitor()}); @@ -40,9 +40,9 @@ fn map_crate(c: crate) -> map { ret cx.map; } -fn map_fn(cx: ctx, f: _fn, _tp: [ty_param], _sp: codemap::span, - _name: fn_ident, _id: node_id) { - for a in f.decl.inputs { +fn map_fn_body(cx: ctx, decl: fn_decl, _body: blk, + _sp: codemap::span, _n: fn_ident, _id: node_id) { + for a in decl.inputs { cx.map.insert(a.id, node_arg(a, cx.local_id)); cx.local_id += 1u; } diff --git a/src/comp/middle/debuginfo.rs b/src/comp/middle/debuginfo.rs index c11f65dc34f1..96868cd0bf03 100644 --- a/src/comp/middle/debuginfo.rs +++ b/src/comp/middle/debuginfo.rs @@ -740,6 +740,9 @@ fn create_function(fcx: @fn_ctxt) -> @metadata { ast::expr_fn(f, _) { (dbg_cx.names.next("fn"), f.decl.output, expr.id) } + ast::expr_fn_block(decl, _) { + (dbg_cx.names.next("fn"), decl.output, expr.id) + } } } }; diff --git a/src/comp/middle/freevars.rs b/src/comp/middle/freevars.rs index a7a791e52b09..f7688d350771 100644 --- a/src/comp/middle/freevars.rs +++ b/src/comp/middle/freevars.rs @@ -28,8 +28,8 @@ type freevar_map = hashmap; // Since we want to be able to collect upvars in some arbitrary piece // of the AST, we take a walker function that we invoke with a visitor // in order to start the search. -fn collect_freevars(def_map: resolve::def_map, walker: fn@(visit::vt)) -> - freevar_info { +fn collect_freevars(def_map: resolve::def_map, blk: ast::blk) + -> freevar_info { let seen = new_int_hash(); let refs = @mutable []; @@ -43,6 +43,9 @@ fn collect_freevars(def_map: resolve::def_map, walker: fn@(visit::vt)) -> visit::visit_expr(expr, depth + 1, v); } } + ast::expr_fn_block(_, _) { + visit::visit_expr(expr, depth + 1, v); + } ast::expr_path(path) { let def = def_map.get(expr.id), i = 0; while i < depth { @@ -64,8 +67,9 @@ fn collect_freevars(def_map: resolve::def_map, walker: fn@(visit::vt)) -> } }; - walker(visit::mk_vt(@{visit_item: ignore_item, visit_expr: walk_expr - with *visit::default_visitor()})); + let v = visit::mk_vt(@{visit_item: ignore_item, visit_expr: walk_expr + with *visit::default_visitor()}); + v.visit_block(blk, 1, v); ret @*refs; } @@ -78,20 +82,16 @@ fn annotate_freevars(def_map: resolve::def_map, crate: @ast::crate) -> freevar_map { let freevars = new_int_hash(); - let walk_fn = - lambda (f: ast::_fn, tps: [ast::ty_param], sp: span, i: ast::fn_ident, - nid: ast::node_id) { - let start_walk = - lambda (v: visit::vt) { - v.visit_fn(f, tps, sp, i, nid, 1, v); - }; - let vars = collect_freevars(def_map, start_walk); - freevars.insert(nid, vars); - }; + let walk_fn_body = lambda (_decl: ast::fn_decl, blk: ast::blk, + _sp: span, _nm: ast::fn_ident, + nid: ast::node_id) { + let vars = collect_freevars(def_map, blk); + freevars.insert(nid, vars); + }; let visitor = - visit::mk_simple_visitor(@{visit_fn: walk_fn - with *visit::default_simple_visitor()}); + visit::mk_simple_visitor(@{visit_fn_body: walk_fn_body + with *visit::default_simple_visitor()}); visit::visit_crate(*crate, (), visitor); ret freevars; diff --git a/src/comp/middle/last_use.rs b/src/comp/middle/last_use.rs index c6879898cc3f..7423cc70f0eb 100644 --- a/src/comp/middle/last_use.rs +++ b/src/comp/middle/last_use.rs @@ -1,5 +1,6 @@ import syntax::{visit, ast_util}; import syntax::ast::*; +import syntax::codemap::span; import std::list::{list, nil, cons, tail}; import core::{vec, option}; import std::list; @@ -42,7 +43,7 @@ type ctx = {last_uses: std::map::hashmap, fn find_last_uses(c: @crate, def_map: resolve::def_map, ref_map: alias::ref_map, tcx: ty::ctxt) -> last_uses { let v = visit::mk_vt(@{visit_expr: visit_expr, - visit_fn: visit_fn + visit_fn_body: visit_fn_body with *visit::default_visitor()}); let cx = {last_uses: std::map::new_int_hash(), def_map: def_map, @@ -136,6 +137,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt) { alt arg.node { //NDM--register captured as uses expr_fn(_, captured) { fns += [arg]; } + expr_fn_block(_, _) { fns += [arg]; } _ { alt arg_ts[i].mode { by_mut_ref. { clear_if_path(cx, arg, v, false); } @@ -151,16 +153,19 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt) { } } -fn visit_fn(f: _fn, tps: [ty_param], sp: syntax::codemap::span, - ident: fn_ident, id: node_id, cx: ctx, v: visit::vt) { - if f.proto == proto_block { +fn visit_fn_body(decl: fn_decl, body: blk, + sp: span, nm: fn_ident, id: node_id, + cx: ctx, v: visit::vt) { + let fty = ty::node_id_to_type(cx.tcx, id); + let proto = ty::ty_fn_proto(cx.tcx, fty); + if proto == proto_block { visit_block(func, cx, {|| - visit::visit_fn(f, tps, sp, ident, id, cx, v); + visit::visit_fn_body(decl, body, sp, nm, id, cx, v); }); } else { let old = nil; cx.blocks <-> old; - visit::visit_fn(f, tps, sp, ident, id, cx, v); + visit::visit_fn_body(decl, body, sp, nm, id, cx, v); cx.blocks <-> old; leave_fn(cx); } diff --git a/src/comp/middle/mut.rs b/src/comp/middle/mut.rs index d9b78d27cfbb..41bc218e1769 100644 --- a/src/comp/middle/mut.rs +++ b/src/comp/middle/mut.rs @@ -171,7 +171,7 @@ fn check_lval(cx: @ctx, dest: @expr, msg: msg) { alt dest.node { expr_path(p) { let def = cx.tcx.def_map.get(dest.id); - alt is_immutable_def(def) { + alt is_immutable_def(cx, def) { some(name) { mk_err(cx, dest.span, msg, name); } _ { } } @@ -258,7 +258,7 @@ fn check_bind(cx: @ctx, f: @expr, args: [option::t<@expr>]) { } } -fn is_immutable_def(def: def) -> option::t { +fn is_immutable_def(cx: @ctx, def: def) -> option::t { alt def { def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) | def_use(_) { @@ -268,8 +268,13 @@ fn is_immutable_def(def: def) -> option::t { def_arg(_, mode_infer.) { some("argument") } def_obj_field(_, imm.) { some("immutable object field") } def_self(_) { some("self argument") } - def_upvar(_, inner, mut) { - if !mut { some("upvar") } else { is_immutable_def(*inner) } + def_upvar(_, inner, node_id) { + let ty = ty::node_id_to_monotype(cx.tcx, node_id); + let proto = ty::ty_fn_proto(cx.tcx, ty); + ret alt proto { + proto_block. { is_immutable_def(cx, *inner) } + _ { some("upvar") } + }; } def_binding(_) { some("binding") } def_local(_, let_ref.) { some("by-reference binding") } diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index df57c71b367f..384b44a24cf7 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -31,7 +31,8 @@ export _impl, iscopes, method_info; tag scope { scope_crate; scope_item(@ast::item); - scope_fn(ast::fn_decl, ast::proto, [ast::ty_param]); + scope_bare_fn(ast::fn_decl, node_id, [ast::ty_param]); + scope_fn_expr(ast::fn_decl, node_id, [ast::ty_param]); scope_native_item(@ast::native_item); scope_loop(@ast::local); // there's only 1 decl per loop. scope_block(ast::blk, @mutable uint, @mutable uint); @@ -335,8 +336,11 @@ fn resolve_names(e: @env, c: @ast::crate) { visit_expr: bind walk_expr(e, _, _, _), visit_ty: bind walk_ty(e, _, _, _), visit_constr: bind walk_constr(e, _, _, _, _, _), - visit_fn: bind visit_fn_with_scope(e, _, _, _, _, _, _, _) - with *visit::default_visitor()}; + visit_fn_proto: + bind visit_fn_proto_with_scope(e, _, _, _, _, _, _, _), + visit_fn_block: + bind visit_fn_block_with_scope(e, _, _, _, _, _, _) + with *visit::default_visitor()}; visit::visit_crate(*c, cons(scope_crate, @nil), visit::mk_vt(v)); e.used_imports.track = false; e.sess.abort_if_errors(); @@ -400,8 +404,8 @@ fn visit_item_with_scope(i: @ast::item, sc: scopes, v: vt) { ast::item_impl(tps, sty, methods) { visit::visit_ty(sty, sc, v); for m in methods { - v.visit_fn(m.node.meth, tps + m.node.tps, m.span, - some(m.node.ident), m.node.id, sc, v); + v.visit_fn_proto(m.node.meth, tps + m.node.tps, m.span, + some(m.node.ident), m.node.id, sc, v); } } _ { visit::visit_item(i, sc, v); } @@ -413,9 +417,9 @@ fn visit_native_item_with_scope(ni: @ast::native_item, sc: scopes, visit::visit_native_item(ni, cons(scope_native_item(ni), @sc), v); } -fn visit_fn_with_scope(e: @env, f: ast::_fn, tp: [ast::ty_param], sp: span, - name: fn_ident, id: node_id, sc: scopes, - v: vt) { +fn visit_fn_proto_with_scope(e: @env, f: ast::_fn, tp: [ast::ty_param], + sp: span, name: fn_ident, id: node_id, + sc: scopes, v: vt) { // is this a main fn declaration? alt name { some(nm) { @@ -431,8 +435,21 @@ fn visit_fn_with_scope(e: @env, f: ast::_fn, tp: [ast::ty_param], sp: span, // here's where we need to set up the mapping // for f's constrs in the table. for c: @ast::constr in f.decl.constraints { resolve_constr(e, c, sc, v); } - visit::visit_fn(f, tp, sp, name, id, - cons(scope_fn(f.decl, f.proto, tp), @sc), v); + let scope = alt f.proto { + ast::proto_bare. { scope_bare_fn(f.decl, id, tp) } + _ { scope_fn_expr(f.decl, id, tp) } + }; + + visit::visit_fn_proto(f, tp, sp, name, id, cons(scope, @sc), v); +} + +fn visit_fn_block_with_scope(_e: @env, decl: fn_decl, blk: ast::blk, + span: span, id: node_id, + sc: scopes, v: vt) { + let scope = scope_fn_expr(decl, id, []); + log ("scope=", scope); + visit::visit_fn_block(decl, blk, span, id, cons(scope, @sc), v); + log ("unscope"); } fn visit_block_with_scope(b: ast::blk, sc: scopes, v: vt) { @@ -648,7 +665,8 @@ fn unresolved_err(e: env, cx: ctxt, sp: span, name: ident, kind: str) { alt sc { cons(cur, rest) { alt cur { - scope_crate. | scope_fn(_, _, _) | + scope_crate. | scope_bare_fn(_, _, _) | + scope_fn_expr(_, _, _) | scope_item(@{node: ast::item_mod(_), _}) { ret some(cur); } @@ -734,23 +752,17 @@ fn lookup_in_scope_strict(e: env, sc: scopes, sp: span, name: ident, fn scope_is_fn(sc: scope) -> bool { ret alt sc { - scope_fn(_, ast::proto_bare., _) | - scope_native_item(_) { - true - } - _ { false } - }; + scope_bare_fn(_, _, _) | scope_native_item(_) { true } + _ { false } + }; } // Returns: // none - does not close -// some(true) - closes and permits mutation -// some(false) - closes but no mutation -fn scope_closes(sc: scope) -> option::t { +// some(node_id) - closes via the expr w/ node_id +fn scope_closes(sc: scope) -> option::t { alt sc { - scope_fn(_, ast::proto_block., _) { some(true) } - scope_fn(_, ast::proto_send., _) { some(false) } - scope_fn(_, ast::proto_shared(_), _) { some(false) } + scope_fn_expr(_, node_id, _) { some(node_id) } _ { none } } } @@ -823,7 +835,8 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace) } } } - scope_fn(decl, _, ty_params) { + scope_bare_fn(decl, _, ty_params) | + scope_fn_expr(decl, _, ty_params) { ret lookup_in_fn(name, decl, ty_params, ns); } scope_loop(local) { @@ -887,7 +900,10 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace) left_fn_level2 = true; } else if ns == ns_value || ns == ns_type { left_fn = scope_is_fn(hd); - alt scope_closes(hd) { some(mut) { closing += [mut]; } _ { } } + alt scope_closes(hd) { + some(node_id) { closing += [node_id]; } + _ { } + } } sc = *tl; } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index aa72cb98ad3e..8ccda0daa4df 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3558,6 +3558,19 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt { ret trans_closure::trans_expr_fn( bcx, f, e.span, e.id, *cap_clause, dest); } + ast::expr_fn_block(decl, body) { + alt ty::struct(tcx, ty::expr_ty(tcx, e)) { + ty::ty_fn(proto, _, _, _, _) { + let f: ast::_fn = { decl: decl, proto: proto, body: body }; + let cap_clause = { copies: [], moves: [] }; + ret trans_closure::trans_expr_fn( + bcx, f, e.span, e.id, cap_clause, dest); + } + _ { + fail "Type of fn block is not a function!"; + } + } + } ast::expr_bind(f, args) { ret trans_closure::trans_bind( bcx, f, args, e.id, dest); diff --git a/src/comp/middle/tstate/annotate.rs b/src/comp/middle/tstate/annotate.rs index 0ca72c569a2f..389fbf1c76d9 100644 --- a/src/comp/middle/tstate/annotate.rs +++ b/src/comp/middle/tstate/annotate.rs @@ -32,15 +32,14 @@ fn collect_ids_local(l: @local, rs: @mutable [node_id]) { *rs += pat_binding_ids(l.node.pat); } -fn node_ids_in_fn(f: _fn, tps: [ty_param], sp: span, i: fn_ident, id: node_id, - rs: @mutable [node_id]) { +fn node_ids_in_fn(body: blk, rs: @mutable [node_id]) { let collect_ids = visit::mk_simple_visitor(@{visit_expr: bind collect_ids_expr(_, rs), visit_block: bind collect_ids_block(_, rs), visit_stmt: bind collect_ids_stmt(_, rs), visit_local: bind collect_ids_local(_, rs) with *visit::default_simple_visitor()}); - visit::visit_fn(f, tps, sp, i, id, (), collect_ids); + collect_ids.visit_block(body, (), collect_ids); } fn init_vecs(ccx: crate_ctxt, node_ids: [node_id], len: uint) { @@ -50,25 +49,24 @@ fn init_vecs(ccx: crate_ctxt, node_ids: [node_id], len: uint) { } } -fn visit_fn(ccx: crate_ctxt, num_constraints: uint, f: _fn, tps: [ty_param], - sp: span, i: fn_ident, id: node_id) { +fn visit_fn(ccx: crate_ctxt, num_constraints: uint, body: blk) { let node_ids: @mutable [node_id] = @mutable []; - node_ids_in_fn(f, tps, sp, i, id, node_ids); + node_ids_in_fn(body, node_ids); let node_id_vec = *node_ids; init_vecs(ccx, node_id_vec, num_constraints); } -fn annotate_in_fn(ccx: crate_ctxt, f: _fn, tps: [ty_param], sp: span, - i: fn_ident, id: node_id) { +fn annotate_in_fn_body(ccx: crate_ctxt, _decl: fn_decl, body: blk, + _sp: span, _n: fn_ident, id: node_id) { let f_info = get_fn_info(ccx, id); - visit_fn(ccx, num_constraints(f_info), f, tps, sp, i, id); + visit_fn(ccx, num_constraints(f_info), body); } fn annotate_crate(ccx: crate_ctxt, crate: crate) { let do_ann = - visit::mk_simple_visitor(@{visit_fn: - bind annotate_in_fn(ccx, _, _, _, _, _) - with *visit::default_simple_visitor()}); + visit::mk_simple_visitor( + @{visit_fn_body: bind annotate_in_fn_body(ccx, _, _, _, _, _) + with *visit::default_simple_visitor()}); visit::visit_crate(crate, (), do_ann); } // diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index d105a7dd5798..c2d1732c86ec 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -1003,8 +1003,9 @@ fn op_to_oper_ty(io: init_op) -> oper_type { } // default function visitor -fn do_nothing(_f: _fn, _tp: [ty_param], _sp: span, _i: fn_ident, - _iid: node_id, _cx: T, _v: visit::vt) { +fn do_nothing(_decl: fn_decl, _body: blk, + _sp: span, _i: fn_ident, _id: node_id, + _t: T, _v: visit::vt) { } diff --git a/src/comp/middle/tstate/bitvectors.rs b/src/comp/middle/tstate/bitvectors.rs index 9cfe4e3c1781..ac21c5929512 100644 --- a/src/comp/middle/tstate/bitvectors.rs +++ b/src/comp/middle/tstate/bitvectors.rs @@ -151,7 +151,7 @@ fn relax_precond_block(fcx: fn_ctxt, i: node_id, b: blk) { visit_stmt: relax_precond_stmt, visit_item: fn (_i: @item, _cx: relax_ctxt, _vt: visit::vt) { }, - visit_fn: bind do_nothing(_, _, _, _, _, _, _) + visit_fn_body: bind do_nothing(_, _, _, _, _, _, _) with *visitor}; let v1 = visit::mk_vt(visitor); v1.visit_block(b, cx, v1); diff --git a/src/comp/middle/tstate/ck.rs b/src/comp/middle/tstate/ck.rs index e8a1d2e938ed..72b5d6fbab32 100644 --- a/src/comp/middle/tstate/ck.rs +++ b/src/comp/middle/tstate/ck.rs @@ -95,45 +95,47 @@ fn check_states_stmt(s: @stmt, fcx: fn_ctxt, v: visit::vt) { } } -fn check_states_against_conditions(fcx: fn_ctxt, f: _fn, tps: [ast::ty_param], - id: node_id, sp: span, i: fn_ident) { +fn check_states_against_conditions(fcx: fn_ctxt, + f_decl: ast::fn_decl, + f_body: ast::blk, + sp: span, + nm: fn_ident, + id: node_id) { /* Postorder traversal instead of pre is important because we want the smallest possible erroneous statement or expression. */ - let visitor = visit::default_visitor::(); - - visitor = + let visitor = visit::mk_vt( @{visit_stmt: check_states_stmt, visit_expr: check_states_expr, - visit_fn: bind do_nothing(_, _, _, _, _, _, _) - with *visitor}; - visit::visit_fn(f, tps, sp, i, id, fcx, visit::mk_vt(visitor)); + visit_fn_body: bind do_nothing::(_, _, _, _, _, _, _) + with *visit::default_visitor::()}); + visit::visit_fn_body(f_decl, f_body, sp, nm, id, fcx, visitor); /* Check that the return value is initialized */ - let post = aux::block_poststate(fcx.ccx, f.body); + let post = aux::block_poststate(fcx.ccx, f_body); if !promises(fcx, post, fcx.enclosing.i_return) && !type_is_nil(fcx.ccx.tcx, ret_ty_of_fn(fcx.ccx.tcx, id)) && - f.decl.cf == return_val { - fcx.ccx.tcx.sess.span_err(f.body.span, + f_decl.cf == return_val { + fcx.ccx.tcx.sess.span_err(f_body.span, "In function " + fcx.name + ", not all control paths \ return a value"); - fcx.ccx.tcx.sess.span_fatal(f.decl.output.span, + fcx.ccx.tcx.sess.span_fatal(f_decl.output.span, "see declared return type of '" + - ty_to_str(f.decl.output) + "'"); - } else if f.decl.cf == noreturn { + ty_to_str(f_decl.output) + "'"); + } else if f_decl.cf == noreturn { // check that this really always fails // Note that it's ok for i_diverge and i_return to both be true. // In fact, i_diverge implies i_return. (But not vice versa!) if !promises(fcx, post, fcx.enclosing.i_diverge) { - fcx.ccx.tcx.sess.span_fatal(f.body.span, + fcx.ccx.tcx.sess.span_fatal(f_body.span, "In non-returning function " + - fcx.name + - ", some control paths may \ - return to the caller"); + fcx.name + + ", some control paths may \ + return to the caller"); } } @@ -141,29 +143,34 @@ fn check_states_against_conditions(fcx: fn_ctxt, f: _fn, tps: [ast::ty_param], check_unused_vars(fcx); } -fn check_fn_states(fcx: fn_ctxt, f: _fn, tps: [ast::ty_param], id: node_id, - sp: span, i: fn_ident) { +fn check_fn_states(fcx: fn_ctxt, + f_decl: ast::fn_decl, + f_body: ast::blk, + sp: span, + nm: fn_ident, + id: node_id) { /* Compute the pre- and post-states for this function */ // Fixpoint iteration - while find_pre_post_state_fn(fcx, f) { } + while find_pre_post_state_fn(fcx, f_decl, f_body) { } /* Now compare each expr's pre-state to its precondition and post-state to its postcondition */ - check_states_against_conditions(fcx, f, tps, id, sp, i); + check_states_against_conditions(fcx, f_decl, f_body, sp, nm, id); } -fn fn_states(f: _fn, tps: [ast::ty_param], sp: span, i: fn_ident, id: node_id, +fn fn_states(f_decl: ast::fn_decl, f_body: ast::blk, + sp: span, i: ast::fn_ident, id: node_id, ccx: crate_ctxt, v: visit::vt) { - visit::visit_fn(f, tps, sp, i, id, ccx, v); + visit::visit_fn_body(f_decl, f_body, sp, i, id, ccx, v); /* Look up the var-to-bit-num map for this function */ assert (ccx.fm.contains_key(id)); let f_info = ccx.fm.get(id); - let name = option::from_maybe("anon", i); + let name = option::from_maybe("anon", i); // XXXX let fcx = {enclosing: f_info, id: id, name: name, ccx: ccx}; - check_fn_states(fcx, f, tps, id, sp, i); + check_fn_states(fcx, f_decl, f_body, sp, i, id) } fn check_crate(cx: ty::ctxt, crate: @crate) { @@ -177,12 +184,13 @@ fn check_crate(cx: ty::ctxt, crate: @crate) { /* Compute the pre and postcondition for every subexpression */ let vtor = visit::default_visitor::(); - vtor = @{visit_fn: fn_pre_post with *vtor}; + vtor = @{visit_fn_body: fn_pre_post with *vtor}; visit::visit_crate(*crate, ccx, visit::mk_vt(vtor)); /* Check the pre- and postcondition against the pre- and poststate for every expression */ - vtor = @{visit_fn: fn_states with *vtor}; + let vtor = visit::default_visitor::(); + vtor = @{visit_fn_body: fn_states with *vtor}; visit::visit_crate(*crate, ccx, visit::mk_vt(vtor)); } // diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs index 14999d8ad971..125a165b9aab 100644 --- a/src/comp/middle/tstate/collect_locals.rs +++ b/src/comp/middle/tstate/collect_locals.rs @@ -44,7 +44,11 @@ fn collect_pred(e: @expr, cx: ctxt, v: visit::vt) { visit::visit_expr(e, cx, v); } -fn find_locals(tcx: ty::ctxt, f: _fn, tps: [ty_param], sp: span, i: fn_ident, +fn find_locals(tcx: ty::ctxt, + f_decl: fn_decl, + f_body: blk, + sp: span, + n: fn_ident, id: node_id) -> ctxt { let cx: ctxt = {cs: @mutable [], tcx: tcx}; let visitor = visit::default_visitor::(); @@ -52,9 +56,10 @@ fn find_locals(tcx: ty::ctxt, f: _fn, tps: [ty_param], sp: span, i: fn_ident, visitor = @{visit_local: collect_local, visit_expr: collect_pred, - visit_fn: bind do_nothing(_, _, _, _, _, _, _) - with *visitor}; - visit::visit_fn(f, tps, sp, i, id, cx, visit::mk_vt(visitor)); + visit_fn_body: bind do_nothing(_, _, _, _, _, _, _) + with *visitor}; + visit::visit_fn_body(f_decl, f_body, sp, + n, id, cx, visit::mk_vt(visitor)); ret cx; } @@ -90,13 +95,17 @@ fn add_constraint(tcx: ty::ctxt, c: sp_constr, next: uint, tbl: constr_map) -> /* builds a table mapping each local var defined in f to a bit number in the precondition/postcondition vectors */ -fn mk_fn_info(ccx: crate_ctxt, f: _fn, tp: [ty_param], f_sp: span, - f_name: fn_ident, id: node_id) { +fn mk_fn_info(ccx: crate_ctxt, + f_decl: fn_decl, + f_body: blk, + f_sp: span, + f_name: fn_ident, + id: node_id) { let name = fn_ident_to_string(id, f_name); let res_map = @new_def_hash::(); let next: uint = 0u; - let cx: ctxt = find_locals(ccx.tcx, f, tp, f_sp, f_name, id); + let cx: ctxt = find_locals(ccx.tcx, f_decl, f_body, f_sp, f_name, id); /* now we have to add bit nums for both the constraints and the variables... */ @@ -106,17 +115,19 @@ fn mk_fn_info(ccx: crate_ctxt, f: _fn, tp: [ty_param], f_sp: span, /* if this function has any constraints, instantiate them to the argument names and add them */ let sc; - for c: @constr in f.decl.constraints { - sc = ast_constr_to_sp_constr(cx.tcx, f.decl.inputs, c); + for c: @constr in f_decl.constraints { + sc = ast_constr_to_sp_constr(cx.tcx, f_decl.inputs, c); next = add_constraint(cx.tcx, sc, next, res_map); } /* Need to add constraints for args too, b/c they can be deinitialized */ - for a: arg in f.decl.inputs { - next = - add_constraint(cx.tcx, respan(f_sp, ninit(a.id, a.ident)), next, - res_map); + for a: arg in f_decl.inputs { + next = add_constraint( + cx.tcx, + respan(f_sp, ninit(a.id, a.ident)), + next, + res_map); } /* add the special i_diverge and i_return constraints @@ -137,7 +148,7 @@ fn mk_fn_info(ccx: crate_ctxt, f: _fn, tp: [ty_param], f_sp: span, let rslt = {constrs: res_map, num_constraints: next, - cf: f.decl.cf, + cf: f_decl.cf, i_return: ninit(id, name), i_diverge: ninit(diverges_id, diverges_name), used_vars: v}; @@ -152,9 +163,9 @@ fn mk_fn_info(ccx: crate_ctxt, f: _fn, tp: [ty_param], f_sp: span, to bit number) */ fn mk_f_to_fn_info(ccx: crate_ctxt, c: @crate) { let visitor = - visit::mk_simple_visitor(@{visit_fn: + visit::mk_simple_visitor(@{visit_fn_body: bind mk_fn_info(ccx, _, _, _, _, _) - with *visit::default_simple_visitor()}); + with *visit::default_simple_visitor()}); visit::visit_crate(*c, (), visitor); } // diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 862c7867feb2..5a89a8fd0172 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -33,7 +33,7 @@ fn find_pre_post_method(ccx: crate_ctxt, m: @method) { id: m.node.id, name: m.node.ident, ccx: ccx}; - find_pre_post_fn(fcx, m.node.meth); + find_pre_post_fn(fcx, m.node.meth.body); } fn find_pre_post_item(ccx: crate_ctxt, i: item) { @@ -60,7 +60,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) { assert (ccx.fm.contains_key(i.id)); let fcx = {enclosing: ccx.fm.get(i.id), id: i.id, name: i.ident, ccx: ccx}; - find_pre_post_fn(fcx, f); + find_pre_post_fn(fcx, f.body); } item_mod(m) { find_pre_post_mod(m); } item_native_mod(nm) { find_pre_post_native_mod(nm); } @@ -72,7 +72,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) { id: dtor_id, name: i.ident, ccx: ccx}; - find_pre_post_fn(fcx, dtor); + find_pre_post_fn(fcx, dtor.body); } item_obj(o, _, _) {for m in o.methods { find_pre_post_method(ccx, m); }} item_impl(_, _, ms) { for m in ms { find_pre_post_method(ccx, m); } } @@ -298,6 +298,15 @@ fn forget_args_moved_in(fcx: fn_ctxt, parent: @expr, modes: [ty::mode], } } +fn find_pre_post_expr_fn_upvars(fcx: fn_ctxt, e: @expr) { + let rslt = expr_pp(fcx.ccx, e); + clear_pp(rslt); + for def in *freevars::get_freevars(fcx.ccx.tcx, e.id) { + log ("handle_var_def: def=", def); + handle_var_def(fcx, rslt, def.def, "upvar"); + } +} + /* Fills in annotations as a side effect. Does not rebuild the expr */ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) { let enclosing = fcx.enclosing; @@ -340,12 +349,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) { copy_pre_post(fcx.ccx, e.id, arg); } expr_fn(f, cap_clause) { - let rslt = expr_pp(fcx.ccx, e); - clear_pp(rslt); - for def in *freevars::get_freevars(fcx.ccx.tcx, e.id) { - log ("handle_var_def: def=", def); - handle_var_def(fcx, rslt, def.def, "upvar"); - } + find_pre_post_expr_fn_upvars(fcx, e); let use_cap_item = lambda(&&cap_item: @capture_item) { let d = local_node_id_to_local_def_id(fcx, cap_item.id); @@ -358,9 +362,9 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) { log ("forget_in_postcond: ", cap_item); forget_in_postcond(fcx, e.id, cap_item.id); } - - let ann = node_id_to_ts_ann(fcx.ccx, e.id); - log_cond(tritv::to_vec(ann.conditions.postcondition)); + } + expr_fn_block(_, _) { + find_pre_post_expr_fn_upvars(fcx, e); } expr_block(b) { find_pre_post_block(fcx, b); @@ -711,32 +715,33 @@ fn find_pre_post_block(fcx: fn_ctxt, b: blk) { set_pre_and_post(fcx.ccx, b.node.id, block_precond, block_postcond); } -fn find_pre_post_fn(fcx: fn_ctxt, f: _fn) { +fn find_pre_post_fn(fcx: fn_ctxt, body: blk) { // hack use_var(fcx, tsconstr_to_node_id(fcx.enclosing.i_return)); use_var(fcx, tsconstr_to_node_id(fcx.enclosing.i_diverge)); - find_pre_post_block(fcx, f.body); - + find_pre_post_block(fcx, body); // Treat the tail expression as a return statement - alt f.body.node.expr { + alt body.node.expr { some(tailexpr) { set_postcond_false(fcx.ccx, tailexpr.id); } none. {/* fallthrough */ } } } -fn fn_pre_post(f: _fn, tps: [ty_param], sp: span, i: fn_ident, id: node_id, +fn fn_pre_post(decl: fn_decl, body: blk, sp: span, + i: fn_ident, id: node_id, ccx: crate_ctxt, v: visit::vt) { - visit::visit_fn(f, tps, sp, i, id, ccx, v); + visit::visit_fn_body(decl, body, sp, i, id, ccx, v); assert (ccx.fm.contains_key(id)); let fcx = {enclosing: ccx.fm.get(id), id: id, name: fn_ident_to_string(id, i), ccx: ccx}; - find_pre_post_fn(fcx, f); + find_pre_post_fn(fcx, body); } + // // Local Variables: // mode: rust diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index 209899c26b16..16bf445790d2 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -374,6 +374,7 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool { expr_fn(_, cap_clause) { ret find_pre_post_state_cap_clause(fcx, e.id, pres, *cap_clause); } + expr_fn_block(_, _) { ret pure_exp(fcx.ccx, e.id, pres); } expr_block(b) { ret find_pre_post_state_block(fcx, pres, b) | set_prestate_ann(fcx.ccx, e.id, pres) | @@ -732,28 +733,30 @@ fn find_pre_post_state_block(fcx: fn_ctxt, pres0: prestate, b: blk) -> bool { ret changed; } -fn find_pre_post_state_fn(fcx: fn_ctxt, f: _fn) -> bool { +fn find_pre_post_state_fn(fcx: fn_ctxt, + f_decl: fn_decl, + f_body: blk) -> bool { let num_constrs = num_constraints(fcx.enclosing); // All constraints are considered false until proven otherwise. // This ensures that intersect works correctly. - kill_all_prestate(fcx, f.body.node.id); + kill_all_prestate(fcx, f_body.node.id); // Arguments start out initialized - let block_pre = block_prestate(fcx.ccx, f.body); - for a: arg in f.decl.inputs { + let block_pre = block_prestate(fcx.ccx, f_body); + for a: arg in f_decl.inputs { set_in_prestate_constr(fcx, ninit(a.id, a.ident), block_pre); } // Instantiate any constraints on the arguments so we can use them - for c: @constr in f.decl.constraints { - let tsc = ast_constr_to_ts_constr(fcx.ccx.tcx, f.decl.inputs, c); + for c: @constr in f_decl.constraints { + let tsc = ast_constr_to_ts_constr(fcx.ccx.tcx, f_decl.inputs, c); set_in_prestate_constr(fcx, tsc, block_pre); } - let changed = find_pre_post_state_block(fcx, block_pre, f.body); + let changed = find_pre_post_state_block(fcx, block_pre, f_body); // Treat the tail expression as a return statement - alt f.body.node.expr { + alt f_body.node.expr { some(tailexpr) { // We don't want to clear the diverges bit for bottom typed things, @@ -763,7 +766,7 @@ fn find_pre_post_state_fn(fcx: fn_ctxt, f: _fn) -> bool { let post = false_postcond(num_constrs); // except for the "diverges" bit... kill_poststate_(fcx, fcx.enclosing.i_diverge, post); - set_poststate_ann(fcx.ccx, f.body.node.id, post); + set_poststate_ann(fcx.ccx, f_body.node.id, post); } } none. {/* fallthrough */ } @@ -772,7 +775,7 @@ fn find_pre_post_state_fn(fcx: fn_ctxt, f: _fn) -> bool { /* log_err "find_pre_post_state_fn"; log_err changed; - fcx.ccx.tcx.sess.span_note(f.body.span, fcx.name); + fcx.ccx.tcx.sess.span_note(f_body.span, fcx.name); */ ret changed; diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index dc3cee75c23b..d852e8938009 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -999,8 +999,9 @@ mod writeback { if !wbcx.success { ret; } resolve_type_vars_for_node(wbcx, e.span, e.id); alt e.node { - ast::expr_fn(f, _) { // NDM captures? - for input in f.decl.inputs { + ast::expr_fn({decl: decl, _}, _) | + ast::expr_fn_block(decl, _) { + for input in decl.inputs { resolve_type_vars_for_node(wbcx, e.span, input.id); } } @@ -1077,7 +1078,10 @@ type gather_result = next_var_id: @mutable int}; // Used only as a helper for check_fn. -fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id, +fn gather_locals(ccx: @crate_ctxt, + decl: ast::fn_decl, + body: ast::blk, + id: ast::node_id, old_fcx: option::t<@fn_ctxt>) -> gather_result { let {vb: vb, locals: locals, nvi: nvi} = alt old_fcx { @@ -1121,7 +1125,7 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id, let args = ty::ty_fn_args(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)); let i = 0u; for arg: ty::arg in args { - assign(f.decl.inputs[i].id, some(arg.ty)); + assign(decl.inputs[i].id, some(arg.ty)); i += 1u; } @@ -1144,20 +1148,20 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id, }; // Don't descend into fns and items - fn visit_fn(_f: ast::_fn, _tp: [ast::ty_param], _sp: span, - _i: ast::fn_ident, _id: ast::node_id, _e: E, - _v: visit::vt) { + fn visit_fn_body(_decl: ast::fn_decl, _body: ast::blk, + _sp: span, _nm: ast::fn_ident, _id: ast::node_id, + _t: T, _v: visit::vt) { } fn visit_item(_i: @ast::item, _e: E, _v: visit::vt) { } let visit = @{visit_local: visit_local, visit_pat: visit_pat, - visit_fn: bind visit_fn(_, _, _, _, _, _, _), + visit_fn_body: bind visit_fn_body(_, _, _, _, _, _, _), visit_item: bind visit_item(_, _, _) with *visit::default_visitor()}; - visit::visit_block(f.body, (), visit::mk_vt(visit)); + visit::visit_block(body, (), visit::mk_vt(visit)); ret {var_bindings: vb, locals: locals, next_var_id: nvi}; @@ -1496,6 +1500,32 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes, result } +fn check_expr_fn_with_unifier(fcx: @fn_ctxt, + expr: @ast::expr, + decl: ast::fn_decl, + proto: ast::proto, + body: ast::blk, + unify: unifier, + expected: ty::t) { + let tcx = fcx.ccx.tcx; + + let fty = ty_of_fn_decl(tcx, m_check_tyvar(fcx), decl, + proto, [], none).ty; + + write::ty_only_fixup(fcx, expr.id, fty); + + // Unify the type of the function with the expected type before we + // typecheck the body so that we have more information about the + // argument types in the body. This is needed to make binops and + // record projection work on type inferred arguments. + unify(fcx, expr.span, expected, fty); + + check_fn1(fcx.ccx, decl, proto, body, expr.id, some(fcx)); + if proto == ast::proto_block { + write::ty_only_fixup(fcx, expr.id, expected); + } +} + fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, expected: ty::t) -> bool { //log_err "typechecking expr " + syntax::print::pprust::expr_to_str(expr); @@ -1563,7 +1593,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, some(a) { let is_block = alt a.node { - ast::expr_fn(_, _) { true } + ast::expr_fn_block(_, _) { true } _ { false } }; if is_block == check_blocks { @@ -1940,24 +1970,21 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, write::ty_only_fixup(fcx, id, result_ty); } ast::expr_fn(f, captures) { - let fty = ty_of_fn_decl(tcx, m_check_tyvar(fcx), f.decl, - f.proto, [], none).ty; - - write::ty_only_fixup(fcx, id, fty); - - // Unify the type of the function with the expected type before we - // typecheck the body so that we have more information about the - // argument types in the body. This is needed to make binops and - // record projection work on type inferred arguments. - unify(fcx, expr.span, expected, fty); - - check_fn(fcx.ccx, f, id, some(fcx)); - if f.proto == ast::proto_block { - write::ty_only_fixup(fcx, id, expected); - } - + check_expr_fn_with_unifier(fcx, expr, f.decl, + f.proto, f.body, + unify, expected); capture::check_capture_clause(tcx, expr.id, f.proto, *captures); } + ast::expr_fn_block(decl, body) { + // Take the prototype from the expected type, but default to block: + let proto = alt ty::struct(tcx, expected) { + ty::ty_fn(proto, _, _, _, _) { proto } + _ { ast::proto_block } + }; + check_expr_fn_with_unifier(fcx, expr, decl, + proto, body, + unify, expected); + } ast::expr_block(b) { // If this is an unchecked block, turn off purity-checking bot = check_block(fcx, b); @@ -2581,12 +2608,19 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) { } } -fn check_fn(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id, +fn check_fn(ccx: @crate_ctxt, + f: ast::_fn, + id: ast::node_id, old_fcx: option::t<@fn_ctxt>) { + check_fn1(ccx, f.decl, f.proto, f.body, id, old_fcx); +} - let decl = f.decl; - let body = f.body; - +fn check_fn1(ccx: @crate_ctxt, + decl: ast::fn_decl, + proto: ast::proto, + body: ast::blk, + id: ast::node_id, + old_fcx: option::t<@fn_ctxt>) { // If old_fcx is some(...), this is a block fn { |x| ... }. // In that case, the purity is inherited from the context. let purity = alt old_fcx { @@ -2594,12 +2628,12 @@ fn check_fn(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id, some(f) { assert decl.purity == ast::impure_fn; f.purity } }; - let gather_result = gather_locals(ccx, f, id, old_fcx); + let gather_result = gather_locals(ccx, decl, body, id, old_fcx); let fixups: [ast::node_id] = []; let fcx: @fn_ctxt = @{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)), purity: purity, - proto: f.proto, + proto: proto, var_bindings: gather_result.var_bindings, locals: gather_result.locals, next_var_id: gather_result.next_var_id, @@ -2622,7 +2656,7 @@ fn check_fn(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id, let args = ty::ty_fn_args(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)); let i = 0u; for arg: ty::arg in args { - write::ty_only_fixup(fcx, f.decl.inputs[i].id, arg.ty); + write::ty_only_fixup(fcx, decl.inputs[i].id, arg.ty); i += 1u; } diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index 4f6b5cf3744f..ed9349166ed7 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -42,7 +42,7 @@ tag def { def_use(def_id); def_native_ty(def_id); def_native_fn(def_id, purity); - def_upvar(def_id, @def, /* writable */bool); + def_upvar(def_id, @def, node_id); // node_id == expr_fn or expr_fn_block } // The set of meta_items that define the compilation environment of the crate, @@ -227,6 +227,7 @@ tag expr_ { expr_do_while(blk, @expr); expr_alt(@expr, [arm]); expr_fn(_fn, @capture_clause); + expr_fn_block(fn_decl, blk); expr_block(blk); /* @@ -261,10 +262,6 @@ tag expr_ { expr_mac(mac); } -// AST nodes that represent a capture clause, which is used to declare -// variables that are copied or moved explicitly into the closure. In some -// cases, local variables can also be copied implicitly into the closure if -// they are used in the closure body. type capture_item = { id: int, name: ident, // Currently, can only capture a local var. diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index e55326dbdcea..c3caa56a9e41 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -145,6 +145,14 @@ fn fold_mac_(m: mac, fld: ast_fold) -> mac { span: m.span}; } +fn fold_fn_decl(decl: ast::fn_decl, fld: ast_fold) -> ast::fn_decl { + ret {inputs: vec::map(decl.inputs, bind fold_arg_(_, fld)), + output: fld.fold_ty(decl.output), + purity: decl.purity, + il: decl.il, + cf: decl.cf, + constraints: vec::map(decl.constraints, fld.fold_constr)} +} fn noop_fold_crate(c: crate_, fld: ast_fold) -> crate_ { let fold_meta_item = bind fold_meta_item_(_, fld); @@ -385,8 +393,10 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ { expr_alt(expr, arms) { expr_alt(fld.fold_expr(expr), vec::map(arms, fld.fold_arm)) } - // NDM fold_captures expr_fn(f, captures) { expr_fn(fld.fold_fn(f), captures) } + expr_fn_block(decl, body) { + expr_fn_block(fold_fn_decl(decl, fld), fld.fold_block(body)) + } expr_block(blk) { expr_block(fld.fold_block(blk)) } expr_move(el, er) { expr_move(fld.fold_expr(el), fld.fold_expr(er)) @@ -437,15 +447,7 @@ fn noop_fold_constr(c: constr_, fld: ast_fold) -> constr_ { // functions just don't get spans, for some reason fn noop_fold_fn(f: _fn, fld: ast_fold) -> _fn { - let fold_arg = bind fold_arg_(_, fld); - - ret {decl: - {inputs: vec::map(f.decl.inputs, fold_arg), - output: fld.fold_ty(f.decl.output), - purity: f.decl.purity, - il: f.decl.il, - cf: f.decl.cf, - constraints: vec::map(f.decl.constraints, fld.fold_constr)}, + ret {decl: fold_fn_decl(f.decl, fld), proto: f.proto, body: fld.fold_block(f.body)}; } diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 43270de40495..0a436a521c9c 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -1317,9 +1317,7 @@ fn parse_fn_block_expr(p: parser) -> @ast::expr { let lo = p.get_last_lo_pos(); let decl = parse_fn_block_decl(p); let body = parse_block_tail(p, lo, ast::default_blk); - let _fn = {decl: decl, proto: ast::proto_block, body: body}; - let captures = @{copies: [], moves: []}; - ret mk_expr(p, lo, body.span.hi, ast::expr_fn(_fn, captures)); + ret mk_expr(p, lo, body.span.hi, ast::expr_fn_block(decl, body)); } fn parse_else_expr(p: parser) -> @ast::expr { diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 92a5d228c26e..5832140b2305 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -827,24 +827,19 @@ fn print_expr(s: ps, &&expr: @ast::expr) { bclose_(s, expr.span, alt_indent_unit); } ast::expr_fn(f, captures) { // NDM captures - - // If the return type is the magic ty_infer, then we need to - // pretty print as a lambda-block - if f.decl.output.node == ast::ty_infer { - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-box, will be closed by print-block at start - ibox(s, 0u); - word(s.s, "{"); - print_fn_block_args(s, f.decl); - print_possibly_embedded_block(s, f.body, block_block_fn, - indent_unit); - } else { - head(s, proto_to_str(f.proto)); - print_fn_args_and_ret(s, f.decl, []); - space(s.s); - print_block(s, f.body); - } + head(s, proto_to_str(f.proto)); + print_fn_args_and_ret(s, f.decl, []); + space(s.s); + print_block(s, f.body); + } + ast::expr_fn_block(decl, body) { + // containing cbox, will be closed by print-block at } + cbox(s, indent_unit); + // head-box, will be closed by print-block at start + ibox(s, 0u); + word(s.s, "{"); + print_fn_block_args(s, decl); + print_possibly_embedded_block(s, body, block_block_fn, indent_unit); } ast::expr_block(blk) { // containing cbox, will be closed by print-block at } diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs index 7ca54272edf3..3f0d7a27a515 100644 --- a/src/comp/syntax/visit.rs +++ b/src/comp/syntax/visit.rs @@ -31,7 +31,15 @@ type visitor = visit_expr: fn@(@expr, E, vt), visit_ty: fn@(@ty, E, vt), visit_constr: fn@(@path, span, node_id, E, vt), - visit_fn: fn@(_fn, [ty_param], span, fn_ident, node_id, E, vt)}; + + // A function with a fully specified prototype: + visit_fn_proto: fn@(_fn, [ty_param], span, fn_ident, node_id, E, vt), + + // Function sugar like { || ... }: + visit_fn_block: fn@(fn_decl, blk, span, node_id, E, vt), + + // Invoked by both visit_fn_proto and visit_fn_block above. + visit_fn_body: fn@(fn_decl, blk, span, fn_ident, node_id, E, vt)}; fn default_visitor() -> visitor { ret @{visit_mod: bind visit_mod::(_, _, _, _), @@ -47,7 +55,9 @@ fn default_visitor() -> visitor { visit_expr: bind visit_expr::(_, _, _), visit_ty: bind skip_ty::(_, _, _), visit_constr: bind visit_constr::(_, _, _, _, _), - visit_fn: bind visit_fn::(_, _, _, _, _, _, _)}; + visit_fn_proto: bind visit_fn_proto::(_, _, _, _, _, _, _), + visit_fn_block: bind visit_fn_block::(_, _, _, _, _, _), + visit_fn_body: bind visit_fn_body::(_, _, _, _, _, _, _)}; } fn visit_crate(c: crate, e: E, v: vt) { @@ -83,7 +93,8 @@ fn visit_local(loc: @local, e: E, v: vt) { fn visit_item(i: @item, e: E, v: vt) { alt i.node { item_const(t, ex) { v.visit_ty(t, e, v); v.visit_expr(ex, e, v); } - item_fn(f, tp) { v.visit_fn(f, tp, i.span, some(i.ident), i.id, e, v); } + item_fn(f, tp) { v.visit_fn_proto(f, tp, i.span, + some(i.ident), i.id, e, v); } item_mod(m) { v.visit_mod(m, i.span, e, v); } item_native_mod(nm) { for vi: @view_item in nm.view_items { v.visit_view_item(vi, e, v); } @@ -91,7 +102,7 @@ fn visit_item(i: @item, e: E, v: vt) { } item_ty(t, _) { v.visit_ty(t, e, v); } item_res(f, dtor_id, tps, _) { - v.visit_fn(f, tps, i.span, some(i.ident), dtor_id, e, v); + v.visit_fn_proto(f, tps, i.span, some(i.ident), dtor_id, e, v); } item_tag(variants, _) { for vr: variant in variants { @@ -101,15 +112,15 @@ fn visit_item(i: @item, e: E, v: vt) { item_obj(ob, _, _) { for f: obj_field in ob.fields { v.visit_ty(f.ty, e, v); } for m: @method in ob.methods { - v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident), - m.node.id, e, v); + v.visit_fn_proto(m.node.meth, m.node.tps, m.span, + some(m.node.ident), m.node.id, e, v); } } item_impl(_, ty, methods) { visit_ty(ty, e, v); for m in methods { - v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident), - m.node.id, e, v); + v.visit_fn_proto(m.node.meth, m.node.tps, m.span, + some(m.node.ident), m.node.id, e, v); } } } @@ -193,10 +204,21 @@ fn visit_fn_decl(fd: fn_decl, e: E, v: vt) { v.visit_ty(fd.output, e, v); } -fn visit_fn(f: _fn, _tp: [ty_param], _sp: span, _i: fn_ident, _id: node_id, - e: E, v: vt) { - visit_fn_decl(f.decl, e, v); - v.visit_block(f.body, e, v); +fn visit_fn_proto(f: _fn, _tp: [ty_param], sp: span, i: fn_ident, + id: node_id, e: E, v: vt) { + v.visit_fn_body(f.decl, f.body, sp, i, id, e, v); +} + +fn visit_fn_block(decl: fn_decl, body: blk, sp: span, id: node_id, + e: E, v: vt) { + v.visit_fn_body(decl, body, sp, option::none, id, e, v); +} + +fn visit_fn_body(decl: fn_decl, body: blk, _sp: span, + _name: fn_ident, _id: node_id, + e: E, v: vt) { + visit_fn_decl(decl, e, v); + v.visit_block(body, e, v); } fn visit_block(b: ast::blk, e: E, v: vt) { @@ -284,8 +306,12 @@ fn visit_expr(ex: @expr, e: E, v: vt) { v.visit_expr(x, e, v); for a: arm in arms { v.visit_arm(a, e, v); } } - // NDM add visit routine? - expr_fn(f, captures) { v.visit_fn(f, [], ex.span, none, ex.id, e, v); } + expr_fn(f, captures) { + v.visit_fn_proto(f, [], ex.span, none, ex.id, e, v); + } + expr_fn_block(decl, body) { + v.visit_fn_block(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); } expr_copy(a) { v.visit_expr(a, e, v); } @@ -324,8 +350,8 @@ fn visit_expr(ex: @expr, e: E, v: vt) { some(ex) { v.visit_expr(ex, e, v); } } for m: @method in anon_obj.methods { - v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident), - m.node.id, e, v); + v.visit_fn_proto(m.node.meth, m.node.tps, m.span, + some(m.node.ident), m.node.id, e, v); } } expr_mac(mac) { visit_mac(mac, e, v); } @@ -357,7 +383,9 @@ type simple_visitor = visit_expr: fn@(@expr), visit_ty: fn@(@ty), visit_constr: fn@(@path, span, node_id), - visit_fn: fn@(_fn, [ty_param], span, fn_ident, node_id)}; + visit_fn_proto: fn@(_fn, [ty_param], span, fn_ident, node_id), + visit_fn_block: fn@(fn_decl, blk, span, node_id), + visit_fn_body: fn@(fn_decl, blk, span, fn_ident, node_id)}; fn simple_ignore_ty(_t: @ty) {} @@ -375,10 +403,15 @@ fn default_simple_visitor() -> simple_visitor { visit_expr: fn(_e: @expr) { }, visit_ty: simple_ignore_ty, visit_constr: fn(_p: @path, _sp: span, _id: node_id) { }, - visit_fn: + visit_fn_proto: fn(_f: _fn, _tps: [ty_param], _sp: span, _ident: fn_ident, - _id: node_id) { - }}; + _id: node_id) { }, + visit_fn_block: + fn(_f: fn_decl, _b: blk, _sp: span, _node_id: node_id) { }, + visit_fn_body: + fn(_f: fn_decl, _b: blk, _sp: span, + _nm: fn_ident, _node_id: node_id) { } + }; } fn mk_simple_visitor(v: simple_visitor) -> vt<()> { @@ -440,7 +473,21 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> { tps: [ty_param], sp: span, ident: fn_ident, id: node_id, &&e: (), v: vt<()>) { f(ff, tps, sp, ident, id); - visit_fn(ff, tps, sp, ident, id, e, v); + visit_fn_proto(ff, tps, sp, ident, id, e, v); + } + fn v_fn_block(f: fn@(fn_decl, blk, span, node_id), + fn_decl: fn_decl, blk: blk, + sp: span, node_id: node_id, + &&e: (), v: vt<()>) { + f(fn_decl, blk, sp, node_id); + visit_fn_block(fn_decl, blk, sp, node_id, e, v); + } + fn v_fn_body(f: fn@(fn_decl, blk, span, fn_ident, node_id), + fn_decl: fn_decl, blk: blk, + sp: span, name: fn_ident, node_id: node_id, + &&e: (), v: vt<()>) { + f(fn_decl, blk, sp, name, node_id); + visit_fn_body(fn_decl, blk, sp, name, node_id, e, v); } let visit_ty = if v.visit_ty == simple_ignore_ty { bind skip_ty(_, _, _) @@ -461,7 +508,13 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> { visit_expr: bind v_expr(v.visit_expr, _, _, _), visit_ty: visit_ty, visit_constr: bind v_constr(v.visit_constr, _, _, _, _, _), - visit_fn: bind v_fn(v.visit_fn, _, _, _, _, _, _, _)}); + visit_fn_proto: + bind v_fn(v.visit_fn_proto, _, _, _, _, _, _, _), + visit_fn_block: + bind v_fn_block(v.visit_fn_block, _, _, _, _, _, _), + visit_fn_body: + bind v_fn_body(v.visit_fn_body, _, _, _, _, _, _, _), + }); } // Local Variables: