Skip to content

Commit

Permalink
Remove vestiges of "layers", insert skeletal do-nothing "kind" pass p…
Browse files Browse the repository at this point in the history
…lus cached calculation of kind for each type.
  • Loading branch information
graydon committed Jul 28, 2011
1 parent 04611a3 commit 63f74f3
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 19 deletions.
3 changes: 3 additions & 0 deletions src/comp/driver/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
128 changes: 128 additions & 0 deletions src/comp/middle/kind.rs
Original file line number Diff line number Diff line change
@@ -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:
//
130 changes: 128 additions & 2 deletions src/comp/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]]};

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -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?
Expand Down
1 change: 1 addition & 0 deletions src/comp/rustc.rc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod middle {
mod typeck;
mod check_alt;
mod alias;
mod kind;
mod freevars;

mod tstate {
Expand Down
2 changes: 1 addition & 1 deletion src/comp/syntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
Loading

0 comments on commit 63f74f3

Please sign in to comment.