Remove vestiges of "layers", insert skeletal do-nothing "kind" pass plus cached calculation of kind for each type.
This commit is contained in:
parent
04611a3e56
commit
63f74f3771
@ -11,6 +11,7 @@ import front::attr;
|
||||
import middle::trans;
|
||||
import middle::resolve;
|
||||
import middle::freevars;
|
||||
import middle::kind;
|
||||
import middle::ty;
|
||||
import middle::typeck;
|
||||
import middle::tstate::ck;
|
||||
@ -147,6 +148,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
|
||||
}
|
||||
time(time_passes, "alias checking",
|
||||
bind middle::alias::check_crate(ty_cx, crate));
|
||||
time[()](time_passes, "kind checking",
|
||||
bind kind::check_crate(ty_cx, crate));
|
||||
let llmod =
|
||||
time[llvm::llvm::ModuleRef](time_passes, "translation",
|
||||
bind trans::trans_crate(sess, crate,
|
||||
|
128
src/comp/middle/kind.rs
Normal file
128
src/comp/middle/kind.rs
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* The kinds are based on two capabilities: copy and send. These may each be
|
||||
* present or absent, though only three of the four combinations can actually
|
||||
* occur:
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPY + SEND = "Unique": no shared substructures or pins, only
|
||||
* interiors and ~ boxes.
|
||||
*
|
||||
* COPY + NOSEND = "Shared": structures containing @, fixed to the local
|
||||
* task heap/pool.
|
||||
*
|
||||
* NOCOPY + NOSEND = "Pinned": structures containing resources or
|
||||
* by-alias closures as interior or
|
||||
* uniquely-boxed members.
|
||||
*
|
||||
* NOCOPY + 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>(...).
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ~ copies deep
|
||||
* @ copies shallow
|
||||
* pinned values (pinned resources, alias-closures) can't be copied
|
||||
* all other interiors copy shallow
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import syntax::ast;
|
||||
import syntax::walk;
|
||||
|
||||
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 }
|
||||
}
|
||||
|
||||
fn kind_to_str(k: kind) -> str {
|
||||
alt k {
|
||||
ast::kind_pinned. { "pinned" }
|
||||
ast::kind_unique. { "unique" }
|
||||
ast::kind_shared. { "shared" }
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(tcx: &ty::ctxt, e: &@ast::expr) {
|
||||
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));
|
||||
}
|
||||
|
||||
fn check_crate(tcx: &ty::ctxt, crate: &@ast::crate) {
|
||||
let visit =
|
||||
{visit_expr_pre: bind check_expr(tcx, _)
|
||||
with walk::default_visitor()};
|
||||
walk::walk_crate(visit, *crate);
|
||||
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:
|
||||
//
|
@ -152,6 +152,7 @@ export ty_fn_args;
|
||||
export type_constr;
|
||||
export type_contains_params;
|
||||
export type_contains_vars;
|
||||
export type_kind;
|
||||
export type_err;
|
||||
export type_err_to_str;
|
||||
export type_has_dynamic_size;
|
||||
@ -216,6 +217,7 @@ type ctxt =
|
||||
rcache: creader_cache,
|
||||
short_names_cache: hashmap[t, str],
|
||||
has_pointer_cache: hashmap[t, bool],
|
||||
kind_cache: hashmap[t, ast::kind],
|
||||
owns_heap_mem_cache: hashmap[t, bool],
|
||||
ast_ty_to_ty_cache: hashmap[@ast::ty, option::t[t]]};
|
||||
|
||||
@ -409,6 +411,7 @@ fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map,
|
||||
rcache: mk_rcache(),
|
||||
short_names_cache: map::mk_hashmap(ty::hash_ty, ty::eq_ty),
|
||||
has_pointer_cache: map::mk_hashmap(ty::hash_ty, ty::eq_ty),
|
||||
kind_cache: map::mk_hashmap(ty::hash_ty, ty::eq_ty),
|
||||
owns_heap_mem_cache: map::mk_hashmap(ty::hash_ty, ty::eq_ty),
|
||||
ast_ty_to_ty_cache: map::mk_hashmap(ast::hash_ty, ast::eq_ty)};
|
||||
populate_type_store(cx);
|
||||
@ -981,7 +984,10 @@ fn type_has_pointers(cx: &ctxt, ty: &t) -> bool {
|
||||
ty_native(_) {/* no-op */ }
|
||||
ty_rec(flds) {
|
||||
for f: field in flds {
|
||||
if type_has_pointers(cx, f.mt.ty) { result = true; }
|
||||
if type_has_pointers(cx, f.mt.ty) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ty_tag(did, tps) {
|
||||
@ -990,8 +996,12 @@ fn type_has_pointers(cx: &ctxt, ty: &t) -> bool {
|
||||
for aty: t in variant.args {
|
||||
// Perform any type parameter substitutions.
|
||||
let arg_ty = substitute_type_params(cx, tps, aty);
|
||||
if type_has_pointers(cx, arg_ty) { result = true; }
|
||||
if type_has_pointers(cx, arg_ty) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if result { break; }
|
||||
}
|
||||
}
|
||||
ty_res(did, inner, tps) {
|
||||
@ -1005,6 +1015,122 @@ fn type_has_pointers(cx: &ctxt, ty: &t) -> bool {
|
||||
ret result;
|
||||
}
|
||||
|
||||
fn type_kind(cx: &ctxt, ty: &t) -> ast::kind {
|
||||
alt cx.kind_cache.find(ty) {
|
||||
some(result) { ret result; }
|
||||
none. {/* fall through */ }
|
||||
}
|
||||
|
||||
let result = ast::kind_unique;
|
||||
|
||||
// Insert a default in case we loop back on self recursively.
|
||||
cx.kind_cache.insert(ty, result);
|
||||
|
||||
alt struct(cx, ty) {
|
||||
|
||||
// Scalar types are unique-kind, no substructure.
|
||||
ty_nil. | ty_bot. | ty_bool. | ty_int. | ty_uint. | ty_float.
|
||||
| ty_machine(_) | ty_char. | ty_native(_) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
// A handful of other built-in are unique too.
|
||||
ty_type. | ty_istr. | ty_native_fn(_, _, _) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
// Those things with refcounts-to-interior are just shared.
|
||||
ty_str. | ty_task. {
|
||||
result = kind_shared;
|
||||
}
|
||||
|
||||
// FIXME: obj is broken for now, since we aren't asserting
|
||||
// anything about its fields.
|
||||
ty_obj(_) { result = kind_shared; }
|
||||
|
||||
// FIXME: the environment capture mode is not fully encoded
|
||||
// here yet, leading to weirdness around closure.
|
||||
ty_fn(proto, _, _, _, _) {
|
||||
result = alt proto {
|
||||
ast::proto_block. { ast::kind_pinned }
|
||||
ast::proto_closure. { ast::kind_shared }
|
||||
_ { ast::kind_unique }
|
||||
}
|
||||
}
|
||||
|
||||
// Those with refcounts-to-inner are the lower of their
|
||||
// inner and shared.
|
||||
ty_box(mt) | ty_vec(mt) {
|
||||
result = kind::lower_kind(ast::kind_shared,
|
||||
type_kind(cx, mt.ty));
|
||||
|
||||
}
|
||||
|
||||
// FIXME: remove ports. Ports currently contribute 'shared'
|
||||
ty_port(t) {
|
||||
result = kind::lower_kind(ast::kind_shared,
|
||||
type_kind(cx, t));
|
||||
}
|
||||
|
||||
// FIXME: remove chans. Chans currently contribute only
|
||||
// their inner.
|
||||
ty_chan(t) {
|
||||
result = type_kind(cx, t);
|
||||
}
|
||||
|
||||
// Pointers and unique boxes / vecs lower to whatever they point to.
|
||||
ty_ptr(tm) | ty_ivec(tm) {
|
||||
result = type_kind(cx, tm.ty);
|
||||
}
|
||||
|
||||
// Records lower to the lowest of their members.
|
||||
ty_rec(flds) {
|
||||
for f: field in flds {
|
||||
result = kind::lower_kind(result, type_kind(cx, f.mt.ty));
|
||||
if result == ast::kind_pinned { break; }
|
||||
}
|
||||
}
|
||||
|
||||
// Tags lower to the lowest of their variants.
|
||||
ty_tag(did, tps) {
|
||||
let variants = tag_variants(cx, did);
|
||||
for variant: variant_info in variants {
|
||||
for aty: t in variant.args {
|
||||
// Perform any type parameter substitutions.
|
||||
let arg_ty = substitute_type_params(cx, tps, aty);
|
||||
result = kind::lower_kind(result, type_kind(cx, arg_ty));
|
||||
if result == ast::kind_pinned { break; }
|
||||
}
|
||||
if result == ast::kind_pinned { break; }
|
||||
}
|
||||
}
|
||||
|
||||
// Resources are always pinned.
|
||||
ty_res(did, inner, tps) {
|
||||
result = ast::kind_pinned;
|
||||
}
|
||||
|
||||
ty_var(_) { fail; }
|
||||
|
||||
ty_param(_) {
|
||||
// FIXME: this should contribute the kind-bound of the typaram,
|
||||
// when those exist.
|
||||
}
|
||||
|
||||
ty_constr(t, _) {
|
||||
result = type_kind(cx, t);
|
||||
}
|
||||
|
||||
_ {
|
||||
cx.sess.bug("missed case: " + ty_to_str(cx, ty));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cx.kind_cache.insert(ty, result);
|
||||
ret result;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: should we just return true for native types in
|
||||
// type_is_scalar?
|
||||
|
@ -27,6 +27,7 @@ mod middle {
|
||||
mod typeck;
|
||||
mod check_alt;
|
||||
mod alias;
|
||||
mod kind;
|
||||
mod freevars;
|
||||
|
||||
mod tstate {
|
||||
|
@ -157,7 +157,7 @@ fn pat_id_map(pat: &@pat) -> pat_id_map {
|
||||
|
||||
tag mutability { mut; imm; maybe_mut; }
|
||||
|
||||
tag layer { layer_value; layer_state; layer_gc; }
|
||||
tag kind { kind_pinned; kind_shared; kind_unique; }
|
||||
|
||||
tag _auth { auth_unsafe; }
|
||||
|
||||
|
@ -483,7 +483,6 @@ fn parse_ty(p: &parser) -> @ast::ty {
|
||||
let t: ast::ty_;
|
||||
// FIXME: do something with this
|
||||
|
||||
parse_layer(p);
|
||||
if eat_word(p, "bool") {
|
||||
t = ast::ty_bool;
|
||||
} else if (eat_word(p, "int")) {
|
||||
@ -1821,7 +1820,7 @@ fn parse_dtor(p: &parser) -> @ast::method {
|
||||
ret @spanned(lo, f.body.span.hi, m);
|
||||
}
|
||||
|
||||
fn parse_item_obj(p: &parser, lyr: ast::layer, attrs: &ast::attribute[]) ->
|
||||
fn parse_item_obj(p: &parser, attrs: &ast::attribute[]) ->
|
||||
@ast::item {
|
||||
let lo = p.get_last_lo_pos();
|
||||
let ident = parse_value_ident(p);
|
||||
@ -1844,7 +1843,7 @@ fn parse_item_obj(p: &parser, lyr: ast::layer, attrs: &ast::attribute[]) ->
|
||||
attrs);
|
||||
}
|
||||
|
||||
fn parse_item_res(p: &parser, lyr: ast::layer, attrs: &ast::attribute[]) ->
|
||||
fn parse_item_res(p: &parser, attrs: &ast::attribute[]) ->
|
||||
@ast::item {
|
||||
let lo = p.get_last_lo_pos();
|
||||
let ident = parse_value_ident(p);
|
||||
@ -1945,7 +1944,6 @@ fn parse_item_native_fn(p: &parser, attrs: &ast::attribute[]) ->
|
||||
|
||||
fn parse_native_item(p: &parser, attrs: &ast::attribute[]) ->
|
||||
@ast::native_item {
|
||||
parse_layer(p);
|
||||
if eat_word(p, "type") {
|
||||
ret parse_item_native_type(p, attrs);
|
||||
} else if (eat_word(p, "fn")) {
|
||||
@ -2084,15 +2082,6 @@ fn parse_item_tag(p: &parser, attrs: &ast::attribute[]) -> @ast::item {
|
||||
ret mk_item(p, lo, hi, id, ast::item_tag(variants, ty_params), attrs);
|
||||
}
|
||||
|
||||
fn parse_layer(p: &parser) -> ast::layer {
|
||||
if eat_word(p, "state") {
|
||||
ret ast::layer_state;
|
||||
} else if (eat_word(p, "gc")) {
|
||||
ret ast::layer_gc;
|
||||
} else { ret ast::layer_value; }
|
||||
fail;
|
||||
}
|
||||
|
||||
fn parse_auth(p: &parser) -> ast::_auth {
|
||||
if eat_word(p, "unsafe") {
|
||||
ret ast::auth_unsafe;
|
||||
@ -2122,15 +2111,14 @@ fn parse_item(p: &parser, attrs: &ast::attribute[]) -> parsed_item {
|
||||
} else if (eat_word(p, "native")) {
|
||||
ret got_item(parse_item_native_mod(p, attrs));
|
||||
}
|
||||
let lyr = parse_layer(p);
|
||||
if eat_word(p, "type") {
|
||||
ret got_item(parse_item_type(p, attrs));
|
||||
} else if (eat_word(p, "tag")) {
|
||||
ret got_item(parse_item_tag(p, attrs));
|
||||
} else if (eat_word(p, "obj")) {
|
||||
ret got_item(parse_item_obj(p, lyr, attrs));
|
||||
ret got_item(parse_item_obj(p, attrs));
|
||||
} else if (eat_word(p, "resource")) {
|
||||
ret got_item(parse_item_res(p, lyr, attrs));
|
||||
ret got_item(parse_item_res(p, attrs));
|
||||
} else { ret no_item; }
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user