about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-07-27 17:49:00 -0700
committerGraydon Hoare <graydon@mozilla.com>2011-07-27 17:49:00 -0700
commit63f74f3771c20fceea294d2dc759ccde8a59a6cd (patch)
tree5504c7c6b9d0acb14f69159095bf63e84f033799 /src/comp
parent04611a3e56b84c9d3439d1625e61d092d860a2c1 (diff)
downloadrust-63f74f3771c20fceea294d2dc759ccde8a59a6cd.tar.gz
rust-63f74f3771c20fceea294d2dc759ccde8a59a6cd.zip
Remove vestiges of "layers", insert skeletal do-nothing "kind" pass plus cached calculation of kind for each type.
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/driver/rustc.rs3
-rw-r--r--src/comp/middle/kind.rs128
-rw-r--r--src/comp/middle/ty.rs130
-rw-r--r--src/comp/rustc.rc1
-rw-r--r--src/comp/syntax/ast.rs2
-rw-r--r--src/comp/syntax/parse/parser.rs20
6 files changed, 265 insertions, 19 deletions
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs
index 3dacbd3b9d0..b267af517b4 100644
--- a/src/comp/driver/rustc.rs
+++ b/src/comp/driver/rustc.rs
@@ -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,
diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs
new file mode 100644
index 00000000000..1d391f80f84
--- /dev/null
+++ b/src/comp/middle/kind.rs
@@ -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:
+//
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 674e5c9b9cb..08e6447c2d0 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -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?
diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc
index 7c9377bd19d..da6f7e5c853 100644
--- a/src/comp/rustc.rc
+++ b/src/comp/rustc.rc
@@ -27,6 +27,7 @@ mod middle {
     mod typeck;
     mod check_alt;
     mod alias;
+    mod kind;
     mod freevars;
 
     mod tstate {
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index 14375e5c73b..45be817f91a 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -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; }
 
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 1782c826785..4d8fe833559 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -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; }
 }