Remove vestiges of "layers", insert skeletal do-nothing "kind" pass plus cached calculation of kind for each type.

This commit is contained in:
Graydon Hoare 2011-07-27 17:49:00 -07:00
parent 04611a3e56
commit 63f74f3771
6 changed files with 265 additions and 19 deletions

View File

@ -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
View 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:
//

View File

@ -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?

View File

@ -27,6 +27,7 @@ mod middle {
mod typeck;
mod check_alt;
mod alias;
mod kind;
mod freevars;
mod tstate {

View File

@ -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; }

View File

@ -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; }
}