body: wrapper_body
};
+ let wrapper_capture: @ast::capture = @{
+ node: {
+ is_send: false,
+ copies: [],
+ moves: []
+ },
+ span: span
+ };
+
let wrapper_expr: ast::expr = {
id: cx.sess.next_node_id(),
- node: ast::expr_fn(wrapper_fn),
+ node: ast::expr_fn(wrapper_fn, wrapper_capture),
span: span
};
ret @respan(sp, {path: pth, args: args, id: def});
}
+fn parse_ty_rust_fn(st: @pstate, sd: str_def, p: ast::proto) -> ty::t {
+ let func = parse_ty_fn(st, sd);
+ ret ty::mk_fn(st.tcx, p,
+ func.args, func.ty, func.cf,
+ func.cs);
+}
+
fn parse_ty(st: @pstate, sd: str_def) -> ty::t {
alt next(st) as char {
'n' { ret ty::mk_nil(st.tcx); }
st.pos = st.pos + 1u;
ret ty::mk_tup(st.tcx, params);
}
+ 's' {
+ ret parse_ty_rust_fn(st, sd, ast::proto_send);
+ }
'F' {
- let func = parse_ty_fn(st, sd);
- ret ty::mk_fn(st.tcx, ast::proto_shared(ast::sugar_normal),
- func.args, func.ty, func.cf,
- func.cs);
+ ret parse_ty_rust_fn(st, sd, ast::proto_shared(ast::sugar_normal));
}
'f' {
- let func = parse_ty_fn(st, sd);
- ret ty::mk_fn(st.tcx, ast::proto_bare, func.args, func.ty, func.cf,
- func.cs);
+ ret parse_ty_rust_fn(st, sd, ast::proto_bare);
}
'B' {
- let func = parse_ty_fn(st, sd);
- ret ty::mk_fn(st.tcx, ast::proto_block, func.args, func.ty, func.cf,
- func.cs);
+ ret parse_ty_rust_fn(st, sd, ast::proto_block);
}
'N' {
let func = parse_ty_fn(st, sd);
}
fn enc_proto(w: io::writer, proto: proto) {
alt proto {
+ proto_send. { w.write_char('s'); }
proto_shared(_) { w.write_char('F'); }
proto_block. { w.write_char('B'); }
proto_bare. { w.write_char('f'); }
lambda (expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
alt expr.node {
ast::expr_fn(f, captures) {
- if f.proto == ast::proto_block ||
- f.proto == ast::proto_shared(ast::sugar_normal) ||
- f.proto == ast::proto_shared(ast::sugar_sexy) {
+ if f.proto != ast::proto_bare {
visit::visit_expr(expr, depth + 1, v);
}
}
}
fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
+
+ fn check_free_vars(e: @expr,
+ cx: ctx,
+ check_fn: fn(ctx, ty::t, sp: span)) {
+ for free in *freevars::get_freevars(cx.tcx, e.id) {
+ let id = ast_util::def_id_of_def(free).node;
+ let ty = ty::node_id_to_type(cx.tcx, id);
+ check_fn(cx, ty, e.span);
+ }
+ }
+
alt e.node {
expr_assign(_, ex) | expr_assign_op(_, _, ex) |
expr_block({node: {expr: some(ex), _}, _}) |
let ty_fields = alt ty::struct(cx.tcx, t) { ty::ty_rec(f) { f } };
for tf in ty_fields {
if !vec::any({|f| f.node.ident == tf.ident}, fields) &&
- ty::type_kind(cx.tcx, tf.mt.ty) == kind_noncopyable {
+ !kind_can_be_copied(ty::type_kind(cx.tcx, tf.mt.ty)) {
cx.tcx.sess.span_err(ex.span,
"copying a noncopyable value");
}
none. {}
}
}
- expr_fn({proto: proto_send, _}, captures) {
- for free in *freevars::get_freevars(cx.tcx, e.id) {
- let id = ast_util::def_id_of_def(free).node;
- let ty = ty::node_id_to_type(cx.tcx, id);
- check_copy(cx, ty, e.span);
- }
+ expr_fn({proto: proto_send., _}, captures) { // NDM captures
+ check_free_vars(e, cx, check_send);
}
- expr_fn({proto: proto_shared(_), _}, captures) {
- for free in *freevars::get_freevars(cx.tcx, e.id) {
- let id = ast_util::def_id_of_def(free).node;
- let ty = ty::node_id_to_type(cx.tcx, id);
- check_copy(cx, ty, e.span);
- }
+ expr_fn({proto: proto_shared(_), _}, captures) { // NDM captures
+ check_free_vars(e, cx, check_copy);
}
expr_ternary(_, a, b) { maybe_copy(cx, a); maybe_copy(cx, b); }
_ { }
}
fn check_copy(cx: ctx, ty: ty::t, sp: span) {
- if ty::type_kind(cx.tcx, ty) == kind_noncopyable {
+ if !kind_can_be_copied(ty::type_kind(cx.tcx, ty)) {
cx.tcx.sess.span_err(sp, "copying a noncopyable value");
}
}
+fn check_send(cx: ctx, ty: ty::t, sp: span) {
+ if !kind_can_be_sent(ty::type_kind(cx.tcx, ty)) {
+ cx.tcx.sess.span_err(sp, "not a sendable value");
+ }
+}
+
//
// Local Variables:
// mode: rust
fn constraint_to_str(tcx: ty::ctxt, c: sp_constr) -> str {
alt c.node {
- ninit(_, i) {
- ret "init(" + i + " [" + tcx.sess.span_str(c.span) + "])";
+ ninit(id, i) {
+ ret #fmt("init(%s id=%d [%s])",
+ i, id, tcx.sess.span_str(c.span));
}
npred(p, _, args) {
ret path_to_str(p) + "(" + comma_str(args) + ")" + "[" +
}
fn handle_var_def(fcx: fn_ctxt, rslt: pre_and_post, def: def, name: ident) {
+ log ("handle_var_def: ", def, name);
alt def {
def_local(d_id, _) | def_arg(d_id, _) {
use_var(fcx, d_id.node);
let rslt = expr_pp(fcx.ccx, e);
clear_pp(rslt);
for def in *freevars::get_freevars(fcx.ccx.tcx, e.id) {
+ log ("handle_var_def: def=", def);
handle_var_def(fcx, rslt, def, "upvar");
}
}
}
fn unify_fn_proto(e_proto: ast::proto, a_proto: ast::proto,
variance: variance) -> option::t<result> {
+ fn rank(proto: ast::proto) -> int {
+ ret alt proto {
+ ast::proto_block. { 0 }
+ ast::proto_shared(_) { 1 }
+ ast::proto_send. { 2 }
+ ast::proto_bare. { 3 }
+ };
+ }
+
fn gt(e_proto: ast::proto, a_proto: ast::proto) -> bool {
- alt e_proto {
- ast::proto_block. {
- // Every function type is a subtype of block
- false
- }
- ast::proto_shared(_) {
- a_proto == ast::proto_block
- }
- ast::proto_bare. {
- a_proto != ast::proto_bare
- }
- }
+ ret rank(e_proto) > rank(a_proto);
}
ret if e_proto == a_proto {
none
} else if variance == invariant {
- if e_proto != a_proto {
- some(ures_err(terr_mismatch))
- } else {
- fail
- }
+ some(ures_err(terr_mismatch))
} else if variance == covariant {
if gt(e_proto, a_proto) {
some(ures_err(terr_mismatch))
tag kind { kind_sendable; kind_copyable; kind_noncopyable; }
+// Using these query functons is preferable to direct comparison or matching
+// against the kind constants, as we may modify the kind hierarchy in the
+// future.
+pure fn kind_can_be_copied(k: kind) -> bool {
+ ret alt k {
+ kind_sendable. { true }
+ kind_copyable. { true }
+ kind_noncopyable. { false }
+ };
+}
+
+pure fn kind_can_be_sent(k: kind) -> bool {
+ ret alt k {
+ kind_sendable. { true }
+ kind_copyable. { false }
+ kind_noncopyable. { false }
+ };
+}
+
tag proto_sugar {
sugar_normal;
sugar_sexy;
tag fn_kw {
fn_kw_fn;
+ fn_kw_fn_at;
fn_kw_lambda;
fn_kw_block;
}
} else if eat_word(p, "block") {
t = parse_ty_fn(ast::proto_block, p);
} else if eat_word(p, "lambda") {
- if p.peek() == token::LBRACE { // lambda[send](...)
- expect(p, token::LBRACE);
+ if eat(p, token::LBRACKET) { // lambda[send](...)
expect_word(p, "send");
- expect(p, token::RBRACE);
+ expect(p, token::RBRACKET);
t = parse_ty_fn(ast::proto_send, p);
} else { // lambda(...)
t = parse_ty_fn(ast::proto_shared(ast::sugar_sexy), p);
ret parse_spawn_expr(p);
*/
} else if eat_word(p, "fn") {
- let proto = parse_fn_anon_proto(p);
- ret parse_fn_expr(p, fn_kw_fn);
+ let kw = parse_fn_anon_kw(p);
+ ret parse_fn_expr(p, kw);
} else if eat_word(p, "block") {
ret parse_fn_expr(p, fn_kw_block);
} else if eat_word(p, "lambda") {
fn parse_capture_clause(p: parser) -> @ast::capture {
fn expect_opt_trailing_semi(p: parser) {
if !eat(p, token::SEMI) {
- if p.peek() != token::RBRACE {
+ if p.peek() != token::RBRACKET {
p.fatal("expecting ; or ]");
}
}
while true {
alt p.peek() {
token::IDENT(_, _) {
- let i = spanned(p.get_lo_pos(), p.get_hi_pos(), parse_ident(p));
+ let i = spanned(p.get_lo_pos(),
+ p.get_hi_pos(),
+ parse_ident(p));
res += [i];
if !eat(p, token::COMMA) {
ret res;
_ { ret res; }
}
}
+ std::util::unreachable();
}
let is_send = false;
let moves = [];
let lo = p.get_lo_pos();
- if eat(p, token::LBRACE) {
- while !eat(p, token::RBRACE) {
+ if eat(p, token::LBRACKET) {
+ while !eat(p, token::RBRACKET) {
if eat_word(p, "send") {
is_send = true;
expect_opt_trailing_semi(p);
let body = parse_block(p);
let proto = alt (kw, captures.node.is_send) {
(fn_kw_fn., true) { ast::proto_bare }
+ (fn_kw_fn_at., true) { ast::proto_send }
(fn_kw_lambda., true) { ast::proto_send }
+ (fn_kw_block., true) { p.fatal("block cannot be declared sendable"); }
+ (fn_kw_fn., false) { ast::proto_bare }
+ (fn_kw_fn_at., false) { ast::proto_shared(ast::sugar_normal) }
(fn_kw_lambda., false) { ast::proto_shared(ast::sugar_sexy) }
(fn_kw_block., false) { ast::proto_block }
- (_, true) { p.fatal("only lambda can be declared sendable"); }
};
let _fn = {decl: decl, proto: proto, body: body};
ret mk_expr(p, lo, body.span.hi, ast::expr_fn(_fn, captures));
}
}
-fn parse_fn_anon_proto(p: parser) -> ast::proto {
+fn parse_fn_anon_kw(p: parser) -> fn_kw {
if p.peek() == token::AT {
p.bump();
- ast::proto_shared(ast::sugar_normal)
+ fn_kw_fn_at
} else {
- ast::proto_bare
+ fn_kw_fn
}
}
ret alt p {
ast::proto_bare. { "fn" }
ast::proto_block. { "block" }
+ ast::proto_send. { "lambda[send]" }
ast::proto_shared(ast::sugar_normal.) { "fn@" }
ast::proto_shared(ast::sugar_sexy.) { "lambda" }
};