diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs index 1d391f80f848d..d899f3f50a39b 100644 --- a/src/comp/middle/kind.rs +++ b/src/comp/middle/kind.rs @@ -10,24 +10,25 @@ * * * -* COPY + SEND = "Unique": no shared substructures or pins, only +* MOVE + SEND = "Unique": no shared substructures or pins, only * interiors and ~ boxes. * -* COPY + NOSEND = "Shared": structures containing @, fixed to the local -* task heap/pool. +* MOVE + NOSEND = "Shared": structures containing @, fixed to the local +* task heap/pool; or ~ structures pointing to +* pinned values. * -* NOCOPY + NOSEND = "Pinned": structures containing resources or +* NOMOVE + NOSEND = "Pinned": structures directly containing resources, or * by-alias closures as interior or * uniquely-boxed members. * -* NOCOPY + SEND = -- : no types are like this. +* NOMOVE + SEND = -- : no types are like this. * * * Since this forms a lattice, we denote the capabilites in terms of a -* worst-case requirement. That is, if your function needs to copy-and-send -* your T, you write fn<~T>(...). If you need to copy but not send, you write -* fn<@T>(...). And if you need neither -- can work with any sort of pinned -* data at all -- then you write fn(...). +* worst-case requirement. That is, if your function needs to move-and-send +* (or copy) your T, you write fn<~T>(...). If you need to copy but not send, +* you write fn<@T>(...). And if you need neither -- can work with any sort of +* pinned data at all -- then you write fn(...). * * * Most types are unique or shared. Other possible name combinations for these @@ -54,10 +55,12 @@ * A copy is made any time you pass-by-value or execute the = operator in a * non-init expression. * -* ~ copies deep -* @ copies shallow +* @ copies shallow, is always legal +* ~ copies deep, is only legal if pointee is unique. * pinned values (pinned resources, alias-closures) can't be copied -* all other interiors copy shallow +* all other unique (eg. interior) values copy shallow +* +* Note this means that only type parameters constrained to ~T can be copied. * * MOVING: * ------- @@ -65,11 +68,6 @@ * A move is made any time you pass-by-move (that is, with 'move' mode) or * execute the <- operator. * -* Anything you can copy, you can move. Move is (semantically) just -* shallow-copy + deinit. Note that: ~ moves shallow even though it copies -* deep. Move is the operator that lets ~ copy shallow: by pairing it with a -* deinit. -* */ @@ -101,11 +99,47 @@ fn kind_to_str(k: kind) -> str { } } -fn check_expr(tcx: &ty::ctxt, e: &@ast::expr) { +fn type_and_kind(tcx: &ty::ctxt, e: &@ast::expr) + -> {ty: ty::t, kind: ast::kind} { let t = ty::expr_ty(tcx, e); let k = ty::type_kind(tcx, t); - log #fmt("%s type: %s", kind_to_str(k), - util::ppaux::ty_to_str(tcx, t)); + {ty: t, kind: k} +} + +fn need_expr_kind(tcx: &ty::ctxt, e: &@ast::expr, + k_need: ast::kind, descr: &str) { + let tk = type_and_kind(tcx, e); + log #fmt("for %s: want %s type, got %s type %s", + descr, + kind_to_str(k_need), + kind_to_str(tk.kind), + util::ppaux::ty_to_str(tcx, tk.ty)); + + if ! kind_lteq(k_need, tk.kind) { + let s = + #fmt("mismatched kinds for %s: needed %s type, got %s type %s", + descr, + kind_to_str(k_need), + kind_to_str(tk.kind), + util::ppaux::ty_to_str(tcx, tk.ty)); + tcx.sess.span_err(e.span, s); + } +} + +fn need_shared_lhs_rhs(tcx: &ty::ctxt, + a: &@ast::expr, b: &@ast::expr, + op: &str) { + need_expr_kind(tcx, a, ast::kind_shared, op + " lhs"); + need_expr_kind(tcx, b, ast::kind_shared, op + " rhs"); +} + +fn check_expr(tcx: &ty::ctxt, e: &@ast::expr) { + alt e.node { + ast::expr_move(a, b) { need_shared_lhs_rhs(tcx, a, b, "<-"); } + ast::expr_assign(a, b) { need_shared_lhs_rhs(tcx, a, b, "="); } + ast::expr_swap(a, b) { need_shared_lhs_rhs(tcx, a, b, "<->"); } + _ { } + } } fn check_crate(tcx: &ty::ctxt, crate: &@ast::crate) { diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 5ff5a018f8805..ccd11cad13091 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1058,12 +1058,10 @@ fn type_kind(cx: &ctxt, ty: &t) -> ast::kind { } } - // Those with refcounts-to-inner are the lower of their - // inner and shared. + // Those with refcounts-to-inner raise pinned to shared, + // lower unique to shared. Therefore just set result to shared. ty_box(mt) | ty_vec(mt) { - result = kind::lower_kind(ast::kind_shared, - type_kind(cx, mt.ty)); - + result = ast::kind_shared; } // FIXME: remove ports. Ports currently contribute 'shared' @@ -1078,9 +1076,12 @@ fn type_kind(cx: &ctxt, ty: &t) -> ast::kind { result = type_kind(cx, t); } - // Pointers and unique boxes / vecs lower to whatever they point to. + // Pointers and unique boxes / vecs raise pinned to shared, + // otherwise pass through their pointee kind. ty_ptr(tm) | ty_ivec(tm) { - result = type_kind(cx, tm.ty); + let k = type_kind(cx, tm.ty); + if k == ast::kind_pinned { k = ast::kind_shared } + result = kind::lower_kind(result, k); } // Records lower to the lowest of their members.