2011-07-27 17:49:00 -07:00
|
|
|
/*
|
|
|
|
* Kinds are types of type.
|
|
|
|
*
|
|
|
|
* Every type has a kind. Every type parameter has a set of kind-capabilities
|
|
|
|
* saying which kind of type may be passed as the parameter.
|
|
|
|
*
|
2011-07-27 23:43:17 -07:00
|
|
|
* The kinds are based on two capabilities: move and send. These may each be
|
2011-07-27 17:49:00 -07:00
|
|
|
* present or absent, though only three of the four combinations can actually
|
|
|
|
* occur:
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
2011-07-27 21:23:40 -07:00
|
|
|
* MOVE + SEND = "Unique": no shared substructures or pins, only
|
2011-07-27 17:49:00 -07:00
|
|
|
* interiors and ~ boxes.
|
|
|
|
*
|
2011-07-27 21:23:40 -07:00
|
|
|
* MOVE + NOSEND = "Shared": structures containing @, fixed to the local
|
|
|
|
* task heap/pool; or ~ structures pointing to
|
|
|
|
* pinned values.
|
2011-07-27 17:49:00 -07:00
|
|
|
*
|
2011-07-27 21:23:40 -07:00
|
|
|
* NOMOVE + NOSEND = "Pinned": structures directly containing resources, or
|
2011-07-27 17:49:00 -07:00
|
|
|
* by-alias closures as interior or
|
|
|
|
* uniquely-boxed members.
|
|
|
|
*
|
2011-07-27 21:23:40 -07:00
|
|
|
* NOMOVE + SEND = -- : no types are like this.
|
2011-07-27 17:49:00 -07:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* Since this forms a lattice, we denote the capabilites in terms of a
|
2011-07-27 21:23:40 -07:00
|
|
|
* worst-case requirement. That is, if your function needs to move-and-send
|
2011-07-27 23:43:17 -07:00
|
|
|
* (or copy) your T, you write fn<~T>(...). If you need to move but not send,
|
2011-07-27 21:23:40 -07:00
|
|
|
* you write fn<@T>(...). And if you need neither -- can work with any sort of
|
|
|
|
* pinned data at all -- then you write fn<T>(...).
|
2011-07-27 17:49:00 -07:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* Most types are unique or shared. Other possible name combinations for these
|
|
|
|
* two: (tree, graph; pruned, pooled; message, local; owned, common) are
|
|
|
|
* plausible but nothing stands out as completely pithy-and-obvious.
|
|
|
|
*
|
|
|
|
* Resources cannot be copied or sent; they're pinned. They can't be copied
|
|
|
|
* because it would interfere with destruction (multiple destruction?) They
|
|
|
|
* cannot be sent because we don't want to oblige the communication system to
|
|
|
|
* run destructors in some weird limbo context of messages-in-transit. It
|
|
|
|
* should always be ok to just free messages it's dropping.
|
|
|
|
*
|
|
|
|
* Note that obj~ and fn~ -- those that capture a unique environment -- can be
|
|
|
|
* sent, so satisfy ~T. So can plain obj and fn.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Further notes on copying and moving; sending is accomplished by calling a
|
|
|
|
* move-in operator on something constrained to a unique type ~T.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* COPYING:
|
|
|
|
* --------
|
|
|
|
*
|
|
|
|
* A copy is made any time you pass-by-value or execute the = operator in a
|
|
|
|
* non-init expression.
|
|
|
|
*
|
2011-07-27 21:23:40 -07:00
|
|
|
* @ copies shallow, is always legal
|
|
|
|
* ~ copies deep, is only legal if pointee is unique.
|
2011-07-27 17:49:00 -07:00
|
|
|
* pinned values (pinned resources, alias-closures) can't be copied
|
2011-07-27 21:23:40 -07:00
|
|
|
* all other unique (eg. interior) values copy shallow
|
|
|
|
*
|
|
|
|
* Note this means that only type parameters constrained to ~T can be copied.
|
2011-07-27 17:49:00 -07:00
|
|
|
*
|
|
|
|
* MOVING:
|
|
|
|
* -------
|
|
|
|
*
|
|
|
|
* A move is made any time you pass-by-move (that is, with 'move' mode) or
|
|
|
|
* execute the <- operator.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import syntax::ast;
|
2011-08-21 21:44:41 -07:00
|
|
|
import syntax::ast_util;
|
2011-07-28 07:42:51 +02:00
|
|
|
import syntax::visit;
|
2011-07-27 17:49:00 -07:00
|
|
|
|
2011-08-15 16:38:23 -07:00
|
|
|
import std::vec;
|
2011-08-23 15:58:53 -07:00
|
|
|
import std::option;
|
2011-09-01 17:27:58 -07:00
|
|
|
import std::str;
|
2011-07-29 18:38:22 -07:00
|
|
|
|
2011-07-27 17:49:00 -07:00
|
|
|
import ast::kind;
|
|
|
|
import ast::kind_unique;
|
|
|
|
import ast::kind_shared;
|
|
|
|
import ast::kind_pinned;
|
|
|
|
|
|
|
|
fn kind_lteq(a: kind, b: kind) -> bool {
|
|
|
|
alt a {
|
|
|
|
kind_pinned. { true }
|
|
|
|
kind_shared. { b != kind_pinned }
|
|
|
|
kind_unique. { b == kind_unique }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lower_kind(a: kind, b: kind) -> kind {
|
|
|
|
if kind_lteq(a, b) { a } else { b }
|
|
|
|
}
|
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
fn kind_to_str(k: kind) -> str {
|
2011-07-27 17:49:00 -07:00
|
|
|
alt k {
|
2011-09-02 15:34:58 -07:00
|
|
|
ast::kind_pinned. { "pinned" }
|
|
|
|
ast::kind_unique. { "unique" }
|
|
|
|
ast::kind_shared. { "shared" }
|
2011-07-27 17:49:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn type_and_kind(tcx: ty::ctxt, e: @ast::expr) ->
|
2011-08-19 15:16:48 -07:00
|
|
|
{ty: ty::t, kind: ast::kind} {
|
2011-07-27 17:49:00 -07:00
|
|
|
let t = ty::expr_ty(tcx, e);
|
|
|
|
let k = ty::type_kind(tcx, t);
|
2011-07-27 21:23:40 -07:00
|
|
|
{ty: t, kind: k}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn need_expr_kind(tcx: ty::ctxt, e: @ast::expr, k_need: ast::kind,
|
|
|
|
descr: str) {
|
2011-07-27 21:23:40 -07:00
|
|
|
let tk = type_and_kind(tcx, e);
|
2011-09-01 18:49:10 -07:00
|
|
|
log #fmt["for %s: want %s type, got %s type %s", descr,
|
2011-08-19 15:16:48 -07:00
|
|
|
kind_to_str(k_need), kind_to_str(tk.kind),
|
2011-08-28 00:24:28 -07:00
|
|
|
util::ppaux::ty_to_str(tcx, tk.ty)];
|
2011-07-27 21:23:40 -07:00
|
|
|
|
2011-08-19 15:16:48 -07:00
|
|
|
if !kind_lteq(k_need, tk.kind) {
|
2011-07-27 21:23:40 -07:00
|
|
|
let s =
|
2011-09-01 18:49:10 -07:00
|
|
|
#fmt["mismatched kinds for %s: needed %s type, got %s type %s",
|
2011-09-02 15:34:58 -07:00
|
|
|
descr, kind_to_str(k_need), kind_to_str(tk.kind),
|
2011-08-28 00:24:28 -07:00
|
|
|
util::ppaux::ty_to_str(tcx, tk.ty)];
|
|
|
|
tcx.sess.span_err(e.span, s);
|
2011-07-27 21:23:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn need_shared_lhs_rhs(tcx: ty::ctxt, a: @ast::expr, b: @ast::expr, op: str) {
|
2011-09-02 15:34:58 -07:00
|
|
|
need_expr_kind(tcx, a, ast::kind_shared, op + " lhs");
|
|
|
|
need_expr_kind(tcx, b, ast::kind_shared, op + " rhs");
|
2011-07-27 21:23:40 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn check_expr(tcx: ty::ctxt, e: @ast::expr) {
|
2011-07-27 21:23:40 -07:00
|
|
|
alt e.node {
|
2011-09-02 15:34:58 -07:00
|
|
|
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_assign_op(_, a, b) { need_shared_lhs_rhs(tcx, a, b, "op="); }
|
|
|
|
ast::expr_swap(a, b) { need_shared_lhs_rhs(tcx, a, b, "<->"); }
|
2011-08-23 15:58:53 -07:00
|
|
|
ast::expr_copy(a) {
|
2011-09-02 15:34:58 -07:00
|
|
|
need_expr_kind(tcx, a, ast::kind_shared, "'copy' operand");
|
2011-08-23 15:58:53 -07:00
|
|
|
}
|
|
|
|
ast::expr_ret(option::some(a)) {
|
2011-09-02 15:34:58 -07:00
|
|
|
need_expr_kind(tcx, a, ast::kind_shared, "'ret' operand");
|
2011-08-23 15:58:53 -07:00
|
|
|
}
|
|
|
|
ast::expr_be(a) {
|
2011-09-02 15:34:58 -07:00
|
|
|
need_expr_kind(tcx, a, ast::kind_shared, "'be' operand");
|
2011-08-23 15:58:53 -07:00
|
|
|
}
|
|
|
|
ast::expr_fail(option::some(a)) {
|
2011-09-02 15:34:58 -07:00
|
|
|
need_expr_kind(tcx, a, ast::kind_shared, "'fail' operand");
|
2011-08-23 15:58:53 -07:00
|
|
|
}
|
2011-07-29 18:38:22 -07:00
|
|
|
ast::expr_call(callee, _) {
|
|
|
|
let tpt = ty::expr_ty_params_and_ty(tcx, callee);
|
2011-08-19 15:16:48 -07:00
|
|
|
|
2011-07-29 18:38:22 -07:00
|
|
|
// If we have typarams, we're calling an item; we need to check
|
|
|
|
// that all the types we're supplying as typarams conform to the
|
|
|
|
// typaram kind constraints on that item.
|
2011-08-15 16:38:23 -07:00
|
|
|
if vec::len(tpt.params) != 0u {
|
2011-09-02 15:34:58 -07:00
|
|
|
let callee_def =
|
|
|
|
ast_util::def_id_of_def(tcx.def_map.get(callee.id));
|
2011-07-29 18:38:22 -07:00
|
|
|
let item_tk = ty::lookup_item_type(tcx, callee_def);
|
|
|
|
let i = 0;
|
2011-08-19 15:16:48 -07:00
|
|
|
assert (vec::len(item_tk.kinds) == vec::len(tpt.params));
|
2011-07-29 18:38:22 -07:00
|
|
|
for k_need: ast::kind in item_tk.kinds {
|
2011-08-19 15:16:48 -07:00
|
|
|
let t = tpt.params[i];
|
2011-07-29 18:38:22 -07:00
|
|
|
let k = ty::type_kind(tcx, t);
|
2011-08-19 15:16:48 -07:00
|
|
|
if !kind_lteq(k_need, k) {
|
|
|
|
let s =
|
2011-09-01 18:49:10 -07:00
|
|
|
#fmt["mismatched kinds for typaram %d: \
|
2011-07-29 18:38:22 -07:00
|
|
|
needed %s type, got %s type %s",
|
2011-08-19 15:16:48 -07:00
|
|
|
i, kind_to_str(k_need), kind_to_str(k),
|
2011-08-28 00:24:28 -07:00
|
|
|
util::ppaux::ty_to_str(tcx, t)];
|
|
|
|
tcx.sess.span_err(e.span, s);
|
2011-07-29 18:38:22 -07:00
|
|
|
}
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
2011-07-29 16:40:23 -07:00
|
|
|
}
|
2011-07-27 21:23:40 -07:00
|
|
|
_ { }
|
|
|
|
}
|
2011-07-27 17:49:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
|
2011-08-19 15:16:48 -07:00
|
|
|
let visit =
|
|
|
|
visit::mk_simple_visitor(@{visit_expr: bind check_expr(tcx, _)
|
|
|
|
with *visit::default_simple_visitor()});
|
2011-07-28 07:42:51 +02:00
|
|
|
visit::visit_crate(*crate, (), visit);
|
2011-07-27 17:49:00 -07:00
|
|
|
tcx.sess.abort_if_errors();
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
|
|
|
// End:
|
|
|
|
//
|