diff --git a/Makefile.in b/Makefile.in index c749a8b40b024..1c8c56295a7a1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -501,6 +501,7 @@ TASK_XFAILS := $(addprefix $(S)src/test/run-pass/, \ task-comm-12.rs \ task-comm-2.rs \ task-comm-9.rs \ + task-comm-chan-nil.rs \ task-life-0.rs \ alt-type-simple.rs \ many.rs) diff --git a/src/Makefile b/src/Makefile index 630babf33c619..45fa909c17b01 100644 --- a/src/Makefile +++ b/src/Makefile @@ -434,6 +434,7 @@ TASK_XFAILS := test/run-pass/task-comm-8.rs \ test/run-pass/task-comm-12.rs \ test/run-pass/task-comm-2.rs \ test/run-pass/task-comm-9.rs \ + test/run-pass/task-comm-chan-nil.rs \ test/run-pass/task-life-0.rs \ test/run-pass/alt-type-simple.rs \ test/run-pass/many.rs @@ -530,9 +531,6 @@ TEST_XFAILS_RUSTC := $(addprefix test/run-pass/, \ task-comm-15.rs \ task-comm-2.rs \ task-comm-3.rs \ - task-comm-4.rs \ - task-comm-5.rs \ - task-comm-6.rs \ task-comm-7.rs \ task-comm-8.rs \ task-comm-9.rs \ diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index d4cd399228951..bc43185a7994a 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -339,6 +339,14 @@ fn T_box(TypeRef t) -> TypeRef { ret T_struct(vec(T_int(), t)); } +fn T_port(TypeRef t) -> TypeRef { + ret T_struct(vec(T_int())); // Refcount +} + +fn T_chan(TypeRef t) -> TypeRef { + ret T_struct(vec(T_int())); // Refcount +} + fn T_crate(type_names tn) -> TypeRef { auto s = "crate"; if (tn.name_has_type(s)) { @@ -623,6 +631,12 @@ fn type_of_inner(@crate_ctxt cx, @ty.t t, bool boxed) -> TypeRef { case (ty.ty_vec(?mt)) { llty = T_ptr(T_vec(type_of_inner(cx, mt.ty, true))); } + case (ty.ty_port(?t)) { + llty = T_ptr(T_port(type_of_inner(cx, t, true))); + } + case (ty.ty_chan(?t)) { + llty = T_ptr(T_chan(type_of_inner(cx, t, true))); + } case (ty.ty_tup(?elts)) { let vec[TypeRef] tys = vec(); for (ty.mt elt in elts) { @@ -1609,6 +1623,28 @@ fn make_drop_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result { T_int(), C_int(0)); } + case (ty.ty_port(_)) { + fn hit_zero(@block_ctxt cx, ValueRef v) -> result { + ret trans_upcall(cx, "upcall_del_port", + vec(vp2i(cx, v))); + } + ret decr_refcnt_and_if_zero(cx, v, + bind hit_zero(_, v), + "free port", + T_int(), C_int(0)); + } + + case (ty.ty_chan(_)) { + fn hit_zero(@block_ctxt cx, ValueRef v) -> result { + ret trans_upcall(cx, "upcall_del_chan", + vec(vp2i(cx, v))); + } + ret decr_refcnt_and_if_zero(cx, v, + bind hit_zero(_, v), + "free chan", + T_int(), C_int(0)); + } + case (ty.ty_obj(_)) { fn hit_zero(@block_ctxt cx, ValueRef v) -> result { @@ -4496,6 +4532,22 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result { ret trans_be(cx, e); } + case (ast.expr_port(?ann)) { + ret trans_port(cx, ann); + } + + case (ast.expr_chan(?e, ?ann)) { + ret trans_chan(cx, e, ann); + } + + case (ast.expr_send(?lhs, ?rhs, ?ann)) { + ret trans_send(cx, lhs, rhs, ann); + } + + case (ast.expr_recv(?lhs, ?rhs, ?ann)) { + ret trans_recv(cx, lhs, rhs, ann); + } + // lval cases fall through to trans_lval and then // possibly load the result (if it's non-structural). @@ -4667,6 +4719,116 @@ fn trans_be(@block_ctxt cx, @ast.expr e) -> result { ret trans_ret(cx, some(e)); } +fn trans_port(@block_ctxt cx, ast.ann ann) -> result { + + auto t = node_ann_type(cx.fcx.ccx, ann); + auto unit_ty; + alt (t.struct) { + case (ty.ty_port(?t)) { + unit_ty = t; + } + case (_) { + cx.fcx.ccx.sess.bug("non-port type in trans_port"); + fail; + } + } + + auto llunit_ty = type_of(cx.fcx.ccx, unit_ty); + + auto bcx = cx; + auto unit_sz = size_of(bcx, unit_ty); + bcx = unit_sz.bcx; + auto sub = trans_upcall(bcx, "upcall_new_port", vec(unit_sz.val)); + bcx = sub.bcx; + auto llty = type_of(cx.fcx.ccx, t); + auto port_val = vi2p(bcx, sub.val, llty); + auto dropref = clean(bind drop_ty(_, port_val, t)); + find_scope_cx(bcx).cleanups += vec(dropref); + + ret res(bcx, port_val); +} + +fn trans_chan(@block_ctxt cx, @ast.expr e, ast.ann ann) -> result { + + auto bcx = cx; + auto prt = trans_expr(bcx, e); + bcx = prt.bcx; + + auto prt_val = vp2i(bcx, prt.val); + auto sub = trans_upcall(bcx, "upcall_new_chan", vec(prt_val)); + bcx = sub.bcx; + + auto chan_ty = node_ann_type(bcx.fcx.ccx, ann); + auto chan_llty = type_of(bcx.fcx.ccx, chan_ty); + auto chan_val = vi2p(bcx, sub.val, chan_llty); + auto dropref = clean(bind drop_ty(_, chan_val, chan_ty)); + find_scope_cx(bcx).cleanups += vec(dropref); + + ret res(bcx, chan_val); +} + +fn trans_send(@block_ctxt cx, @ast.expr lhs, @ast.expr rhs, + ast.ann ann) -> result { + + auto bcx = cx; + auto chn = trans_expr(bcx, lhs); + bcx = chn.bcx; + auto data = trans_expr(bcx, rhs); + bcx = data.bcx; + + auto chan_ty = node_ann_type(cx.fcx.ccx, ann); + auto unit_ty; + alt (chan_ty.struct) { + case (ty.ty_chan(?t)) { + unit_ty = t; + } + case (_) { + bcx.fcx.ccx.sess.bug("non-chan type in trans_send"); + fail; + } + } + + auto data_alloc = alloc_ty(bcx, unit_ty); + bcx = data_alloc.bcx; + auto data_tmp = copy_ty(bcx, INIT, data_alloc.val, data.val, unit_ty); + bcx = data_tmp.bcx; + + find_scope_cx(bcx).cleanups += + vec(clean(bind drop_ty(_, data_alloc.val, unit_ty))); + + auto sub = trans_upcall(bcx, "upcall_send", + vec(vp2i(bcx, chn.val), + vp2i(bcx, data_alloc.val))); + bcx = sub.bcx; + + ret res(bcx, chn.val); +} + +fn trans_recv(@block_ctxt cx, @ast.expr lhs, @ast.expr rhs, + ast.ann ann) -> result { + + auto bcx = cx; + auto data = trans_lval(bcx, lhs); + check (data.is_mem); + bcx = data.res.bcx; + auto prt = trans_expr(bcx, rhs); + bcx = prt.bcx; + + auto sub = trans_upcall(bcx, "upcall_recv", + vec(vp2i(bcx, data.res.val), + vp2i(bcx, prt.val))); + bcx = sub.bcx; + + auto unit_ty = node_ann_type(cx.fcx.ccx, ann); + auto data_load = load_scalar_or_boxed(bcx, data.res.val, unit_ty); + auto cp = copy_ty(bcx, DROP_EXISTING, data.res.val, data_load, unit_ty); + bcx = cp.bcx; + + // TODO: Any cleanup need to be done here? + + ret res(bcx, data.res.val); +} + fn init_local(@block_ctxt cx, @ast.local local) -> result { // Make a note to drop this slot on the way out. diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 6eb3d8b53c125..72564078e4d6b 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -411,6 +411,8 @@ fn type_is_boxed(@t ty) -> bool { case (ty_str) { ret true; } case (ty_vec(_)) { ret true; } case (ty_box(_)) { ret true; } + case (ty_port(_)) { ret true; } + case (ty_chan(_)) { ret true; } case (_) { ret false; } } fail; @@ -759,6 +761,10 @@ fn expr_ty(@ast.expr expr) -> @t { case (ast.expr_index(_, _, ?ann)) { ret ann_to_type(ann); } case (ast.expr_path(_, _, ?ann)) { ret ann_to_type(ann); } case (ast.expr_ext(_, _, _, _, ?ann)) { ret ann_to_type(ann); } + case (ast.expr_port(?ann)) { ret ann_to_type(ann); } + case (ast.expr_chan(_, ?ann)) { ret ann_to_type(ann); } + case (ast.expr_send(_, _, ?ann)) { ret ann_to_type(ann); } + case (ast.expr_recv(_, _, ?ann)) { ret ann_to_type(ann); } case (ast.expr_fail) { ret plain_ty(ty_nil); } case (ast.expr_log(_)) { ret plain_ty(ty_nil); } diff --git a/src/test/run-pass/task-comm-16.rs b/src/test/run-pass/task-comm-16.rs new file mode 100644 index 0000000000000..a4944410f5841 --- /dev/null +++ b/src/test/run-pass/task-comm-16.rs @@ -0,0 +1,122 @@ +// -*- rust -*- + +// Tests of ports and channels on various types + +impure fn test_rec() { + type r = rec(int val0, u8 val1, char val2); + + let port[r] po = port(); + let chan[r] ch = chan(po); + let r r0 = rec(val0 = 0, val1 = 1u8, val2 = '2'); + + ch <| r0; + + let r r1; + r1 <- po; + + check (r1.val0 == 0); + check (r1.val1 == 1u8); + check (r1.val2 == '2'); +} + +impure fn test_vec() { + let port[vec[int]] po = port(); + let chan[vec[int]] ch = chan(po); + let vec[int] v0 = vec(0, 1, 2); + + ch <| v0; + + let vec[int] v1; + v1 <- po; + + check (v1.(0) == 0); + check (v1.(1) == 1); + check (v1.(2) == 2); +} + +impure fn test_str() { + let port[str] po = port(); + let chan[str] ch = chan(po); + let str s0 = "test"; + + ch <| s0; + + let str s1; + s1 <- po; + + check (s1.(0) as u8 == 't' as u8); + check (s1.(1) as u8 == 'e' as u8); + check (s1.(2) as u8 == 's' as u8); + check (s1.(3) as u8 == 't' as u8); +} + +impure fn test_tup() { + type t = tup(int, u8, char); + + let port[t] po = port(); + let chan[t] ch = chan(po); + let t t0 = tup(0, 1u8, '2'); + + ch <| t0; + + let t t1; + t1 <- po; + + check (t0._0 == 0); + check (t0._1 == 1u8); + check (t0._2 == '2'); +} + +impure fn test_tag() { + tag t { + tag1; + tag2(int); + tag3(int, u8, char); + } + + let port[t] po = port(); + let chan[t] ch = chan(po); + + ch <| tag1; + ch <| tag2(10); + ch <| tag3(10, 11u8, 'A'); + + let t t1; + + t1 <- po; + check (t1 == tag1); + t1 <- po; + check (t1 == tag2(10)); + t1 <- po; + check (t1 == tag3(10, 11u8, 'A')); +} + +impure fn test_chan() { + let port[chan[int]] po = port(); + let chan[chan[int]] ch = chan(po); + + let port[int] po0 = port(); + let chan[int] ch0 = chan(po0); + + ch <| ch0; + + let chan[int] ch1; + ch1 <- po; + + // Does the transmitted channel still work? + ch1 <| 10; + + let int i; + i <- po0; + + check (i == 10); +} + +impure fn main() { + test_rec(); + test_vec(); + test_str(); + test_tup(); + test_tag(); + test_chan(); +} diff --git a/src/test/run-pass/task-comm-chan-nil.rs b/src/test/run-pass/task-comm-chan-nil.rs new file mode 100644 index 0000000000000..c8f5a90f59ecd --- /dev/null +++ b/src/test/run-pass/task-comm-chan-nil.rs @@ -0,0 +1,17 @@ +// -*- rust -*- + +// rustboot can't transmit nils across channels because they don't have +// any size, but rustc currently can because they do have size. Whether +// or not this is desirable I don't know, but here's a regression test. + +impure fn main() { + let port[()] po = port(); + let chan[()] ch = chan(po); + + ch <| (); + + let () n; + n <- po; + + check (n == ()); +}