Implement function expressions/anonymous functions
Looks like 'fn(..arg..) -> ret {body;}. They don't support type
parameters or upvars yet.
This commit is contained in:
parent
8c06d1bcb0
commit
471436a299
12 changed files with 114 additions and 30 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue