提交 8685a1f7 编写于 作者: N Niko Matsakis

distinguish "any closure" and "stack closure" (block)

上级 47a534c1
......@@ -161,6 +161,17 @@ fn parse_ty_rust_fn(st: @pstate, conv: conv_did, p: ast::proto) -> ty::t {
ret ty::mk_fn(st.tcx, {proto: p with parse_ty_fn(st, conv)});
}
fn parse_proto(c: char) -> ast::proto {
alt c {
'~' { ast::proto_uniq }
'@' { ast::proto_box }
'*' { ast::proto_any }
'&' { ast::proto_block }
'n' { ast::proto_bare }
_ { fail "illegal fn type kind " + str::from_char(c); }
}
}
fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
alt next(st) as char {
'n' { ret ty::mk_nil(st.tcx); }
......@@ -230,17 +241,9 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
st.pos = st.pos + 1u;
ret ty::mk_tup(st.tcx, params);
}
's' {
ret parse_ty_rust_fn(st, conv, ast::proto_uniq);
}
'F' {
ret parse_ty_rust_fn(st, conv, ast::proto_box);
}
'f' {
ret parse_ty_rust_fn(st, conv, ast::proto_bare);
}
'B' {
ret parse_ty_rust_fn(st, conv, ast::proto_block);
let proto = parse_proto(next(st) as char);
parse_ty_rust_fn(st, conv, proto)
}
'N' {
let func = parse_ty_fn(st, conv);
......
......@@ -192,10 +192,11 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
}
fn enc_proto(w: io::writer, proto: proto) {
alt proto {
proto_uniq. { w.write_char('s'); }
proto_box. { w.write_char('F'); }
proto_block. { w.write_char('B'); }
proto_bare. { w.write_char('f'); }
proto_uniq. { w.write_str("f~"); }
proto_box. { w.write_str("f@"); }
proto_block. { w.write_str("f&"); }
proto_any. { w.write_str("f*"); }
proto_bare. { w.write_str("fn"); }
}
}
......
......@@ -88,11 +88,14 @@ fn visit_fn(cx: @ctx, _fk: visit::fn_kind, decl: ast::fn_decl,
// Blocks need to obey any restrictions from the enclosing scope, and may
// be called multiple times.
let proto = ty::ty_fn_proto(cx.tcx, fty);
if proto == ast::proto_block {
alt proto {
ast::proto_block. | ast::proto_any. {
check_loop(*cx, sc) {|| v.visit_block(body, sc, v);}
} else {
}
ast::proto_box. | ast::proto_uniq. | ast::proto_bare. {
let sc = {bs: [], invalid: @mutable list::nil};
v.visit_block(body, sc, v);
}
}
}
......
......@@ -14,7 +14,7 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
if !cx.allow_block {
alt ty::struct(cx.tcx, ty::expr_ty(cx.tcx, ex)) {
ty::ty_fn({proto: proto_block., _}) {
ty::ty_fn({proto: p, _}) if is_blockish(p) {
cx.tcx.sess.span_err(ex.span, "expressions with block type \
can only appear in callee or (by-ref) argument position");
}
......
......@@ -75,7 +75,7 @@ fn check_capture_clause(tcx: ty::ctxt,
};
alt fn_proto {
ast::proto_block. {
ast::proto_any. | ast::proto_block. {
check_block_captures(cap_clause.copies);
check_block_captures(cap_clause.moves);
}
......@@ -113,7 +113,7 @@ fn compute_capture_vars(tcx: ty::ctxt,
}
let implicit_mode = alt fn_proto {
ast::proto_block. { cap_ref }
ast::proto_any. | ast::proto_block. { cap_ref }
ast::proto_bare. | ast::proto_box. | ast::proto_uniq. { cap_copy }
};
......
......@@ -63,8 +63,8 @@ fn with_appropriate_checker(cx: ctx, id: node_id,
alt ty::ty_fn_proto(cx.tcx, fty) {
proto_uniq. { b(check_send); }
proto_box. { b(check_copy); }
proto_block. { /* no check needed */ }
proto_bare. { b(check_none); }
proto_any. | proto_block. { /* no check needed */ }
}
}
......
......@@ -63,9 +63,9 @@ fn find_last_uses(c: @crate, def_map: resolve::def_map,
ret mini_table;
}
fn is_block(cx: ctx, id: node_id) -> bool {
fn ex_is_blockish(cx: ctx, id: node_id) -> bool {
alt ty::struct(cx.tcx, ty::node_id_to_monotype(cx.tcx, id)) {
ty::ty_fn({proto: proto_block., _}) { true }
ty::ty_fn({proto: p, _}) if is_blockish(p) { true }
_ { false }
}
}
......@@ -152,8 +152,12 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
let arg_ts = ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f));
for arg in args {
alt arg.node {
expr_fn(proto_block., _, _, _) { fns += [arg]; }
expr_fn_block(_, _) if is_block(cx, arg.id) { fns += [arg]; }
expr_fn(p, _, _, _) if is_blockish(p) {
fns += [arg];
}
expr_fn_block(_, _) if ex_is_blockish(cx, arg.id) {
fns += [arg];
}
_ {
alt arg_ts[i].mode {
by_mut_ref. { clear_if_path(cx, arg, v, false); }
......@@ -174,11 +178,13 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
cx: ctx, v: visit::vt<ctx>) {
let fty = ty::node_id_to_type(cx.tcx, id);
let proto = ty::ty_fn_proto(cx.tcx, fty);
if proto == proto_block {
alt proto {
proto_any. | proto_block. {
visit_block(func, cx, {||
visit::visit_fn(fk, decl, body, sp, id, cx, v);
});
} else {
}
proto_box. | proto_uniq. | proto_bare. {
alt cx.tcx.freevars.find(id) {
some(vars) {
for v in *vars {
......@@ -193,6 +199,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
visit::visit_fn(fk, decl, body, sp, id, cx, v);
cx.blocks <-> old;
leave_fn(cx);
}
}
}
......
......@@ -269,7 +269,7 @@ fn is_immutable_def(cx: @ctx, def: def) -> option::t<str> {
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) }
proto_any. | proto_block. { is_immutable_def(cx, *inner) }
_ { some("upvar") }
};
}
......
......@@ -523,6 +523,7 @@ fn trans_expr_fn(bcx: @block_ctxt,
};
let closure = alt proto {
ast::proto_any. { fail "proto_any cannot appear in an expr"; }
ast::proto_block. { trans_closure_env(ty::ck_block) }
ast::proto_box. { trans_closure_env(ty::ck_box) }
ast::proto_uniq. { trans_closure_env(ty::ck_uniq) }
......@@ -664,6 +665,7 @@ fn make_fn_glue(
ret alt ty::struct(tcx, t) {
ty::ty_native_fn(_, _) | ty::ty_fn({proto: ast::proto_bare., _}) { bcx }
ty::ty_fn({proto: ast::proto_block., _}) { bcx }
ty::ty_fn({proto: ast::proto_any., _}) { bcx }
ty::ty_fn({proto: ast::proto_uniq., _}) { fn_env(ty::ck_uniq) }
ty::ty_fn({proto: ast::proto_box., _}) { fn_env(ty::ck_box) }
_ { fail "make_fn_glue invoked on non-function type" }
......
......@@ -993,6 +993,7 @@ fn type_needs_drop(cx: ctxt, ty: t) -> bool {
fn proto_kind(p: proto) -> kind {
alt p {
ast::proto_any. { kind_noncopyable }
ast::proto_block. { kind_noncopyable }
ast::proto_box. { kind_copyable }
ast::proto_uniq. { kind_sendable }
......@@ -1925,7 +1926,8 @@ fn unify_fn_proto(e_proto: ast::proto, a_proto: ast::proto,
// subtype).
fn sub_proto(p_sub: ast::proto, p_sup: ast::proto) -> bool {
ret alt (p_sub, p_sup) {
(_, ast::proto_block.) { true }
(_, ast::proto_any.) { true }
(_, ast::proto_block.) { true } /* NDM temporary */
(ast::proto_bare., _) { true }
// Equal prototypes are always subprotos:
......
......@@ -2874,7 +2874,7 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
_ {}
}
}
ast::expr_fn(ast::proto_block., _, _, _) {}
ast::expr_fn(p, _, _, _) if ast::is_blockish(p) {}
ast::expr_fn(_, _, _, _) { ret; }
_ {}
}
......
......@@ -117,6 +117,13 @@
proto_block; // fn&
}
pure fn is_blockish(p: ast::proto) -> bool {
alt p {
proto_any. | proto_block. { true }
proto_bare. | proto_uniq. | proto_box. { false }
}
}
tag binop {
add;
sub;
......
......@@ -481,11 +481,12 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty {
} else if eat_word(p, "fn") {
let proto = parse_fn_ty_proto(p);
alt proto {
ast::proto_bare. { p.fatal("fn is deprecated, use native fn"); }
ast::proto_bare. { p.warn("fn is deprecated, use native fn"); }
_ { /* fallthrough */ }
}
t = parse_ty_fn(proto, p);
} else if eat_word(p, "block") {
//p.warn("block is deprecated, use fn& or fn");
t = parse_ty_fn(ast::proto_block, p);
} else if eat_word(p, "native") {
expect_word(p, "fn");
......@@ -788,11 +789,13 @@ fn parse_bottom_expr(p: parser) -> pexpr {
} else if eat_word(p, "fn") {
let proto = parse_fn_ty_proto(p);
alt proto {
ast::proto_bare. { p.warn("fn expr are deprecated, use fn@"); }
ast::proto_bare. { p.fatal("fn expr are deprecated, use fn@"); }
ast::proto_any. { p.fatal("fn* cannot be used in an expression"); }
_ { /* fallthrough */ }
}
ret pexpr(parse_fn_expr(p, proto));
} else if eat_word(p, "block") {
p.warn("block is deprecated, use fn& or fn");
ret pexpr(parse_fn_expr(p, ast::proto_block));
} else if eat_word(p, "unchecked") {
ret pexpr(parse_block_expr(p, lo, ast::unchecked_blk));
......@@ -2055,19 +2058,12 @@ fn parse_item_tag(p: parser, attrs: [ast::attribute]) -> @ast::item {
}
fn parse_fn_ty_proto(p: parser) -> ast::proto {
<<<<<<< HEAD
if p.token == token::AT {
p.bump();
ast::proto_box
} else if p.token == token::TILDE {
=======
alt p.peek() {
alt p.token {
token::AT. {
p.bump();
ast::proto_box
}
token::TILDE. {
>>>>>>> make blocks fn& and fn stand for "any closure"
p.bump();
ast::proto_uniq
}
......@@ -2075,6 +2071,10 @@ fn parse_fn_ty_proto(p: parser) -> ast::proto {
p.bump();
ast::proto_block
}
token::BINOP(token::STAR.) {
p.bump(); // temporary: fn* for any closure
ast::proto_any
}
_ {
ast::proto_bare
}
......
......@@ -1611,11 +1611,12 @@ fn opt_proto_to_str(opt_p: option<ast::proto>) -> str {
fn proto_to_str(p: ast::proto) -> str {
ret alt p {
ast::proto_bare. { "native fn" }
ast::proto_block. { "block" }
ast::proto_uniq. { "fn~" }
ast::proto_box. { "fn@" }
};
ast::proto_bare. { "native fn" }
ast::proto_any. { "fn*" }
ast::proto_block. { "fn&" }
ast::proto_uniq. { "fn~" }
ast::proto_box. { "fn@" }
};
}
fn ty_constr_to_str(c: @ast::ty_constr) -> str {
......
......@@ -116,13 +116,19 @@ fn safe_to_steal_ty(t: @ast::ty, tm: test_mode) -> bool {
}
// Not type-parameterized: https://github.com/graydon/rust/issues/898
fn stash_expr_if(c: fn(@ast::expr, test_mode)->bool, es: @mutable [ast::expr], e: @ast::expr, tm: test_mode) {
fn stash_expr_if(c: fn@(@ast::expr, test_mode)->bool,
es: @mutable [ast::expr],
e: @ast::expr,
tm: test_mode) {
if c(e, tm) {
*es += [*e];
} else {/* now my indices are wrong :( */ }
}
fn stash_ty_if(c: fn(@ast::ty, test_mode)->bool, es: @mutable [ast::ty], e: @ast::ty, tm: test_mode) {
fn stash_ty_if(c: fn@(@ast::ty, test_mode)->bool,
es: @mutable [ast::ty],
e: @ast::ty,
tm: test_mode) {
if c(e, tm) {
*es += [*e];
} else {/* now my indices are wrong :( */ }
......@@ -236,8 +242,8 @@ fn check_variants_T<T: copy>(
filename: str,
thing_label: str,
things: [T],
stringifier: fn(@T) -> str,
replacer: fn(ast::crate, uint, T, test_mode) -> ast::crate,
stringifier: fn@(@T) -> str,
replacer: fn@(ast::crate, uint, T, test_mode) -> ast::crate,
cx: context
) {
#error("%s contains %u %s objects", filename, vec::len(things), thing_label);
......
......@@ -49,7 +49,7 @@ impl writer_util for io::writer {
// to support isolation of tests into tasks.
type test_fn<T> = T;
type default_test_fn = test_fn<sendfn()>;
type default_test_fn = test_fn<fn~()>;
// The definition of a single test. A test runner will run a list of
// these.
......@@ -336,7 +336,7 @@ fn run_test<T: copy>(test: test_desc<T>,
// We need to run our tests in another task in order to trap test failures.
// This function only works with functions that don't contain closures.
fn default_test_to_task(&&f: default_test_fn) -> joinable {
ret task::spawn_joinable(sendfn[copy f]() {
ret task::spawn_joinable(fn~[copy f]() {
configure_test_task();
f();
});
......
// error-pattern:Variable 'x' captured more than once
fn main() {
let x = 5;
let y = sendfn[move x; copy x]() -> int { x };
let y = fn~[move x; copy x]() -> int { x };
}
// error-pattern:Variable 'x' captured more than once
fn main() {
let x = 5;
let y = sendfn[copy x, x]() -> int { x };
let y = fn~[copy x, x]() -> int { x };
}
// error-pattern:Variable 'x' captured more than once
fn main() {
let x = 5;
let y = sendfn[move x, x]() -> int { x };
let y = fn~[move x, x]() -> int { x };
}
// error-pattern:Upvars (like 'x') cannot be moved into a closure
fn main() {
let x = 5;
let _y = sendfn[move x]() -> int {
let _z = sendfn[move x]() -> int { x };
let _y = fn~[move x]() -> int {
let _z = fn~[move x]() -> int { x };
22
};
}
// error-pattern:unresolved name: z
fn main() {
let x = 5;
let y = sendfn[copy z, x]() {
let y = fn~[copy z, x]() {
};
}
\ No newline at end of file
// error-pattern:unresolved name: z
fn main() {
let x = 5;
let y = sendfn[move z, x]() {
let y = fn~[move z, x]() {
};
}
\ No newline at end of file
......@@ -2,6 +2,6 @@
fn main() {
let x = 5;
let _y = sendfn[move x]() { };
let _y = fn~[move x]() { };
let _z = x; //< error: Unsatisfied precondition constraint
}
......@@ -2,6 +2,6 @@
fn main() {
// Typestate should work even in a fn@. we should reject this program.
let f = fn () -> int { let i: int; ret i; };
let f = fn@() -> int { let i: int; ret i; };
log(error, f());
}
// error-pattern:Unsatisfied precondition
fn main() {
let j = fn () -> int { let i: int; ret i; }();
let j = fn@() -> int { let i: int; ret i; }();
log(error, j);
}
......@@ -2,5 +2,5 @@
fn main() {
let x = @3u;
let _f = sendfn(y: uint) -> uint { ret *x+y; };
let _f = fn~(y: uint) -> uint { ret *x+y; };
}
\ No newline at end of file
......@@ -3,4 +3,4 @@
use std;
import task;
fn main() { task::spawn(sendfn() -> int { 10 }); }
fn main() { task::spawn(fn~() -> int { 10 }); }
......@@ -9,8 +9,8 @@ fn main() {
let x = ~2;
let y = ptr::addr_of(*x) as uint;
let snd_copy = sendfn[copy x]() -> uint { ptr::addr_of(*x) as uint };
let snd_move = sendfn[move x]() -> uint { ptr::addr_of(*x) as uint };
let snd_copy = fn~[copy x]() -> uint { ptr::addr_of(*x) as uint };
let snd_move = fn~[move x]() -> uint { ptr::addr_of(*x) as uint };
assert snd_copy() != y;
assert snd_move() == y;
}
// error-pattern: warning: Captured variable 'y' not used in closure
fn main() {
let x = 5;
let _y = sendfn[copy x]() { };
let _y = fn~[copy x]() { };
}
......@@ -3,6 +3,6 @@ fn test(f: block(uint) -> uint) -> uint {
}
fn main() {
let y = test(sendfn(x: uint) -> uint { ret 4u * x; });
let y = test(fn~(x: uint) -> uint { ret 4u * x; });
assert y == 88u;
}
\ No newline at end of file
......@@ -8,7 +8,7 @@ fn main() {
let y = ~2;
let y_in_parent = ptr::addr_of(*y) as uint;
task::spawn(sendfn[copy ch, y; move x]() {
task::spawn(fn~[copy ch, y; move x]() {
let x_in_child = ptr::addr_of(*x) as uint;
comm::send(ch, x_in_child);
......
......@@ -63,8 +63,8 @@ fn filter_for_ignored_option() {
let opts = {filter: option::none, run_ignored: true};
let tests =
[{name: "1", fn: fn () { }, ignore: true, should_fail: false},
{name: "2", fn: fn () { }, ignore: false, should_fail: false}];
[{name: "1", fn: fn@() { }, ignore: true, should_fail: false},
{name: "2", fn: fn@() { }, ignore: false, should_fail: false}];
let filtered = test::filter_tests(opts, tests);
assert (vec::len(filtered) == 1u);
......@@ -85,7 +85,7 @@ fn sort_tests() {
"test::sort_tests"];
let tests =
{
let testfn = fn () { };
let testfn = fn@() { };
let tests = [];
for name: str in names {
let test = {name: name, fn: testfn, ignore: false,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册