about summary refs log tree commit diff
path: root/src/comp/middle
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/middle
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/middle')
-rw-r--r--src/comp/middle/kind.rs128
-rw-r--r--src/comp/middle/ty.rs130
2 files changed, 256 insertions, 2 deletions
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?