about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-08-10 16:21:34 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-08-10 16:22:06 -0700
commit0101125a962abae18525d6014cd26ad10bbb96e6 (patch)
treee3e15717c4f19cd55afb745853b13944d840d3c0 /src/rustc
parent99942ae430738ba43a2896973fa7f1a8ffe445a2 (diff)
rustc: Make function types have vstores in them
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/metadata/tydecode.rs14
-rw-r--r--src/rustc/metadata/tyencode.rs15
-rw-r--r--src/rustc/middle/block_use.rs2
-rw-r--r--src/rustc/middle/borrowck/check_loans.rs5
-rw-r--r--src/rustc/middle/capture.rs12
-rw-r--r--src/rustc/middle/check_loop.rs3
-rw-r--r--src/rustc/middle/kind.rs10
-rw-r--r--src/rustc/middle/mem_categorization.rs8
-rw-r--r--src/rustc/middle/trans/base.rs10
-rw-r--r--src/rustc/middle/trans/closure.rs33
-rw-r--r--src/rustc/middle/trans/foreign.rs2
-rw-r--r--src/rustc/middle/trans/reflect.rs10
-rw-r--r--src/rustc/middle/trans/shape.rs22
-rw-r--r--src/rustc/middle/trans/type_use.rs7
-rw-r--r--src/rustc/middle/ty.rs65
-rw-r--r--src/rustc/middle/typeck.rs2
-rw-r--r--src/rustc/middle/typeck/astconv.rs4
-rw-r--r--src/rustc/middle/typeck/check.rs49
-rw-r--r--src/rustc/middle/typeck/check/method.rs6
-rw-r--r--src/rustc/middle/typeck/collect.rs7
-rw-r--r--src/rustc/middle/typeck/infer.rs53
-rw-r--r--src/rustc/util/ppaux.rs12
22 files changed, 237 insertions, 114 deletions
diff --git a/src/rustc/metadata/tydecode.rs b/src/rustc/metadata/tydecode.rs
index e66d0cef71b..80c64430ec3 100644
--- a/src/rustc/metadata/tydecode.rs
+++ b/src/rustc/metadata/tydecode.rs
@@ -85,13 +85,11 @@ fn parse_ty_rust_fn(st: @pstate, conv: conv_did) -> ty::t {
     return ty::mk_fn(st.tcx, parse_ty_fn(st, conv));
 }
 
-fn parse_proto(c: char) -> ast::proto {
-    match c {
-      '~' => ast::proto_uniq,
-      '@' => ast::proto_box,
-      '&' => ast::proto_block,
-      'n' => ast::proto_bare,
-      _ => fail ~"illegal fn type kind " + str::from_char(c)
+fn parse_proto(st: @pstate) -> ty::fn_proto {
+    match next(st) {
+        'n' => ty::proto_bare,
+        'v' => ty::proto_vstore(parse_vstore(st)),
+        c => fail ~"illegal proto type kind " + str::from_char(c)
     }
 }
 
@@ -360,7 +358,7 @@ fn parse_purity(c: char) -> purity {
 }
 
 fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::fn_ty {
-    let proto = parse_proto(next(st));
+    let proto = parse_proto(st);
     let purity = parse_purity(next(st));
     let bounds = parse_bounds(st, conv);
     assert (next(st) == '[');
diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs
index 9e67157b181..30b2a21167a 100644
--- a/src/rustc/metadata/tyencode.rs
+++ b/src/rustc/metadata/tyencode.rs
@@ -306,12 +306,15 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
       }
     }
 }
-fn enc_proto(w: io::writer, proto: proto) {
+
+fn enc_proto(w: io::writer, cx: @ctxt, proto: ty::fn_proto) {
+    w.write_str(&"f");
     match proto {
-      proto_uniq => w.write_str(&"f~"),
-      proto_box => w.write_str(&"f@"),
-      proto_block => w.write_str(~"f&"),
-      proto_bare => w.write_str(&"fn")
+        ty::proto_bare => w.write_str(&"n"),
+        ty::proto_vstore(vstore) => {
+            w.write_str(&"v");
+            enc_vstore(w, cx, vstore);
+        }
     }
 }
 
@@ -335,7 +338,7 @@ fn enc_purity(w: io::writer, p: purity) {
 }
 
 fn enc_ty_fn(w: io::writer, cx: @ctxt, ft: ty::fn_ty) {
-    enc_proto(w, ft.proto);
+    enc_proto(w, cx, ft.proto);
     enc_purity(w, ft.purity);
     enc_bounds(w, cx, ft.bounds);
     w.write_char('[');
diff --git a/src/rustc/middle/block_use.rs b/src/rustc/middle/block_use.rs
index 2896ad32d6a..bb33b8c92a8 100644
--- a/src/rustc/middle/block_use.rs
+++ b/src/rustc/middle/block_use.rs
@@ -14,7 +14,7 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
 fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
     if !cx.allow_block {
         match ty::get(ty::expr_ty(cx.tcx, ex)).struct {
-          ty::ty_fn({proto: p, _}) if is_blockish(p) => {
+          ty::ty_fn({proto: p, _}) if ty::is_blockish(p) => {
             cx.tcx.sess.span_err(ex.span,
                ~"expressions with stack closure type \
                 can only appear in callee or (by-ref) argument position");
diff --git a/src/rustc/middle/borrowck/check_loans.rs b/src/rustc/middle/borrowck/check_loans.rs
index 301c78aa109..4c3ee9eb4dd 100644
--- a/src/rustc/middle/borrowck/check_loans.rs
+++ b/src/rustc/middle/borrowck/check_loans.rs
@@ -218,10 +218,7 @@ impl check_loan_ctxt {
     fn is_stack_closure(id: ast::node_id) -> bool {
         let fn_ty = ty::node_id_to_type(self.tcx(), id);
         let proto = ty::ty_fn_proto(fn_ty);
-        match proto {
-          ast::proto_block => true,
-          ast::proto_bare | ast::proto_uniq | ast::proto_box => false
-        }
+        return ty::is_blockish(proto);
     }
 
     fn is_allowed_pure_arg(expr: @ast::expr) -> bool {
diff --git a/src/rustc/middle/capture.rs b/src/rustc/middle/capture.rs
index 266c31b2805..b45064db88d 100644
--- a/src/rustc/middle/capture.rs
+++ b/src/rustc/middle/capture.rs
@@ -59,7 +59,7 @@ fn check_capture_clause(tcx: ty::ctxt,
 
 fn compute_capture_vars(tcx: ty::ctxt,
                         fn_expr_id: ast::node_id,
-                        fn_proto: ast::proto,
+                        fn_proto: ty::fn_proto,
                         cap_clause: ast::capture_clause) -> ~[capture_var] {
     let freevars = freevars::get_freevars(tcx, fn_expr_id);
     let cap_map = map::int_hash();
@@ -101,10 +101,12 @@ fn compute_capture_vars(tcx: ty::ctxt,
     // now go through anything that is referenced but was not explicitly
     // named and add that
 
-    let implicit_mode = match fn_proto {
-      ast::proto_block => cap_ref,
-      ast::proto_bare | ast::proto_box | ast::proto_uniq => cap_copy
-    };
+    let implicit_mode;
+    if ty::is_blockish(fn_proto) {
+        implicit_mode = cap_ref;
+    } else {
+        implicit_mode = cap_copy;
+    }
 
     do vec::iter(*freevars) |fvar| {
         let fvar_def_id = ast_util::def_id_of_def(fvar.def).node;
diff --git a/src/rustc/middle/check_loop.rs b/src/rustc/middle/check_loop.rs
index dad51ed48b4..a105ce68529 100644
--- a/src/rustc/middle/check_loop.rs
+++ b/src/rustc/middle/check_loop.rs
@@ -25,7 +25,8 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
                 v.visit_block(b, {in_loop: false, can_ret: false}, v);
               }
               expr_loop_body(@{node: expr_fn_block(_, b, _), _}) => {
-                let blk = is_blockish(ty::ty_fn_proto(ty::expr_ty(tcx, e)));
+                let blk = ty::is_blockish(ty::ty_fn_proto(ty::expr_ty(tcx,
+                                                                      e)));
                 v.visit_block(b, {in_loop: true, can_ret: blk}, v);
               }
               expr_break => {
diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs
index 61d9938e388..9968318292c 100644
--- a/src/rustc/middle/kind.rs
+++ b/src/rustc/middle/kind.rs
@@ -144,10 +144,12 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
 
     let fty = ty::node_id_to_type(cx.tcx, id);
     match ty::ty_fn_proto(fty) {
-      proto_uniq => b(check_for_uniq),
-      proto_box => b(check_for_box),
-      proto_bare => b(check_for_bare),
-      proto_block => b(check_for_block)
+      ty::proto_vstore(ty::vstore_uniq) => b(check_for_uniq),
+      ty::proto_vstore(ty::vstore_box) => b(check_for_box),
+      ty::proto_bare => b(check_for_bare),
+      ty::proto_vstore(ty::vstore_slice(_)) => b(check_for_block),
+      ty::proto_vstore(ty::vstore_fixed(_)) =>
+        fail ~"fixed vstore not allowed here"
     }
 }
 
diff --git a/src/rustc/middle/mem_categorization.rs b/src/rustc/middle/mem_categorization.rs
index d600f63246a..cf9ee1bc190 100644
--- a/src/rustc/middle/mem_categorization.rs
+++ b/src/rustc/middle/mem_categorization.rs
@@ -383,18 +383,22 @@ impl &mem_categorization_ctxt {
             let ty = ty::node_id_to_type(self.tcx, fn_node_id);
             let proto = ty::ty_fn_proto(ty);
             match proto {
-              ast::proto_block => {
+              ty::proto_vstore(ty::vstore_slice(_)) => {
                 let upcmt = self.cat_def(id, span, expr_ty, *inner);
                 @{id:id, span:span,
                   cat:cat_stack_upvar(upcmt), lp:upcmt.lp,
                   mutbl:upcmt.mutbl, ty:upcmt.ty}
               }
-              ast::proto_bare | ast::proto_uniq | ast::proto_box => {
+              ty::proto_bare |
+              ty::proto_vstore(ty::vstore_uniq) |
+              ty::proto_vstore(ty::vstore_box) => {
                 // FIXME #2152 allow mutation of moved upvars
                 @{id:id, span:span,
                   cat:cat_special(sk_heap_upvar), lp:none,
                   mutbl:m_imm, ty:expr_ty}
               }
+              ty::proto_vstore(ty::vstore_fixed(_)) =>
+                fail ~"fixed vstore not allowed here"
             }
           }
 
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 9054b5a4611..0c7d04d143e 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -2043,7 +2043,8 @@ fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> option<ty::t> {
       }
       ty::ty_trait(_, _) => {
         some(ty::mk_fn(tcx, {purity: ast::impure_fn,
-                             proto: ast::proto_box,
+                             proto: ty::proto_vstore(ty::vstore_slice
+                                                     (ty::re_static)),
                              bounds: @~[],
                              inputs: ~[],
                              output: ty::mk_nil(tcx),
@@ -3774,8 +3775,11 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
           }
           ast::expr_addr_of(_, x) => { return trans_addr_of(bcx, x, dest); }
           ast::expr_fn(proto, decl, body, cap_clause) => {
-            return closure::trans_expr_fn(bcx, proto, decl, body, e.id,
-                                       cap_clause, none, dest);
+            // XXX: This syntax should be reworked a bit (in the parser I
+            // guess?); @fn() { ... } won't work.
+            return closure::trans_expr_fn(bcx, ty::ast_proto_to_proto(proto),
+                                          decl, body, e.id, cap_clause, none,
+                                          dest);
           }
           ast::expr_fn_block(decl, body, cap_clause) => {
             match check ty::get(expr_ty(bcx, e)).struct {
diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs
index 80fde9955d0..997991a5aa2 100644
--- a/src/rustc/middle/trans/closure.rs
+++ b/src/rustc/middle/trans/closure.rs
@@ -347,7 +347,7 @@ fn load_environment(fcx: fn_ctxt,
 }
 
 fn trans_expr_fn(bcx: block,
-                 proto: ast::proto,
+                 proto: ty::fn_proto,
                  decl: ast::fn_decl,
                  body: ast::blk,
                  id: ast::node_id,
@@ -364,8 +364,8 @@ fn trans_expr_fn(bcx: block,
     let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
 
     let trans_closure_env = fn@(ck: ty::closure_kind) -> result {
-        let cap_vars = capture::compute_capture_vars(
-            ccx.tcx, id, proto, cap_clause);
+        let cap_vars = capture::compute_capture_vars(ccx.tcx, id, proto,
+                                                     cap_clause);
         let ret_handle = match is_loop_body { some(x) => x, none => none };
         let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, ck, id,
                                                    ret_handle);
@@ -382,14 +382,19 @@ fn trans_expr_fn(bcx: block,
     };
 
     let {bcx: bcx, val: closure} = match proto {
-      ast::proto_block => trans_closure_env(ty::ck_block),
-      ast::proto_box => trans_closure_env(ty::ck_box),
-      ast::proto_uniq => trans_closure_env(ty::ck_uniq),
-      ast::proto_bare => {
+      ty::proto_vstore(ty::vstore_slice(_)) =>
+        trans_closure_env(ty::ck_block),
+      ty::proto_vstore(ty::vstore_box) =>
+        trans_closure_env(ty::ck_box),
+      ty::proto_vstore(ty::vstore_uniq) =>
+        trans_closure_env(ty::ck_uniq),
+      ty::proto_bare => {
         trans_closure(ccx, sub_path, decl, body, llfn, no_self, none,
                       id, |_fcx| { }, |_bcx| { });
         {bcx: bcx, val: C_null(T_opaque_box_ptr(ccx))}
       }
+      ty::proto_vstore(ty::vstore_fixed(_)) =>
+        fail ~"vstore_fixed unexpected"
     };
     fill_fn_pair(bcx, get_dest_addr(dest), llfn, closure);
 
@@ -416,11 +421,15 @@ fn make_fn_glue(
     };
 
     return match ty::get(t).struct {
-      ty::ty_fn({proto: ast::proto_bare, _}) |
-      ty::ty_fn({proto: ast::proto_block, _}) => bcx,
-      ty::ty_fn({proto: ast::proto_uniq, _}) => fn_env(ty::ck_uniq),
-      ty::ty_fn({proto: ast::proto_box, _}) => fn_env(ty::ck_box),
-      _ => fail ~"make_fn_glue invoked on non-function type"
+      ty::ty_fn({proto: ty::proto_bare, _}) |
+      ty::ty_fn({proto: ty::proto_vstore(ty::vstore_slice(_)), _}) =>
+        bcx,
+      ty::ty_fn({proto: ty::proto_vstore(ty::vstore_uniq), _}) =>
+        fn_env(ty::ck_uniq),
+      ty::ty_fn({proto: ty::proto_vstore(ty::vstore_box), _}) =>
+        fn_env(ty::ck_box),
+      _ =>
+        fail ~"make_fn_glue invoked on non-function type"
     };
 }
 
diff --git a/src/rustc/middle/trans/foreign.rs b/src/rustc/middle/trans/foreign.rs
index 3eac4a7e663..a81e665356f 100644
--- a/src/rustc/middle/trans/foreign.rs
+++ b/src/rustc/middle/trans/foreign.rs
@@ -960,7 +960,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
         let frameaddress_val = Call(bcx, frameaddress, ~[C_i32(0i32)]);
         let fty = ty::mk_fn(bcx.tcx(), {
             purity: ast::impure_fn,
-            proto: ast::proto_block,
+            proto: ty::proto_vstore(ty::vstore_slice(ty::re_static)),
             bounds: @~[],
             inputs: ~[{
                 mode: ast::expl(ast::by_val),
diff --git a/src/rustc/middle/trans/reflect.rs b/src/rustc/middle/trans/reflect.rs
index ae93021583b..7f8752c84d4 100644
--- a/src/rustc/middle/trans/reflect.rs
+++ b/src/rustc/middle/trans/reflect.rs
@@ -185,10 +185,12 @@ impl reflector {
               ast::extern_fn => 3u
             };
             let protoval = match fty.proto {
-              ast::proto_bare => 0u,
-              ast::proto_uniq => 2u,
-              ast::proto_box => 3u,
-              ast::proto_block => 4u
+              ty::proto_bare => 0u,
+              ty::proto_vstore(ty::vstore_uniq) => 2u,
+              ty::proto_vstore(ty::vstore_box) => 3u,
+              ty::proto_vstore(ty::vstore_slice(_)) => 4u,
+              ty::proto_vstore(ty::vstore_fixed(_)) =>
+                fail ~"fixed unexpected"
             };
             let retval = match fty.ret_style {
               ast::noreturn => 0u,
diff --git a/src/rustc/middle/trans/shape.rs b/src/rustc/middle/trans/shape.rs
index 4246defbe0f..68bddb8d151 100644
--- a/src/rustc/middle/trans/shape.rs
+++ b/src/rustc/middle/trans/shape.rs
@@ -351,14 +351,20 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t) -> ~[u8] {
       ty::ty_param(*) => {
         ccx.tcx.sess.bug(~"non-monomorphized type parameter");
       }
-      ty::ty_fn({proto: ast::proto_box, _}) => ~[shape_box_fn],
-      ty::ty_fn({proto: ast::proto_uniq, _}) => ~[shape_uniq_fn],
-      ty::ty_fn({proto: ast::proto_block, _}) => ~[shape_stack_fn],
-      ty::ty_fn({proto: ast::proto_bare, _}) => ~[shape_bare_fn],
-      ty::ty_opaque_closure_ptr(_) => ~[shape_opaque_closure_ptr],
-      ty::ty_var(_) | ty::ty_var_integral(_) | ty::ty_self => {
-        ccx.sess.bug(~"shape_of: unexpected type struct found");
-      }
+      ty::ty_fn({proto: ty::proto_vstore(ty::vstore_box), _}) =>
+        ~[shape_box_fn],
+      ty::ty_fn({proto: ty::proto_vstore(ty::vstore_uniq), _}) =>
+        ~[shape_uniq_fn],
+      ty::ty_fn({proto: ty::proto_vstore(ty::vstore_slice(_)), _}) =>
+        ~[shape_stack_fn],
+      ty::ty_fn({proto: ty::proto_vstore(ty::vstore_fixed(_)), _}) =>
+        fail ~"fixed vstore is impossible",
+      ty::ty_fn({proto: ty::proto_bare, _}) =>
+        ~[shape_bare_fn],
+      ty::ty_opaque_closure_ptr(_) =>
+        ~[shape_opaque_closure_ptr],
+      ty::ty_var(_) | ty::ty_var_integral(_) | ty::ty_self =>
+        ccx.sess.bug(~"shape_of: unexpected type struct found")
     }
 }
 
diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs
index c21ad7c992b..d630653ef27 100644
--- a/src/rustc/middle/trans/type_use.rs
+++ b/src/rustc/middle/trans/type_use.rs
@@ -202,13 +202,16 @@ fn mark_for_expr(cx: ctx, e: @expr) {
       }
       expr_fn(*) | expr_fn_block(*) => {
         match ty::ty_fn_proto(ty::expr_ty(cx.ccx.tcx, e)) {
-          proto_bare | proto_uniq => {}
-          proto_box | proto_block => {
+          ty::proto_bare | ty::proto_vstore(ty::vstore_uniq) => {}
+          ty::proto_vstore(ty::vstore_box) |
+          ty::proto_vstore(ty::vstore_slice(_)) => {
             for vec::each(*freevars::get_freevars(cx.ccx.tcx, e.id)) |fv| {
                 let node_id = ast_util::def_id_of_def(fv.def).node;
                 node_type_needs(cx, use_repr, node_id);
             }
           }
+          ty::proto_vstore(ty::vstore_fixed(_)) =>
+            fail ~"vstore_fixed not allowed here"
         }
       }
       expr_assign(val, _) | expr_swap(val, _) | expr_assign_op(_, val, _) |
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 90ea9b3a6b1..b74dad6cda9 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -171,9 +171,13 @@ export terr_sorts, terr_vec, terr_str, terr_record_size, terr_tuple_size;
 export terr_regions_differ, terr_mutability, terr_purity_mismatch;
 export terr_proto_mismatch;
 export terr_ret_style_mismatch;
+export terr_fn;
 export purity_to_str;
 export param_tys_in_type;
 export eval_repeat_count;
+export fn_proto, proto_bare, proto_vstore;
+export ast_proto_to_proto;
+export is_blockish;
 
 // Data types
 
@@ -316,6 +320,11 @@ enum closure_kind {
     ck_uniq,
 }
 
+enum fn_proto {
+    proto_bare,             // supertype of all other protocols
+    proto_vstore(vstore)
+}
+
 /// Innards of a function type:
 ///
 /// - `purity` is the function's effect (pure, impure, unsafe).
@@ -325,7 +334,7 @@ enum closure_kind {
 /// - `output` is the return type.
 /// - `ret_style` indicates whether the function returns a value or fails.
 type fn_ty = {purity: ast::purity,
-              proto: ast::proto,
+              proto: fn_proto,
               bounds: @~[param_bound],
               inputs: ~[arg],
               output: t,
@@ -442,7 +451,7 @@ enum sty {
 }
 
 enum terr_vstore_kind {
-    terr_vec, terr_str
+    terr_vec, terr_str, terr_fn
 }
 
 // Data structures used in type unification
@@ -451,7 +460,7 @@ enum type_err {
     terr_ret_style_mismatch(ast::ret_style, ast::ret_style),
     terr_purity_mismatch(purity, purity),
     terr_mutability,
-    terr_proto_mismatch(ast::proto, ast::proto),
+    terr_proto_mismatch(ty::fn_proto, ty::fn_proto),
     terr_box_mutability,
     terr_ptr_mutability,
     terr_ref_mutability,
@@ -1308,7 +1317,7 @@ fn type_needs_drop(cx: ctxt, ty: t) -> bool {
       }
       ty_fn(ref fty) => {
         match fty.proto {
-          proto_bare | proto_block => false,
+          proto_bare | proto_vstore(vstore_slice(_)) => false,
           _ => true
         }
       }
@@ -1548,13 +1557,18 @@ pure fn kind_is_owned(k: kind) -> bool {
     *k & KIND_MASK_OWNED == KIND_MASK_OWNED
 }
 
-fn proto_kind(p: proto) -> kind {
+fn proto_kind(p: fn_proto) -> kind {
     match p {
-      ast::proto_block => kind_noncopyable() | kind_(KIND_MASK_DEFAULT_MODE),
-      ast::proto_box => kind_safe_for_default_mode() | kind_owned(),
-      ast::proto_uniq => kind_send_copy() | kind_owned(),
-      ast::proto_bare => kind_safe_for_default_mode_send() | kind_const() |
-                           kind_owned()
+      proto_vstore(vstore_slice(_)) =>
+        kind_noncopyable() | kind_(KIND_MASK_DEFAULT_MODE),
+      proto_vstore(vstore_box) =>
+        kind_safe_for_default_mode() | kind_owned(),
+      proto_vstore(vstore_uniq) =>
+        kind_send_copy() | kind_owned(),
+      proto_vstore(vstore_fixed(_)) =>
+        fail ~"fixed vstore protos are not allowed",
+      proto_bare =>
+        kind_safe_for_default_mode_send() | kind_const() | kind_owned()
     }
 }
 
@@ -2293,7 +2307,7 @@ fn ty_fn_args(fty: t) -> ~[arg] {
     }
 }
 
-fn ty_fn_proto(fty: t) -> ast::proto {
+fn ty_fn_proto(fty: t) -> fn_proto {
     match get(fty).struct {
       ty_fn(ref f) => f.proto,
       _ => fail ~"ty_fn_proto() called on non-fn type"
@@ -2576,7 +2590,11 @@ fn ty_sort_str(cx: ctxt, t: t) -> ~str {
 
 fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
     fn terr_vstore_kind_to_str(k: terr_vstore_kind) -> ~str {
-        match k { terr_vec => ~"[]", terr_str => ~"str" }
+        match k {
+            terr_vec => ~"[]",
+            terr_str => ~"str",
+            terr_fn => ~"fn"
+        }
     }
 
     match *err {
@@ -2597,7 +2615,8 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
       }
       terr_proto_mismatch(e, a) => {
         return fmt!{"closure protocol mismatch (%s vs %s)",
-                 proto_to_str(e), proto_to_str(a)};
+                    util::ppaux::proto_ty_to_str(cx, e),
+                    util::ppaux::proto_ty_to_str(cx, a)};
       }
       terr_mutability => return ~"values differ in mutability",
       terr_box_mutability => return ~"boxed values differ in mutability",
@@ -3254,6 +3273,26 @@ fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr, span: span) -> uint {
     }
 }
 
+fn ast_proto_to_proto(ast_proto: ast::proto) -> ty::fn_proto {
+    match ast_proto {
+        ast::proto_bare => ty::proto_bare,
+        ast::proto_uniq => ty::proto_vstore(ty::vstore_uniq),
+        ast::proto_box => ty::proto_vstore(ty::vstore_box),
+        ast::proto_block => ty::proto_vstore(ty::vstore_slice(ty::re_static))
+    }
+}
+
+pure fn is_blockish(proto: fn_proto) -> bool {
+    match proto {
+        proto_vstore(vstore_slice(_)) =>
+            true,
+        proto_vstore(vstore_box) | proto_vstore(vstore_uniq) | proto_bare =>
+            false,
+        proto_vstore(vstore_fixed(_)) =>
+            fail ~"fixed vstore not allowed here"
+    }
+}
+
 // Local Variables:
 // mode: rust
 // fill-column: 78;
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 35ef1d5406e..88469c33516 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -251,7 +251,7 @@ fn check_main_fn_ty(ccx: @crate_ctxt,
     let tcx = ccx.tcx;
     let main_t = ty::node_id_to_type(tcx, main_id);
     match ty::get(main_t).struct {
-      ty::ty_fn({purity: ast::impure_fn, proto: ast::proto_bare, bounds,
+      ty::ty_fn({purity: ast::impure_fn, proto: ty::proto_bare, bounds,
                  inputs, output, ret_style: ast::return_val}) => {
         match tcx.items.find(main_id) {
          some(ast_map::node_item(it,_)) => {
diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs
index 124c5154a46..c6ede5bf817 100644
--- a/src/rustc/middle/typeck/astconv.rs
+++ b/src/rustc/middle/typeck/astconv.rs
@@ -423,7 +423,7 @@ type expected_tys = option<{inputs: ~[ty::arg],
 
 fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy owned>(
     self: AC, rscope: RS,
-    proto: ast::proto,
+    ast_proto: ast::proto,
     bounds: @~[ty::param_bound],
     decl: ast::fn_decl,
     expected_tys: expected_tys) -> ty::fn_ty {
@@ -450,6 +450,8 @@ fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy owned>(
           _ => ast_ty_to_ty(self, rb, decl.output)
         };
 
+        let proto = ty::ast_proto_to_proto(ast_proto);
+
         {purity: decl.purity, proto: proto, bounds: bounds, inputs: input_tys,
          output: output_ty, ret_style: decl.cf}
     }
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index 8dea6d6cfba..3bb2d0974ec 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -1116,9 +1116,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         }
     }
 
+    enum fn_or_ast_proto {
+        foap_fn_proto(ty::fn_proto),
+        foap_ast_proto(ast::proto)
+    }
+
     fn check_expr_fn(fcx: @fn_ctxt,
                      expr: @ast::expr,
-                     proto: ast::proto,
+                     fn_or_ast_proto: fn_or_ast_proto,
                      decl: ast::fn_decl,
                      body: ast::blk,
                      is_loop_body: bool,
@@ -1143,9 +1148,29 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
             }
         };
 
+        let ast_proto;
+        match fn_or_ast_proto {
+            foap_fn_proto(fn_proto) => {
+                // Generate a fake AST prototype. We'll fill in the type with
+                // the real one later.
+                // XXX: This is a hack.
+                ast_proto = ast::proto_box;
+            }
+            foap_ast_proto(existing_ast_proto) => {
+                ast_proto = existing_ast_proto;
+            }
+        }
+
         // construct the function type
-        let fn_ty = astconv::ty_of_fn_decl(fcx, fcx, proto, @~[],
-                                           decl, expected_tys);
+        let mut fn_ty = astconv::ty_of_fn_decl(fcx, fcx, ast_proto, @~[],
+                                               decl, expected_tys);
+
+        // Patch up the function declaration, if necessary.
+        match fn_or_ast_proto {
+            foap_fn_proto(fn_proto) => fn_ty.proto = fn_proto,
+            foap_ast_proto(_) => {}
+        }
+
         let fty = ty::mk_fn(tcx, fn_ty);
 
         debug!{"check_expr_fn_with_unifier %s fty=%s",
@@ -1485,15 +1510,17 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         bot = alt::check_alt(fcx, expr, discrim, arms);
       }
       ast::expr_fn(proto, decl, body, cap_clause) => {
-        check_expr_fn(fcx, expr, proto, decl, body, false, expected);
+        check_expr_fn(fcx, expr, foap_ast_proto(proto), decl, body, false,
+                      expected);
         capture::check_capture_clause(tcx, expr.id, cap_clause);
       }
       ast::expr_fn_block(decl, body, cap_clause) => {
          // Take the prototype from the expected type, but default to block:
           let proto = unpack_expected(fcx, expected, |sty|
               match sty { ty::ty_fn({proto, _}) => some(proto), _ => none }
-          ).get_default(ast::proto_box);
-        check_expr_fn(fcx, expr, proto, decl, body, false, expected);
+          ).get_default(ty::proto_vstore(ty::vstore_box));
+        check_expr_fn(fcx, expr, foap_fn_proto(proto), decl, body, false,
+                      expected);
         capture::check_capture_clause(tcx, expr.id, cap_clause);
       }
       ast::expr_loop_body(b) => {
@@ -1525,7 +1552,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         };
         match check b.node {
           ast::expr_fn_block(decl, body, cap_clause) => {
-            check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
+            check_expr_fn(fcx, b, foap_fn_proto(proto), decl, body, true,
+                          some(inner_ty));
             demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
             capture::check_capture_clause(tcx, b.id, cap_clause);
           }
@@ -1553,7 +1581,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         };
         match check b.node {
           ast::expr_fn_block(decl, body, cap_clause) => {
-            check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
+            check_expr_fn(fcx, b, foap_fn_proto(proto), decl, body, true,
+                          some(inner_ty));
             demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
             capture::check_capture_clause(tcx, b.id, cap_clause);
           }
@@ -2438,7 +2467,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
       ~"frame_address" => {
         let fty = ty::mk_fn(ccx.tcx, {
             purity: ast::impure_fn,
-            proto: ast::proto_block,
+            proto: ty::proto_vstore(ty::vstore_slice(ty::re_static)),
             bounds: @~[],
             inputs: ~[{
                 mode: ast::expl(ast::by_val),
@@ -2458,7 +2487,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
       }
     };
     let fty = ty::mk_fn(tcx, {purity: ast::impure_fn,
-                              proto: ast::proto_bare,
+                              proto: ty::proto_bare,
                               bounds: @~[],
                               inputs: inputs, output: output,
                               ret_style: ast::return_val});
diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs
index 3091e28d556..274eab9242e 100644
--- a/src/rustc/middle/typeck/check/method.rs
+++ b/src/rustc/middle/typeck/check/method.rs
@@ -334,7 +334,8 @@ class lookup {
     fn ty_from_did(did: ast::def_id) -> ty::t {
         match check ty::get(ty::lookup_item_type(self.tcx(), did).ty).struct {
           ty::ty_fn(fty) => {
-            ty::mk_fn(self.tcx(), {proto: ast::proto_box with fty})
+            ty::mk_fn(self.tcx(),
+                      {proto: ty::proto_vstore(ty::vstore_box) with fty})
           }
         }
         /*
@@ -416,7 +417,8 @@ class lookup {
 
         // a bit hokey, but the method unbound has a bare protocol, whereas
         // a.b has a protocol like fn@() (perhaps eventually fn&()):
-        let fty = ty::mk_fn(tcx, {proto: ast::proto_box with m.fty});
+        let fty = ty::mk_fn(tcx, {proto: ty::proto_vstore(ty::vstore_box)
+                                  with m.fty});
 
         self.candidates.push(
             {self_ty: self.self_ty,
diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs
index 477ea6d0e34..0eaa435e32d 100644
--- a/src/rustc/middle/typeck/collect.rs
+++ b/src/rustc/middle/typeck/collect.rs
@@ -126,7 +126,8 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
                 });
                 result_ty = some(ty::mk_fn(tcx,
                                            {purity: ast::pure_fn,
-                                            proto: ast::proto_box,
+                                            proto: ty::proto_vstore
+                                                (ty::vstore_box),
                                             bounds: @~[],
                                             inputs: args,
                                             output: enum_ty,
@@ -474,7 +475,7 @@ fn convert_struct(ccx: @crate_ctxt, rp: bool, struct_def: @ast::struct_def,
              tps: ty::ty_params_to_tys(tcx, tps)});
         let t_ctor = ty::mk_fn(
             tcx, {purity: ast::impure_fn,
-                  proto: ast::proto_block,
+                  proto: ty::proto_vstore(ty::vstore_slice(ty::re_static)),
                   bounds: @~[],
                   inputs: t_args,
                   output: t_res,
@@ -726,7 +727,7 @@ fn ty_of_foreign_fn_decl(ccx: @crate_ctxt,
     let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
 
     let t_fn = ty::mk_fn(ccx.tcx, {purity: decl.purity,
-                                   proto: ast::proto_bare,
+                                   proto: ty::proto_bare,
                                    bounds: @~[],
                                    inputs: input_tys,
                                    output: output_ty,
diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs
index 38913a5b605..13735e2f6d0 100644
--- a/src/rustc/middle/typeck/infer.rs
+++ b/src/rustc/middle/typeck/infer.rs
@@ -172,7 +172,7 @@ import std::smallintmap::smallintmap;
 import std::map::hashmap;
 import middle::ty;
 import middle::ty::{tv_vid, tvi_vid, region_vid, vid,
-                    ty_int, ty_uint, get};
+                    ty_int, ty_uint, get, terr_fn};
 import syntax::{ast, ast_util};
 import syntax::ast::{ret_style, purity};
 import util::ppaux::{ty_to_str, mt_to_str};
@@ -1552,7 +1552,7 @@ trait combine {
     fn flds(a: ty::field, b: ty::field) -> cres<ty::field>;
     fn modes(a: ast::mode, b: ast::mode) -> cres<ast::mode>;
     fn args(a: ty::arg, b: ty::arg) -> cres<ty::arg>;
-    fn protos(p1: ast::proto, p2: ast::proto) -> cres<ast::proto>;
+    fn protos(p1: ty::fn_proto, p2: ty::fn_proto) -> cres<ty::fn_proto>;
     fn ret_styles(r1: ret_style, r2: ret_style) -> cres<ret_style>;
     fn purities(f1: purity, f2: purity) -> cres<purity>;
     fn contraregions(a: ty::region, b: ty::region) -> cres<ty::region>;
@@ -1945,7 +1945,7 @@ impl sub: combine {
         }
     }
 
-    fn protos(a: ast::proto, b: ast::proto) -> cres<ast::proto> {
+    fn protos(a: ty::fn_proto, b: ty::fn_proto) -> cres<ty::fn_proto> {
         (&self.lub()).protos(a, b).compare(b, || {
             ty::terr_proto_mismatch(b, a)
         })
@@ -2103,15 +2103,20 @@ impl lub: combine {
         glb(self.infcx()).tys(a, b)
     }
 
-    fn protos(p1: ast::proto, p2: ast::proto) -> cres<ast::proto> {
-        if p1 == ast::proto_bare {
-            ok(p2)
-        } else if p2 == ast::proto_bare {
-            ok(p1)
-        } else if p1 == p2 {
-            ok(p1)
-        } else {
-            ok(ast::proto_block)
+    fn protos(p1: ty::fn_proto, p2: ty::fn_proto) -> cres<ty::fn_proto> {
+        match (p1, p2) {
+            (ty::proto_bare, _) => ok(p2),
+            (_, ty::proto_bare) => ok(p1),
+            (ty::proto_vstore(v1), ty::proto_vstore(v2)) => {
+                self.infcx().try(|| {
+                    do self.vstores(terr_fn, v1, v2).chain |vs| {
+                        ok(ty::proto_vstore(vs))
+                    }
+                }).chain_err(|_err| {
+                    // XXX: Totally unsound, but fixed up later.
+                    ok(ty::proto_vstore(ty::vstore_slice(ty::re_static)))
+                })
+            }
         }
     }
 
@@ -2300,15 +2305,21 @@ impl glb: combine {
         lub(self.infcx()).tys(a, b)
     }
 
-    fn protos(p1: ast::proto, p2: ast::proto) -> cres<ast::proto> {
-        if p1 == ast::proto_block {
-            ok(p2)
-        } else if p2 == ast::proto_block {
-            ok(p1)
-        } else if p1 == p2 {
-            ok(p1)
-        } else {
-            ok(ast::proto_bare)
+    fn protos(p1: ty::fn_proto, p2: ty::fn_proto) -> cres<ty::fn_proto> {
+        match (p1, p2) {
+            (ty::proto_vstore(ty::vstore_slice(_)), _) => ok(p2),
+            (_, ty::proto_vstore(ty::vstore_slice(_))) => ok(p1),
+            (ty::proto_vstore(v1), ty::proto_vstore(v2)) => {
+                self.infcx().try(|| {
+                    do self.vstores(terr_fn, v1, v2).chain |vs| {
+                        ok(ty::proto_vstore(vs))
+                    }
+                }).chain_err(|_err| {
+                    // XXX: Totally unsound, but fixed up later.
+                    ok(ty::proto_bare)
+                })
+            }
+            _ => ok(ty::proto_bare)
         }
     }
 
diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs
index b64c7232137..c43a76d6a42 100644
--- a/src/rustc/util/ppaux.rs
+++ b/src/rustc/util/ppaux.rs
@@ -188,6 +188,13 @@ fn vstore_ty_to_str(cx: ctxt, ty: ~str, vs: ty::vstore) -> ~str {
     }
 }
 
+fn proto_ty_to_str(cx: ctxt, proto: ty::fn_proto) -> ~str {
+    match proto {
+      ty::proto_bare => ~"",
+      ty::proto_vstore(vstore) => vstore_to_str(cx, vstore)
+    }
+}
+
 fn tys_to_str(cx: ctxt, ts: ~[t]) -> ~str {
     let mut rs = ~"";
     for ts.each |t| { rs += ty_to_str(cx, t); }
@@ -211,7 +218,7 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
         };
         modestr + ty_to_str(cx, ty)
     }
-    fn fn_to_str(cx: ctxt, purity: ast::purity, proto: ast::proto,
+    fn fn_to_str(cx: ctxt, purity: ast::purity, proto: ty::fn_proto,
                  ident: option<ast::ident>,
                  inputs: ~[arg], output: t, cf: ast::ret_style) -> ~str {
         let mut s;
@@ -220,7 +227,8 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
           ast::impure_fn => ~"",
           _ => purity_to_str(purity) + ~" "
         };
-        s += proto_to_str(proto);
+
+        s += proto_ty_to_str(cx, proto);
         match ident {
           some(i) => { s += ~" "; s += *i; }
           _ => { }