diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 75145a89a104a..b19644eb205c5 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -8,6 +8,8 @@ import util::common::ty_mach; import util::common::filename; type ident = str; +// Functions may or may not have names. +type fn_ident = option::t[ident]; type path_ = rec(vec[ident] idents, vec[@ty] types); diff --git a/src/comp/middle/tstate/annotate.rs b/src/comp/middle/tstate/annotate.rs index ef20a58b52f78..8a705be2dcb79 100644 --- a/src/comp/middle/tstate/annotate.rs +++ b/src/comp/middle/tstate/annotate.rs @@ -51,7 +51,7 @@ fn collect_ids_local(&@local l, @mutable vec[node_id] rs) { vec::push(*rs, l.node.id); } -fn node_ids_in_fn(&_fn f, &span sp, &ident i, node_id id, +fn node_ids_in_fn(&_fn f, &span sp, &fn_ident i, node_id id, @mutable vec[node_id] rs) { auto collect_ids = walk::default_visitor(); collect_ids = @@ -69,15 +69,16 @@ fn init_vecs(&crate_ctxt ccx, &vec[node_id] node_ids, uint len) { } } -fn visit_fn(&crate_ctxt ccx, uint num_constraints, &_fn f, &span sp, &ident i, - node_id id) { +fn visit_fn(&crate_ctxt ccx, uint num_constraints, &_fn f, &span sp, + &fn_ident i, node_id id) { let @mutable vec[node_id] node_ids = @mutable []; node_ids_in_fn(f, sp, i, id, node_ids); auto node_id_vec = *node_ids; init_vecs(ccx, node_id_vec, num_constraints); } -fn annotate_in_fn(&crate_ctxt ccx, &_fn f, &span sp, &ident i, node_id id) { +fn annotate_in_fn(&crate_ctxt ccx, &_fn f, &span sp, &fn_ident i, + node_id id) { auto f_info = get_fn_info(ccx, id); visit_fn(ccx, num_constraints(f_info), f, sp, i, id); } diff --git a/src/comp/middle/tstate/ck.rs b/src/comp/middle/tstate/ck.rs index 444880e02cacd..93b2c5326b167 100644 --- a/src/comp/middle/tstate/ck.rs +++ b/src/comp/middle/tstate/ck.rs @@ -8,6 +8,7 @@ import front::ast::obj_field; import front::ast::_obj; import front::ast::stmt; import front::ast::ident; +import front::ast::fn_ident; import front::ast::node_id; import front::ast::def_id; import front::ast::local_def; @@ -120,7 +121,7 @@ fn check_states_stmt(&fn_ctxt fcx, &@stmt s) { } fn check_states_against_conditions(&fn_ctxt fcx, &_fn f, node_id id, - &span sp, &ident i) { + &span sp, &fn_ident i) { /* Postorder traversal instead of pre is important because we want the smallest possible erroneous statement or expression. */ @@ -172,7 +173,7 @@ fn check_states_against_conditions(&fn_ctxt fcx, &_fn f, node_id id, } } -fn check_fn_states(&fn_ctxt fcx, &_fn f, node_id id, &span sp, &ident i) { +fn check_fn_states(&fn_ctxt fcx, &_fn f, node_id id, &span sp, &fn_ident i) { /* Compute the pre- and post-states for this function */ auto g = find_pre_post_state_fn; @@ -183,12 +184,13 @@ fn check_fn_states(&fn_ctxt fcx, &_fn f, node_id id, &span sp, &ident i) { check_states_against_conditions(fcx, f, id, sp, i); } -fn fn_states(&crate_ctxt ccx, &_fn f, &span sp, &ident i, node_id id) { +fn fn_states(&crate_ctxt ccx, &_fn f, &span sp, &fn_ident i, node_id id) { /* Look up the var-to-bit-num map for this function */ assert (ccx.fm.contains_key(id)); auto f_info = ccx.fm.get(id); - auto fcx = rec(enclosing=f_info, id=id, name=i, ccx=ccx); + auto name = option::from_maybe("anon", i); + auto fcx = rec(enclosing=f_info, id=id, name=name, ccx=ccx); check_fn_states(fcx, f, id, sp, i); } diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs index eed418578ebdd..2a23dac596b31 100644 --- a/src/comp/middle/tstate/collect_locals.rs +++ b/src/comp/middle/tstate/collect_locals.rs @@ -3,6 +3,7 @@ import std::vec; import std::vec::plus_option; import front::ast; import front::ast::*; +import pretty::ppaux::fn_ident_to_string; import std::option::*; import middle::walk::walk_crate; import middle::walk::walk_fn; @@ -56,7 +57,7 @@ fn collect_pred(&ctxt cx, &@expr e) { } } -fn find_locals(&ty::ctxt tcx, &_fn f, &span sp, &ident i, node_id id) +fn find_locals(&ty::ctxt tcx, &_fn f, &span sp, &fn_ident i, node_id id) -> ctxt { let ctxt cx = rec(cs=@mutable vec::alloc(0u), tcx=tcx); auto visitor = walk::default_visitor(); @@ -103,7 +104,7 @@ fn add_constraint(&ty::ctxt tcx, aux::constr c, uint next, constr_map tbl) -> /* builds a table mapping each local var defined in f to a bit number in the precondition/postcondition vectors */ -fn mk_fn_info(&crate_ctxt ccx, &_fn f, &span f_sp, &ident f_name, +fn mk_fn_info(&crate_ctxt ccx, &_fn f, &span f_sp, &fn_ident f_name, node_id id) { auto res_map = @new_int_hash[constraint](); let uint next = 0u; @@ -121,14 +122,15 @@ fn mk_fn_info(&crate_ctxt ccx, &_fn f, &span f_sp, &ident f_name, /* add a pseudo-entry for the function's return value we can safely use the function's name itself for this purpose */ - add_constraint(cx.tcx, respan(f_sp, rec(id=id, c=ninit(f_name))), next, + auto name = fn_ident_to_string(id, f_name); + add_constraint(cx.tcx, respan(f_sp, rec(id=id, c=ninit(name))), next, res_map); auto rslt = rec(constrs=res_map, num_constraints=vec::len(*cx.cs) + 1u, cf=f.decl.cf); ccx.fm.insert(id, rslt); - log f_name + " has " + uistr(num_constraints(rslt)) + " constraints"; + log name + " has " + uistr(num_constraints(rslt)) + " constraints"; } diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 8d75c6cdb0a26..47b41f27e3ec6 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -78,6 +78,7 @@ import util::common::log_expr_err; import util::common::log_block_err; import util::common::log_block; import util::common::span; +import pretty::ppaux::fn_ident_to_string; fn find_pre_post_mod(&_mod m) -> _mod { log "implement find_pre_post_mod!"; @@ -686,10 +687,11 @@ fn find_pre_post_fn(&fn_ctxt fcx, &_fn f) { } } -fn fn_pre_post(crate_ctxt ccx, &_fn f, &span sp, &ident i, node_id id) { +fn fn_pre_post(crate_ctxt ccx, &_fn f, &span sp, &fn_ident i, + node_id id) { assert (ccx.fm.contains_key(id)); - auto fcx = rec(enclosing=ccx.fm.get(id), id=id, name=i, - ccx=ccx); + auto fcx = rec(enclosing=ccx.fm.get(id), id=id, + name=fn_ident_to_string(id, i), ccx=ccx); find_pre_post_fn(fcx, f); } // diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 1d3cd16557877..353eb3997dfb2 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -966,13 +966,8 @@ mod writeback { fn visit_stmt_pre(@fn_ctxt fcx, &@ast::stmt s) { resolve_type_vars_for_node(fcx, s.span, ty::stmt_node_id(s)); } - fn visit_expr_pre(@mutable bool ignore, @fn_ctxt fcx, &@ast::expr e) { + fn visit_expr_pre(@fn_ctxt fcx, &@ast::expr e) { resolve_type_vars_for_node(fcx, e.span, e.id); - alt (e.node) { - // We don't want to recurse down into lambdas. - case (ast::expr_fn(_)) { *ignore = true; } - case (_) { } - } } fn visit_expr_post(@mutable bool ignore, &@ast::expr e) { *ignore = false; @@ -1000,8 +995,7 @@ mod writeback { } } fn resolve_type_vars_in_block(&@fn_ctxt fcx, &ast::block block) { - // A trick to ignore any contained items. - + // A trick to ignore any contained items and lambdas. auto ignore = @mutable false; fn visit_item_pre(@mutable bool ignore, &@ast::item item) { *ignore = true; @@ -1009,14 +1003,23 @@ mod writeback { fn visit_item_post(@mutable bool ignore, &@ast::item item) { *ignore = false; } + fn visit_fn_pre(@mutable bool ignore, &ast::_fn f, &span sp, + &ast::fn_ident i, ast::node_id d) { + *ignore = true; + } + fn visit_fn_post(@mutable bool ignore, &ast::_fn f, &span sp, + &ast::fn_ident i, ast::node_id d) { + *ignore = false; + } fn keep_going(@mutable bool ignore) -> bool { ret !*ignore; } auto visit = rec(keep_going=bind keep_going(ignore), visit_item_pre=bind visit_item_pre(ignore, _), visit_item_post=bind visit_item_post(ignore, _), + visit_fn_pre=bind visit_fn_pre(ignore, _, _, _, _), + visit_fn_post=bind visit_fn_post(ignore, _, _, _, _), visit_stmt_pre=bind visit_stmt_pre(fcx, _), - visit_expr_pre=bind visit_expr_pre(ignore, fcx, _), - visit_expr_post=bind visit_expr_post(ignore, _), + visit_expr_pre=bind visit_expr_pre(fcx, _), visit_block_pre=bind visit_block_pre(fcx, _), visit_pat_pre=bind visit_pat_pre(fcx, _), visit_local_pre=bind visit_local_pre(fcx, _) diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index 89df2668421ae..d2e9343a33d53 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -6,8 +6,6 @@ import std::option::none; import util::common::span; import util::common::respan; - -// FIXME: Should visit patterns as well. type ast_visitor = rec(fn() -> bool keep_going, fn() -> bool want_crate_directives, @@ -40,8 +38,8 @@ type ast_visitor = fn(&@ast::ty) visit_ty_pre, fn(&@ast::ty) visit_ty_post, fn(&@ast::constr) visit_constr, - fn(&ast::_fn, &span, &ast::ident, ast::node_id) visit_fn_pre, - fn(&ast::_fn, &span, &ast::ident, ast::node_id) visit_fn_post); + fn(&ast::_fn, &span, &ast::fn_ident, ast::node_id) visit_fn_pre, + fn(&ast::_fn, &span, &ast::fn_ident, ast::node_id) visit_fn_post); fn walk_crate(&ast_visitor v, &ast::crate c) { if (!v.keep_going()) { ret; } @@ -102,7 +100,7 @@ fn walk_item(&ast_visitor v, @ast::item i) { alt (i.node) { case (ast::item_const(?t, ?e)) { walk_ty(v, t); walk_expr(v, e); } case (ast::item_fn(?f, _)) { - walk_fn(v, f, i.span, i.ident, i.id); + walk_fn(v, f, i.span, some(i.ident), i.id); } case (ast::item_mod(?m)) { walk_mod(v, m); } case (ast::item_native_mod(?nm)) { walk_native_mod(v, nm); } @@ -118,13 +116,15 @@ fn walk_item(&ast_visitor v, @ast::item i) { for (ast::obj_field f in ob.fields) { walk_ty(v, f.ty); } for (@ast::method m in ob.methods) { v.visit_method_pre(m); - walk_fn(v, m.node.meth, m.span, m.node.ident, m.node.id); + walk_fn(v, m.node.meth, m.span, + some(m.node.ident), m.node.id); v.visit_method_post(m); } alt (ob.dtor) { case (none) { } case (some(?m)) { - walk_fn(v, m.node.meth, m.span, m.node.ident, m.node.id); + walk_fn(v, m.node.meth, m.span, + some(m.node.ident), m.node.id); } } } @@ -217,7 +217,7 @@ fn walk_fn_decl(&ast_visitor v, &ast::fn_decl fd) { walk_ty(v, fd.output); } -fn walk_fn(&ast_visitor v, &ast::_fn f, &span sp, &ast::ident i, +fn walk_fn(&ast_visitor v, &ast::_fn f, &span sp, &ast::fn_ident i, ast::node_id d) { if (!v.keep_going()) { ret; } v.visit_fn_pre(f, sp, i, d); @@ -340,8 +340,7 @@ fn walk_expr(&ast_visitor v, @ast::expr e) { } } case (ast::expr_fn(?f)) { - walk_fn_decl(v, f.decl); - walk_block(v, f.body); + walk_fn(v, f, e.span, none, e.id); } case (ast::expr_block(?b)) { walk_block(v, b); } case (ast::expr_assign(?a, ?b)) { @@ -405,7 +404,8 @@ fn walk_expr(&ast_visitor v, @ast::expr e) { // Methods for (@ast::method m in anon_obj.methods) { v.visit_method_pre(m); - walk_fn(v, m.node.meth, m.span, m.node.ident, m.node.id); + walk_fn(v, m.node.meth, m.span, some(m.node.ident), + m.node.id); v.visit_method_post(m); } } @@ -447,7 +447,7 @@ fn def_visit_ty(&@ast::ty t) { } fn def_visit_constr(&@ast::constr c) { } -fn def_visit_fn(&ast::_fn f, &span sp, &ast::ident i, ast::node_id d) { } +fn def_visit_fn(&ast::_fn f, &span sp, &ast::fn_ident i, ast::node_id d) { } fn default_visitor() -> ast_visitor { ret rec(keep_going=def_keep_going, diff --git a/src/comp/pretty/ppaux.rs b/src/comp/pretty/ppaux.rs index 97c932cdd5fff..c3534a9e8bdad 100644 --- a/src/comp/pretty/ppaux.rs +++ b/src/comp/pretty/ppaux.rs @@ -34,6 +34,13 @@ fn mode_str_1(&ty::mode m) -> str { } } +fn fn_ident_to_string(ast::node_id id, &ast::fn_ident i) -> str { + ret alt (i) { + case (none) { "anon" + istr(id) } + case (some(?s)) { s } + }; +} + fn ty_to_str(&ctxt cx, &t typ) -> str { fn fn_input_to_str(&ctxt cx, &rec(middle::ty::mode mode, t ty) input) -> str { diff --git a/src/test/compile-fail/fn-expr-type-state.rs b/src/test/compile-fail/fn-expr-type-state.rs new file mode 100644 index 0000000000000..ac9489a1290ac --- /dev/null +++ b/src/test/compile-fail/fn-expr-type-state.rs @@ -0,0 +1,11 @@ +// error-pattern:Unsatisfied precondition +// xfail-stage0 + +fn main() { + // Typestate should work even in a lambda. we should reject this program. + auto f = fn () -> int { + let int i; + ret i; + }; + log_err f(); +}