Skip to content

Commit ac948b4

Browse files
committed
Resolve and typecheck alias-environment-capturing blocks.
1 parent 8c8fa79 commit ac948b4

File tree

5 files changed

+107
-34
lines changed

5 files changed

+107
-34
lines changed

src/comp/metadata/tydecode.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,11 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
250250
ret ty::mk_fn(st.tcx, ast::proto_iter, func.args, func.ty,
251251
func.cf, func.cs);
252252
}
253+
case ('B') {
254+
auto func = parse_ty_fn(st, sd);
255+
ret ty::mk_fn(st.tcx, ast::proto_block, func.args, func.ty,
256+
func.cf, func.cs);
257+
}
253258
case ('N') {
254259
auto abi;
255260
alt (next(st) as char) {

src/comp/metadata/tyencode.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ fn enc_proto(&ioivec::writer w, proto proto) {
200200
alt (proto) {
201201
case (proto_iter) { w.write_char('W'); }
202202
case (proto_fn) { w.write_char('F'); }
203+
case (proto_block) { w.write_char('B'); }
203204
}
204205
}
205206

src/comp/middle/resolve.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export def_map;
4949
tag scope {
5050
scope_crate;
5151
scope_item(@ast::item);
52-
scope_fn(ast::fn_decl, ast::ty_param[]);
52+
scope_fn(ast::fn_decl, ast::proto, ast::ty_param[]);
5353
scope_native_item(@ast::native_item);
5454
scope_loop(@ast::local); // there's only 1 decl per loop.
5555
scope_block(ast::blk);
@@ -360,7 +360,7 @@ fn visit_fn_with_scope(&@env e, &ast::_fn f, &ast::ty_param[] tp, &span sp,
360360
resolve_constr(e, id, c, sc, v);
361361
}
362362
visit::visit_fn(f, tp, sp, name, id,
363-
cons(scope_fn(f.decl, tp), @sc), v);
363+
cons(scope_fn(f.decl, f.proto, tp), @sc), v);
364364
}
365365

366366
fn visit_block_with_scope(&ast::blk b, &scopes sc, &vt[scopes] v) {
@@ -381,7 +381,7 @@ fn visit_expr_with_scope(&@ast::expr x, &scopes sc, &vt[scopes] v) {
381381
v.visit_block(blk, new_sc, v);
382382
}
383383
ast::expr_fn(?f) {
384-
visit::visit_expr(x, cons(scope_fn(f.decl, ~[]), @sc), v);
384+
visit::visit_expr(x, cons(scope_fn(f.decl, f.proto, ~[]), @sc), v);
385385
}
386386
_ { visit::visit_expr(x, sc, v); }
387387
};
@@ -536,7 +536,7 @@ fn unresolved_err(&env e, &scopes sc, &span sp, &ident name, &str kind) {
536536
alt sc {
537537
cons(?cur, ?rest) {
538538
alt cur {
539-
scope_crate | scope_fn(_, _) |
539+
scope_crate | scope_fn(_, _, _) |
540540
scope_item(@{node: ast::item_mod(_), _}) {
541541
ret cur;
542542
}
@@ -602,9 +602,11 @@ fn lookup_in_scope_strict(&env e, scopes sc, &span sp, &ident name,
602602

603603
fn scope_is_fn(&scope sc) -> bool {
604604
ret alt (sc) {
605-
scope_fn(_, _) | scope_native_item(_) { true }
606-
_ { false }
607-
};
605+
scope_fn(_, ast::proto_iter, _) |
606+
scope_fn(_, ast::proto_fn, _) |
607+
scope_native_item(_) { true }
608+
_ { false }
609+
};
608610
}
609611

610612
fn def_is_local(&def d) -> bool {
@@ -663,7 +665,7 @@ fn lookup_in_scope(&env e, scopes sc, &span sp, &ident name, namespace ns) ->
663665
}
664666
}
665667
}
666-
case (scope_fn(?decl, ?ty_params)) {
668+
case (scope_fn(?decl, _, ?ty_params)) {
667669
ret lookup_in_fn(name, decl, ty_params, ns);
668670
}
669671
case (scope_loop(?local)) {

src/comp/middle/ty.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,7 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool {
889889
fn type_is_copyable(&ctxt cx, &t ty) -> bool {
890890
ret alt (struct(cx, ty)) {
891891
case (ty_res(_, _, _)) { false }
892+
case (ty_fn(proto_block, _, _, _, _)) { false }
892893
case (_) { true }
893894
};
894895
}

src/comp/middle/typeck.rs

Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,13 @@ type crate_ctxt = rec(mutable obj_info[] obj_infos, ty::ctxt tcx);
6565
type fn_ctxt =
6666
rec(ty::t ret_ty,
6767
ast::purity purity,
68+
// var_bindings, locals, local_names, and next_var_id are shared
69+
// with any nested functions that capture the environment
70+
// (and with any functions whose environment is being captured).
6871
@ty::unify::var_bindings var_bindings,
6972
hashmap[ast::node_id, int] locals,
7073
hashmap[ast::node_id, ast::ident] local_names,
71-
mutable int next_var_id,
74+
@mutable int next_var_id,
7275
mutable ast::node_id[] fixups,
7376
@crate_ctxt ccx);
7477

@@ -237,6 +240,18 @@ fn structure_of(&@fn_ctxt fcx, &span sp, ty::t typ) -> ty::sty {
237240
ret ty::struct(fcx.ccx.tcx, structurally_resolved_type(fcx, sp, typ));
238241
}
239242

243+
// Returns the one-level-deep structure of the given type or none if it
244+
// is not known yet.
245+
fn structure_of_maybe(&@fn_ctxt fcx, &span sp, ty::t typ)
246+
-> option::t[ty::sty] {
247+
auto r =
248+
ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings, typ);
249+
ret alt (r) {
250+
case (fix_ok(?typ_s)) { some(ty::struct(fcx.ccx.tcx, typ_s)) }
251+
case (fix_err(_)) { none }
252+
}
253+
}
254+
240255
fn type_is_integral(&@fn_ctxt fcx, &span sp, ty::t typ) -> bool {
241256
auto typ_s = structurally_resolved_type(fcx, sp, typ);
242257
ret ty::type_is_integral(fcx.ccx.tcx, typ_s);
@@ -470,6 +485,15 @@ mod write {
470485
}
471486
}
472487

488+
// Determine the proto for a fn type given the proto for its associated
489+
// code. This is needed because fn and lambda have fn type while iter
490+
// has iter type and block has block type. This may end up changing.
491+
fn proto_to_ty_proto(&ast::proto proto) -> ast::proto {
492+
ret alt (proto) {
493+
ast::proto_iter | ast::proto_block { proto }
494+
_ { ast::proto_fn }
495+
};
496+
}
473497

474498
// Item collection - a pair of bootstrap passes:
475499
//
@@ -511,8 +535,8 @@ mod collect {
511535
out_constrs += ~[ty::ast_constr_to_constr(cx.tcx, constr)];
512536
}
513537
auto t_fn =
514-
ty::mk_fn(cx.tcx, proto, input_tys, output_ty, decl.cf,
515-
out_constrs);
538+
ty::mk_fn(cx.tcx, proto_to_ty_proto(proto), input_tys,
539+
output_ty, decl.cf, out_constrs);
516540
auto ty_param_count = ivec::len[ast::ty_param](ty_params);
517541
auto tpt = rec(count=ty_param_count, ty=t_fn);
518542
alt (def_id) {
@@ -590,9 +614,9 @@ mod collect {
590614
for (@ast::constr constr in m.node.meth.decl.constraints) {
591615
out_constrs += ~[ty::ast_constr_to_constr(cx.tcx, constr)];
592616
}
593-
ret rec(proto=m.node.meth.proto, ident=m.node.ident,
594-
inputs=inputs, output=output, cf=m.node.meth.decl.cf,
595-
constrs=out_constrs);
617+
ret rec(proto=proto_to_ty_proto(m.node.meth.proto),
618+
ident=m.node.ident, inputs=inputs, output=output,
619+
cf=m.node.meth.decl.cf, constrs=out_constrs);
596620
}
597621
fn ty_of_obj(@ctxt cx, &ast::ident id, &ast::_obj ob,
598622
&ast::ty_param[] ty_params) -> ty::ty_param_count_and_ty {
@@ -872,7 +896,7 @@ mod unify {
872896
}
873897
}
874898

875-
tag autoderef_kind { AUTODEREF_OK; NO_AUTODEREF; }
899+
tag autoderef_kind { AUTODEREF_OK; NO_AUTODEREF; AUTODEREF_BLOCK_COERCE; }
876900

877901
// FIXME This is almost a duplicate of ty::type_autoderef, with structure_of
878902
// instead of ty::struct.
@@ -917,6 +941,29 @@ fn count_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> uint {
917941
fail;
918942
}
919943

944+
fn do_fn_block_coerce(&@fn_ctxt fcx, &span sp,
945+
&ty::t actual, &ty::t expected) -> ty::t {
946+
// fns can be silently coerced to blocks when being used as
947+
// function call or bind arguments, but not the reverse.
948+
// If our actual type is a fn and our expected type is a block,
949+
// build up a new expected type that is identical to the old one
950+
// except for its proto. If we don't know the expected or actual
951+
// types, that's fine, but we can't do the coercion.
952+
ret alt (structure_of_maybe(fcx, sp, actual)) {
953+
some(ty::ty_fn(ast::proto_fn, ?args, ?ret_ty, ?cf, ?constrs)) {
954+
alt (structure_of_maybe(fcx, sp, expected)) {
955+
some(ty::ty_fn(ast::proto_block, _, _, _, _)) {
956+
ty::mk_fn(fcx.ccx.tcx,
957+
ast::proto_block, args, ret_ty, cf, constrs)
958+
}
959+
_ { actual }
960+
}
961+
}
962+
_ { actual }
963+
}
964+
}
965+
966+
920967
fn resolve_type_vars_if_possible(&@fn_ctxt fcx, ty::t typ) -> ty::t {
921968
alt (ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ)) {
922969
case (fix_ok(?new_type)) { ret new_type; }
@@ -951,6 +998,8 @@ mod demand {
951998
expected_1 = do_autoderef(fcx, sp, expected_1);
952999
actual_1 = do_autoderef(fcx, sp, actual_1);
9531000
implicit_boxes = count_boxes(fcx, sp, actual);
1001+
} else if (adk == AUTODEREF_BLOCK_COERCE) {
1002+
actual_1 = do_fn_block_coerce(fcx, sp, actual, expected);
9541003
}
9551004
let ty::t[mutable] ty_param_substs = ~[mutable];
9561005
let int[] ty_param_subst_var_ids = ~[];
@@ -1175,11 +1224,12 @@ type gather_result =
11751224
rec(@ty::unify::var_bindings var_bindings,
11761225
hashmap[ast::node_id, int] locals,
11771226
hashmap[ast::node_id, ast::ident] local_names,
1178-
int next_var_id);
1227+
@mutable int next_var_id);
11791228

11801229
// Used only as a helper for check_fn.
11811230
fn gather_locals(&@crate_ctxt ccx, &ast::_fn f,
1182-
&ast::node_id id) -> gather_result {
1231+
&ast::node_id id, &option::t[@fn_ctxt] old_fcx)
1232+
-> gather_result {
11831233
fn next_var_id(@mutable int nvi) -> int {
11841234
auto rv = *nvi;
11851235
*nvi += 1;
@@ -1201,10 +1251,22 @@ fn gather_locals(&@crate_ctxt ccx, &ast::_fn f,
12011251
}
12021252
}
12031253
}
1204-
auto vb = ty::unify::mk_var_bindings();
1205-
auto locals = new_int_hash[int]();
1206-
auto local_names = new_int_hash[ast::ident]();
1207-
auto nvi = @mutable 0;
1254+
1255+
auto vb; auto locals; auto local_names; auto nvi;
1256+
alt (old_fcx) {
1257+
none {
1258+
vb = ty::unify::mk_var_bindings();
1259+
locals = new_int_hash[int]();
1260+
local_names = new_int_hash[ast::ident]();
1261+
nvi = @mutable 0;
1262+
}
1263+
some(?fcx) {
1264+
vb = fcx.var_bindings;
1265+
locals = fcx.locals;
1266+
local_names = fcx.local_names;
1267+
nvi = fcx.next_var_id;
1268+
}
1269+
}
12081270

12091271
// Add object fields, if any.
12101272
auto obj_fields = ~[];
@@ -1288,7 +1350,7 @@ fn gather_locals(&@crate_ctxt ccx, &ast::_fn f,
12881350
ret rec(var_bindings=vb,
12891351
locals=locals,
12901352
local_names=local_names,
1291-
next_var_id=*nvi);
1353+
next_var_id=nvi);
12921354
}
12931355

12941356
// AST fragment checking
@@ -1555,8 +1617,9 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
15551617
alt (a_opt) {
15561618
case (some(?a)) {
15571619
check_expr(fcx, a);
1558-
demand::simple(fcx, a.span, arg_tys.(i).ty,
1559-
expr_ty(fcx.ccx.tcx, a));
1620+
demand::full(fcx, a.span, arg_tys.(i).ty,
1621+
expr_ty(fcx.ccx.tcx, a), ~[],
1622+
AUTODEREF_BLOCK_COERCE);
15601623
}
15611624
case (none) {
15621625
check_ty_vars = true;
@@ -2013,7 +2076,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
20132076
collect::ty_of_fn_decl(cx, convert, ty_of_arg, f.decl,
20142077
f.proto, ~[], none).ty;
20152078
write::ty_only_fixup(fcx, id, fty);
2016-
check_fn(fcx.ccx, f, id);
2079+
check_fn(fcx.ccx, f, id, some(fcx));
20172080
}
20182081
case (ast::expr_block(?b)) {
20192082
check_block(fcx, b);
@@ -2487,8 +2550,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
24872550
}
24882551

24892552
fn next_ty_var_id(@fn_ctxt fcx) -> int {
2490-
auto id = fcx.next_var_id;
2491-
fcx.next_var_id += 1;
2553+
auto id = *fcx.next_var_id;
2554+
*fcx.next_var_id = fcx.next_var_id + 1;
24922555
ret id;
24932556
}
24942557

@@ -2586,24 +2649,25 @@ fn check_const(&@crate_ctxt ccx, &span sp, &@ast::expr e, &ast::node_id id) {
25862649
var_bindings=ty::unify::mk_var_bindings(),
25872650
locals=new_int_hash[int](),
25882651
local_names=new_int_hash[ast::ident](),
2589-
mutable next_var_id=0,
2652+
next_var_id=@mutable 0,
25902653
mutable fixups=fixups,
25912654
ccx=ccx);
25922655
check_expr(fcx, e);
25932656
}
25942657

2595-
fn check_fn(&@crate_ctxt ccx, &ast::_fn f, &ast::node_id id) {
2658+
fn check_fn(&@crate_ctxt ccx, &ast::_fn f, &ast::node_id id,
2659+
&option::t[@fn_ctxt] old_fcx) {
25962660
auto decl = f.decl;
25972661
auto body = f.body;
2598-
auto gather_result = gather_locals(ccx, f, id);
2662+
auto gather_result = gather_locals(ccx, f, id, old_fcx);
25992663
let ast::node_id[] fixups = ~[];
26002664
let @fn_ctxt fcx =
26012665
@rec(ret_ty=ast_ty_to_ty_crate(ccx, decl.output),
26022666
purity=decl.purity,
26032667
var_bindings=gather_result.var_bindings,
26042668
locals=gather_result.locals,
26052669
local_names=gather_result.local_names,
2606-
mutable next_var_id=gather_result.next_var_id,
2670+
next_var_id=gather_result.next_var_id,
26072671
mutable fixups=fixups,
26082672
ccx=ccx);
26092673

@@ -2636,7 +2700,7 @@ fn check_fn(&@crate_ctxt ccx, &ast::_fn f, &ast::node_id id) {
26362700
}
26372701

26382702
fn check_method(&@crate_ctxt ccx, &@ast::method method) {
2639-
check_fn(ccx, method.node.meth, method.node.id);
2703+
check_fn(ccx, method.node.meth, method.node.id, none);
26402704
}
26412705

26422706
fn check_item(@crate_ctxt ccx, &@ast::item it) {
@@ -2645,10 +2709,10 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) {
26452709
check_const(ccx, it.span, e, it.id);
26462710
}
26472711
case (ast::item_fn(?f, _)) {
2648-
check_fn(ccx, f, it.id);
2712+
check_fn(ccx, f, it.id, none);
26492713
}
26502714
case (ast::item_res(?f, ?dtor_id, _, _)) {
2651-
check_fn(ccx, f, dtor_id);
2715+
check_fn(ccx, f, dtor_id, none);
26522716
}
26532717
case (ast::item_obj(?ob, _, _)) {
26542718
// We're entering an object, so gather up the info we need.

0 commit comments

Comments
 (0)