diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 66ee43e991d4..84a6bc9d2e65 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -271,6 +271,7 @@ tag expr_ { expr_for_each(@local, @expr, block, ann); expr_do_while(block, @expr, ann); expr_alt(@expr, vec[arm], ann); + expr_fn(_fn, ann); expr_block(block, ann); expr_move(@expr /* TODO: @expr|is_lval */, @expr, ann); expr_assign(@expr /* TODO: @expr|is_lval */, @expr, ann); diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 68d57b87340c..258966ff0523 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -815,7 +815,8 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { ret parse_alt_expr(p); } else if (eat_word(p, "spawn")) { ret parse_spawn_expr(p); - + } else if (eat_word(p, "fn")) { + ret parse_fn_expr(p); } else if (eat_word(p, "tup")) { fn parse_elt(&parser p) -> ast::elt { auto m = parse_mutability(p); @@ -1114,8 +1115,11 @@ fn parse_self_method(&parser p) -> @ast::expr { } fn parse_dot_or_call_expr(&parser p) -> @ast::expr { - auto lo = p.get_lo_pos(); - auto e = parse_bottom_expr(p); + ret parse_dot_or_call_expr_with(p, parse_bottom_expr(p)); +} + +fn parse_dot_or_call_expr_with(&parser p, @ast::expr e) -> @ast::expr { + auto lo = e.span.lo; auto hi = e.span.hi; while (true) { alt (p.peek()) { @@ -1357,6 +1361,14 @@ fn parse_if_expr(&parser p) -> @ast::expr { ret @spanned(lo, hi, ast::expr_if(cond, thn, els, p.get_ann())); } +fn parse_fn_expr(&parser p) -> @ast::expr { + auto lo = p.get_last_lo_pos(); + auto decl = parse_fn_decl(p, ast::impure_fn); + auto body = parse_block(p); + auto _fn = rec(decl=decl, proto=ast::proto_fn, body=body); + ret @spanned(lo, body.span.hi, ast::expr_fn(_fn, p.get_ann())); +} + fn parse_else_expr(&parser p) -> @ast::expr { if (eat_word(p, "if")) { ret parse_if_expr(p); @@ -1630,10 +1642,14 @@ fn parse_source_stmt(&parser p) -> @ast::stmt { auto decl = @spanned(lo, hi, ast::decl_item(i)); ret @spanned(lo, hi, ast::stmt_decl(decl, p.get_ann())); } + case (fn_no_item) { // parse_item will have already skipped "fn" + auto e = parse_fn_expr(p); + e = parse_dot_or_call_expr_with(p, e); + ret @spanned(lo, e.span.hi, ast::stmt_expr(e, p.get_ann())); + } case (no_item) { // Remainder are line-expr stmts. auto e = parse_expr(p); - auto hi = p.get_span(); ret @spanned(lo, e.span.hi, ast::stmt_expr(e, p.get_ann())); } } @@ -1676,6 +1692,7 @@ fn stmt_ends_with_semi(&ast::stmt stmt) -> bool { case (ast::expr_while(_,_,_)) { ret false; } case (ast::expr_do_while(_,_,_)) { ret false; } case (ast::expr_alt(_,_,_)) { ret false; } + case (ast::expr_fn(_,_)) { ret false; } case (ast::expr_block(_,_)) { ret false; } case (ast::expr_assign(_,_,_)) { ret true; } case (ast::expr_assign_op(_,_,_,_)) @@ -2152,16 +2169,18 @@ fn parse_auth(&parser p) -> ast::_auth { fail; } -// FIXME will be extended to help parse anon functions tag parsed_item { got_item(@ast::item); no_item; + fn_no_item; } fn parse_item(&parser p) -> parsed_item { if (eat_word(p, "const")) { ret got_item(parse_item_const(p)); } else if (eat_word(p, "fn")) { + // This is an anonymous function + if (p.peek() == token::LPAREN) { ret fn_no_item; } ret got_item(parse_item_fn_or_iter(p, ast::impure_fn, ast::proto_fn)); } else if (eat_word(p, "pred")) { ret got_item(parse_item_fn_or_iter(p, ast::pure_fn, ast::proto_fn)); diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 0230de83f1a4..01570dc7789b 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -346,6 +346,9 @@ fn visit_expr_with_scope(&@ast::expr x, &scopes sc, &vt[scopes] v) { case (ast::expr_for_each(?d, _, _, _)) { cons[scope](scope_loop(d.node), @sc) } + case (ast::expr_fn(?f, _)) { + cons(scope_fn(f.decl, []), @sc) + } case (_) { sc } }; visit::visit_expr(x, new_sc, v); diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index c1ec7fa338a1..4f4fc19c62fc 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -6020,6 +6020,22 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) cx, ann, output); } + case (ast::expr_fn(?f, ?ann)) { + auto ccx = cx.fcx.lcx.ccx; + let TypeRef llfnty = alt (ty::struct(ccx.tcx, + node_ann_type(ccx, ann))) { + case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) { + type_of_fn_full(ccx, e.span, proto, none, inputs, + output, 0u) + } + }; + auto sub_cx = extend_path(cx.fcx.lcx, ccx.names.next("anon")); + auto s = mangle_internal_name_by_path(ccx, sub_cx.path); + auto llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfnty); + trans_fn(sub_cx, e.span, f, llfn, none, [], ann); + ret res(cx, create_fn_pair(ccx, s, llfnty, llfn, false)); + } + case (ast::expr_block(?blk, ?ann)) { *cx = rec(sp=blk.span with *cx); auto sub_cx = new_scope_block_ctxt(cx, "block-expr body"); @@ -7668,10 +7684,9 @@ fn finish_fn(&@fn_ctxt fcx, BasicBlockRef lltop) { // trans_fn: creates an LLVM function corresponding to a source language // function. -fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ast::def_id fid, +fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ValueRef llfndecl, option::t[ty_self_pair] ty_self, &vec[ast::ty_param] ty_params, &ast::ann ann) { - auto llfndecl = cx.ccx.item_ids.get(fid); set_uwtable(llfndecl); // Set up arguments to the function. @@ -7765,7 +7780,7 @@ fn create_vtbl(@local_ctxt cx, cx.ccx.item_ids.insert(m.node.id, llfn); cx.ccx.item_symbols.insert(m.node.id, s); - trans_fn(mcx, m.span, m.node.meth, m.node.id, + trans_fn(mcx, m.span, m.node.meth, llfn, some[ty_self_pair](tup(llself_ty, self_ty)), ty_params, m.node.ann); methods += [llfn]; @@ -7794,7 +7809,7 @@ fn trans_dtor(@local_ctxt cx, cx.ccx.item_ids.insert(dtor.node.id, llfn); cx.ccx.item_symbols.insert(dtor.node.id, s); - trans_fn(cx, dtor.span, dtor.node.meth, dtor.node.id, + trans_fn(cx, dtor.span, dtor.node.meth, llfn, some[ty_self_pair](tup(llself_ty, self_ty)), ty_params, dtor.node.ann); @@ -8119,7 +8134,8 @@ fn trans_item(@local_ctxt cx, &ast::item item) { alt (item.node) { case (ast::item_fn(?name, ?f, ?tps, ?fid, ?ann)) { auto sub_cx = extend_path(cx, name); - trans_fn(sub_cx, item.span, f, fid, none[ty_self_pair], + auto llfndecl = cx.ccx.item_ids.get(fid); + trans_fn(sub_cx, item.span, f, llfndecl, none[ty_self_pair], tps, ann); } case (ast::item_obj(?name, ?ob, ?tps, ?oid, ?ann)) { @@ -8168,12 +8184,10 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, ast::def_id id) { auto llfty; - auto llpairty; alt (ty::struct(ccx.tcx, node_ann_type(ccx, ann))) { case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) { llfty = type_of_fn(ccx, sp, proto, inputs, output, vec::len[ast::ty_param](ty_params)); - llpairty = T_fn_pair(ccx.tn, llfty); } case (_) { ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!"); @@ -8192,7 +8206,7 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, // Declare the global constant pair that points to it. let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann)); - register_fn_pair(ccx, ps, llpairty, llfn, id); + register_fn_pair(ccx, ps, llfty, llfn, id); if (is_main) { if (ccx.main_fn != none[ValueRef]) { @@ -8205,22 +8219,25 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, } -fn register_fn_pair(&@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn, - ast::def_id id) { - let ValueRef gvar = llvm::LLVMAddGlobal(cx.llmod, llpairty, - str::buf(ps)); - auto pair = C_struct([llfn, - C_null(T_opaque_closure_ptr(cx.tn))]); - +fn create_fn_pair(&@crate_ctxt cx, str ps, TypeRef llfnty, ValueRef llfn, + bool external) -> ValueRef { + auto gvar = llvm::LLVMAddGlobal + (cx.llmod, T_fn_pair(cx.tn, llfnty), str::buf(ps)); + auto pair = C_struct([llfn, C_null(T_opaque_closure_ptr(cx.tn))]); llvm::LLVMSetInitializer(gvar, pair); llvm::LLVMSetGlobalConstant(gvar, True); - - // FIXME: We should also hide the unexported pairs in crates. - if (!cx.sess.get_opts().shared) { + if (!external) { llvm::LLVMSetLinkage(gvar, lib::llvm::LLVMInternalLinkage as llvm::Linkage); } + ret gvar; +} +fn register_fn_pair(&@crate_ctxt cx, str ps, TypeRef llfnty, ValueRef llfn, + ast::def_id id) { + // FIXME: We should also hide the unexported pairs in crates. + auto gvar = create_fn_pair(cx, ps, llfnty, llfn, + cx.sess.get_opts().shared); cx.item_ids.insert(id, llfn); cx.item_symbols.insert(id, ps); cx.fn_pairs.insert(id, gvar); @@ -8268,10 +8285,9 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, wrapper_type); // Declare the global constant pair that points to it. - auto wrapper_pair_type = T_fn_pair(ccx.tn, wrapper_type); let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann)); - register_fn_pair(ccx, ps, wrapper_pair_type, wrapper_fn, id); + register_fn_pair(ccx, ps, wrapper_type, wrapper_fn, id); // Build the wrapper. auto fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, wrapper_fn); diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 5eafeb8a1a52..7d45e3f16ad0 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -301,6 +301,10 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () { } } } + // FIXME this was just put in here as a placeholder + case (expr_fn(?f, ?a)) { + clear_pp(expr_pp(fcx.ccx, e)); + } case (expr_block(?b, ?a)) { find_pre_post_block(fcx, b); auto p = block_pp(fcx.ccx, b); diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index e89fd1a6a838..3fd160d6a647 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -223,6 +223,10 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool { case (expr_lit(?l,?a)) { ret pure_exp(fcx.ccx, a, pres); } + // FIXME This was just put in here as a placeholder + case (expr_fn(?f,?a)) { + ret pure_exp(fcx.ccx, a, pres); + } case (expr_block(?b,?a)) { changed = find_pre_post_state_block(fcx, pres, b) || changed; diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index c72f58d1265e..0cb239560186 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1662,6 +1662,7 @@ fn expr_ann(&@ast::expr e) -> ast::ann { case (ast::expr_for_each(_,_,_,?a)) { ret a; } case (ast::expr_do_while(_,_,?a)) { ret a; } case (ast::expr_alt(_,_,?a)) { ret a; } + case (ast::expr_fn(_,?a)) { ret a; } case (ast::expr_block(_,?a)) { ret a; } case (ast::expr_move(_,_,?a)) { ret a; } case (ast::expr_assign(_,_,?a)) { ret a; } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 99dfe96da62a..2a879bbfd578 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -474,14 +474,18 @@ mod collect { &ast::fn_decl decl, ast::proto proto, &vec[ast::ty_param] ty_params, - &ast::def_id def_id) -> ty::ty_param_count_and_ty { + &option::t[ast::def_id] def_id) + -> ty::ty_param_count_and_ty { auto input_tys = vec::map[ast::arg,arg](ty_of_arg, decl.inputs); auto output_ty = convert(decl.output); auto t_fn = ty::mk_fn(cx.tcx, proto, input_tys, output_ty, decl.cf, decl.constraints); auto ty_param_count = vec::len[ast::ty_param](ty_params); auto tpt = tup(ty_param_count, t_fn); - cx.tcx.tcache.insert(def_id, tpt); + alt (def_id) { + case (some(?did)) { cx.tcx.tcache.insert(did, tpt); } + case (_) {} + } ret tpt; } @@ -589,7 +593,7 @@ mod collect { case (ast::item_fn(?ident, ?fn_info, ?tps, ?def_id, _)) { auto f = bind ty_of_arg(cx, _); ret ty_of_fn_decl(cx, convert, f, fn_info.decl, fn_info.proto, - tps, def_id); + tps, some(def_id)); } case (ast::item_obj(?ident, ?obj_info, ?tps, ?odid, _)) { @@ -1897,6 +1901,17 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { write::ty_only_fixup(fcx, a.id, result_ty); } + case (ast::expr_fn(?f, ?a)) { + auto cx = @rec(tcx = fcx.ccx.tcx); + auto convert = bind ast_ty_to_ty + (cx.tcx, bind collect::getter(cx, _), _); + auto ty_of_arg = bind collect::ty_of_arg(cx, _); + auto fty = collect::ty_of_fn_decl(cx, convert, ty_of_arg, + f.decl, f.proto, [], none)._1; + write::ty_only_fixup(fcx, a.id, fty); + check_fn(fcx.ccx, f.decl, f.proto, f.body, a); + } + case (ast::expr_block(?b, ?a)) { check_block(fcx, b); alt (b.node.expr) { diff --git a/src/comp/middle/visit.rs b/src/comp/middle/visit.rs index 586ff0397bce..5ede53356439 100644 --- a/src/comp/middle/visit.rs +++ b/src/comp/middle/visit.rs @@ -335,6 +335,10 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) { vt(v).visit_arm(a, e, v); } } + case (expr_fn(?f, _)) { + visit_fn_decl(f.decl, e, v); + vt(v).visit_block(f.body, e, v); + } case (expr_block(?b, _)) { vt(v).visit_block(b, e, v); } diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index 3c184eacfb42..f6f7d7d77bce 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -410,6 +410,10 @@ fn walk_expr(&ast_visitor v, @ast::expr e) { v.visit_arm_post(a); } } + case (ast::expr_fn(?f, ?a)) { + walk_fn_decl(v, f.decl); + walk_block(v, f.body); + } case (ast::expr_block(?b, _)) { walk_block(v, b); } diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index c4c48c234d0c..c5bfe230fc14 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -671,6 +671,12 @@ fn print_expr(&ps s, &@ast::expr expr) { } bclose(s, expr.span); } + case (ast::expr_fn(?f, _)) { + head(s, "fn"); + print_fn_args_and_ret(s, f.decl); + space(s.s); + print_block(s, f.body); + } case (ast::expr_block(?block,_)) { // containing cbox, will be closed by print-block at } cbox(s, indent_unit); @@ -954,6 +960,10 @@ fn print_fn(&ps s, ast::fn_decl decl, ast::proto proto, str name, } word(s.s, name); print_type_params(s, typarams); + print_fn_args_and_ret(s, decl); +} + +fn print_fn_args_and_ret(&ps s, &ast::fn_decl decl) { popen(s); fn print_arg(&ps s, &ast::arg x) { ibox(s, indent_unit); @@ -963,8 +973,7 @@ fn print_fn(&ps s, ast::fn_decl decl, ast::proto proto, str name, word(s.s, x.ident); end(s); } - auto f = print_arg; - commasep[ast::arg](s, inconsistent, decl.inputs, f); + commasep[ast::arg](s, inconsistent, decl.inputs, print_arg); pclose(s); maybe_print_comment(s, decl.output.span.lo); if (decl.output.node != ast::ty_nil) { diff --git a/src/test/run-pass/fn-expr.rs b/src/test/run-pass/fn-expr.rs new file mode 100644 index 000000000000..8e87eb80ddee --- /dev/null +++ b/src/test/run-pass/fn-expr.rs @@ -0,0 +1,4 @@ +fn main() { + auto x = fn(int a) -> int { ret a + 1; }; + assert (x(4) == 5); +}