Skip to content

Commit

Permalink
Further refinement to kind system lattice and type-kind rules; first …
Browse files Browse the repository at this point in the history
…successful caught kind error (prohibits copying a pinned resource, though trans already caught it later).
  • Loading branch information
graydon committed Jul 28, 2011
1 parent 7073ee4 commit a11bb40
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 27 deletions.
74 changes: 54 additions & 20 deletions src/comp/middle/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(...).
* 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<T>(...).
*
*
* Most types are unique or shared. Other possible name combinations for these
Expand All @@ -54,22 +55,19 @@
* 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:
* -------
*
* 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.
*
*/


Expand Down Expand Up @@ -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) {
Expand Down
15 changes: 8 additions & 7 deletions src/comp/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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.
Expand Down

0 comments on commit a11bb40

Please sign in to comment.