Further refinement to kind system lattice and type-kind rules; first successful caught kind error (prohibits copying a pinned resource, though trans already caught it later).
This commit is contained in:
parent
7073ee4e31
commit
a11bb404a5
@ -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
|
||||
@ -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) {
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user