about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-11-04 20:41:00 -0800
committerNiko Matsakis <niko@alum.mit.edu>2012-11-06 08:56:29 -0800
commitb0ed151539cddb1c191f67f9f9597942919d44eb (patch)
tree976ed7cab726c0cdae81e0a18e28a27cbd5e4664
parent53ec6c3f9b495dd930cd061784251534bef58d74 (diff)
downloadrust-b0ed151539cddb1c191f67f9f9597942919d44eb.tar.gz
rust-b0ed151539cddb1c191f67f9f9597942919d44eb.zip
Cleanup how we handle proto in types, remove unsound subtyping
Fixes #1896 which was never truly fixed, just masked.
The given tests would have failed had they used `~fn()` and
not `@fn()`.  They now result in compilation errors.

Fixes #2978.

Necessary first step for #2202, #2263.
-rw-r--r--src/libsyntax/ast.rs45
-rw-r--r--src/libsyntax/fold.rs18
-rw-r--r--src/libsyntax/parse/obsolete.rs66
-rw-r--r--src/libsyntax/parse/parser.rs275
-rw-r--r--src/libsyntax/print/pprust.rs150
-rw-r--r--src/libsyntax/visit.rs12
-rw-r--r--src/rustc/front/test.rs2
-rw-r--r--src/rustc/metadata/tydecode.rs21
-rw-r--r--src/rustc/metadata/tyencode.rs21
-rw-r--r--src/rustc/middle/borrowck/check_loans.rs2
-rw-r--r--src/rustc/middle/borrowck/gather_loans.rs8
-rw-r--r--src/rustc/middle/capture.rs4
-rw-r--r--src/rustc/middle/check_loop.rs4
-rw-r--r--src/rustc/middle/freevars.rs2
-rw-r--r--src/rustc/middle/kind.rs10
-rw-r--r--src/rustc/middle/lint.rs22
-rw-r--r--src/rustc/middle/mem_categorization.rs90
-rw-r--r--src/rustc/middle/region.rs65
-rw-r--r--src/rustc/middle/trans/closure.rs151
-rw-r--r--src/rustc/middle/trans/expr.rs25
-rw-r--r--src/rustc/middle/trans/foreign.rs5
-rw-r--r--src/rustc/middle/trans/monomorphize.rs5
-rw-r--r--src/rustc/middle/trans/reflect.rs24
-rw-r--r--src/rustc/middle/trans/type_use.rs7
-rw-r--r--src/rustc/middle/ty.rs224
-rw-r--r--src/rustc/middle/typeck/astconv.rs200
-rw-r--r--src/rustc/middle/typeck/check.rs86
-rw-r--r--src/rustc/middle/typeck/check/method.rs4
-rw-r--r--src/rustc/middle/typeck/check/regionck.rs23
-rw-r--r--src/rustc/middle/typeck/collect.rs56
-rw-r--r--src/rustc/middle/typeck/infer/assignment.rs23
-rw-r--r--src/rustc/middle/typeck/infer/combine.rs29
-rw-r--r--src/rustc/middle/typeck/infer/glb.rs18
-rw-r--r--src/rustc/middle/typeck/infer/lub.rs19
-rw-r--r--src/rustc/middle/typeck/infer/sub.rs26
-rw-r--r--src/rustc/util/ppaux.rs93
-rw-r--r--src/test/compile-fail/block-coerce-no.rs8
-rw-r--r--src/test/compile-fail/extern-wrong-value-type.rs3
-rw-r--r--src/test/compile-fail/issue-1896-1.rs (renamed from src/test/run-pass/issue-1896-1.rs)2
-rw-r--r--src/test/compile-fail/issue-1896-2.rs (renamed from src/test/run-pass/issue-1896-2.rs)4
-rw-r--r--src/test/compile-fail/issue-1896-3.rs (renamed from src/test/run-pass/issue-1896-3.rs)2
-rw-r--r--src/test/compile-fail/issue-1896.rs5
-rw-r--r--src/test/compile-fail/missing-do.rs2
-rw-r--r--src/test/compile-fail/obsolete-syntax.rs13
-rw-r--r--src/test/compile-fail/pure-subtyping.rs38
-rw-r--r--src/test/compile-fail/regions-fn-bound.rs21
-rw-r--r--src/test/compile-fail/regions-freevar.rs3
-rw-r--r--src/test/compile-fail/sendfn-is-not-a-lambda.rs2
-rw-r--r--src/test/pretty/disamb-stmt-expr.rs2
-rw-r--r--src/test/pretty/fn-types.rs6
-rw-r--r--src/test/run-pass/issue-2185.rs1
-rw-r--r--src/test/run-pass/task-killjoin-rsrc.rs2
52 files changed, 947 insertions, 1002 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 8667f36c749..8fcb9300b52 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -410,18 +410,24 @@ impl mutability : cmp::Eq {
 
 #[auto_serialize]
 #[auto_deserialize]
-enum proto {
-    proto_bare,    // foreign fn
-    proto_uniq,    // fn~
-    proto_box,     // fn@
-    proto_block,   // fn&
+pub enum Proto {
+    ProtoBare,     // bare functions (deprecated)
+    ProtoUniq,     // ~fn
+    ProtoBox,      // @fn
+    ProtoBorrowed, // &fn
 }
 
-impl proto : cmp::Eq {
-    pure fn eq(other: &proto) -> bool {
+impl Proto : cmp::Eq {
+    pure fn eq(other: &Proto) -> bool {
         (self as uint) == ((*other) as uint)
     }
-    pure fn ne(other: &proto) -> bool { !self.eq(other) }
+    pure fn ne(other: &Proto) -> bool { !self.eq(other) }
+}
+
+impl Proto : to_bytes::IterBytes {
+    pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
+        (self as uint).iter_bytes(lsb0, f);
+    }
 }
 
 #[auto_serialize]
@@ -444,10 +450,10 @@ enum expr_vstore {
     expr_vstore_slice                  // &[1,2,3,4]
 }
 
-pure fn is_blockish(p: ast::proto) -> bool {
+pure fn is_blockish(p: ast::Proto) -> bool {
     match p {
-      proto_block => true,
-      proto_bare | proto_uniq | proto_box => false
+        ProtoBorrowed => true,
+        ProtoBare | ProtoUniq | ProtoBox => false
     }
 }
 
@@ -678,7 +684,7 @@ enum expr_ {
        (implicit) condition is always true. */
     expr_loop(blk, Option<ident>),
     expr_match(@expr, ~[arm]),
-    expr_fn(proto, fn_decl, blk, capture_clause),
+    expr_fn(Proto, fn_decl, blk, capture_clause),
     expr_fn_block(fn_decl, blk, capture_clause),
     // Inner expr is always an expr_fn_block. We need the wrapping node to
     // easily type this (a function returning nil on the inside but bool on
@@ -1080,19 +1086,30 @@ impl Onceness : cmp::Eq {
 
 #[auto_serialize]
 #[auto_deserialize]
+struct TyFn {
+    proto: Proto,
+    region: Option<@region>,
+    purity: purity,
+    onceness: Onceness,
+    bounds: @~[ty_param_bound],
+    decl: fn_decl
+}
+
+#[auto_serialize]
+#[auto_deserialize]
 enum ty_ {
     ty_nil,
     ty_bot, /* bottom type */
     ty_box(mt),
     ty_uniq(mt),
     ty_vec(mt),
+    ty_fixed_length_vec(mt, uint),
     ty_ptr(mt),
     ty_rptr(@region, mt),
     ty_rec(~[ty_field]),
-    ty_fn(proto, purity, Onceness, @~[ty_param_bound], fn_decl),
+    ty_fn(@TyFn),
     ty_tup(~[@Ty]),
     ty_path(@path, node_id),
-    ty_fixed_length(@Ty, Option<uint>),
     ty_mac(mac),
     // ty_infer means the type should be inferred instead of it having been
     // specified. This should only appear at the "top level" of a type and not
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 7c8909668f5..3879e70cb28 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -524,15 +524,19 @@ fn noop_fold_ty(t: ty_, fld: ast_fold) -> ty_ {
       ty_ptr(mt) => ty_ptr(fold_mt(mt, fld)),
       ty_rptr(region, mt) => ty_rptr(region, fold_mt(mt, fld)),
       ty_rec(fields) => ty_rec(vec::map(fields, |f| fold_field(*f, fld))),
-      ty_fn(proto, purity, onceness, bounds, decl) =>
-        ty_fn(proto,
-              purity,
-              onceness,
-              @vec::map(*bounds, |x| fold_ty_param_bound(*x, fld)),
-              fold_fn_decl(decl, fld)),
+      ty_fn(f) =>
+        ty_fn(@TyFn {
+            proto: f.proto,
+            purity: f.purity,
+            region: f.region,
+            onceness: f.onceness,
+            bounds: @vec::map(*f.bounds, |x| fold_ty_param_bound(*x, fld)),
+            decl: fold_fn_decl(f.decl, fld)
+        }),
       ty_tup(tys) => ty_tup(vec::map(tys, |ty| fld.fold_ty(*ty))),
       ty_path(path, id) => ty_path(fld.fold_path(path), fld.new_id(id)),
-      ty_fixed_length(t, vs) => ty_fixed_length(fld.fold_ty(t), vs),
+      ty_fixed_length_vec(mt, vs) =>
+        ty_fixed_length_vec(fold_mt(mt, fld), vs),
       ty_mac(mac) => ty_mac(fold_mac(mac))
     }
 }
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index 1344c9b11ea..e5f6cf8ee25 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -24,7 +24,6 @@ pub enum ObsoleteSyntax {
     ObsoletePrivSection,
     ObsoleteModeInFnType,
     ObsoleteByMutRefMode,
-    ObsoleteFixedLengthVec,
     ObsoleteMoveInit,
     ObsoleteBinaryMove
 }
@@ -102,11 +101,6 @@ impl Parser : ObsoleteReporter {
                 "by-mutable-reference mode",
                 "Declare an argument of type &mut T instead"
             ),
-            ObsoleteFixedLengthVec => (
-                "fixed-length vector",
-                "Fixed-length types are now written `[T * N]`, and instances \
-                 are type-inferred"
-            ),
             ObsoleteMoveInit => (
                 "initializer-by-move",
                 "Write `let foo = move bar` instead"
@@ -200,65 +194,5 @@ impl Parser : ObsoleteReporter {
         }
     }
 
-    fn try_parse_obsolete_fixed_vstore() -> Option<Option<uint>> {
-        if self.token == token::BINOP(token::SLASH) {
-            self.bump();
-            match copy self.token {
-                token::UNDERSCORE => {
-                    self.obsolete(copy self.last_span,
-                                  ObsoleteFixedLengthVec);
-                    self.bump(); Some(None)
-                }
-                token::LIT_INT_UNSUFFIXED(i) if i >= 0i64 => {
-                    self.obsolete(copy self.last_span,
-                                  ObsoleteFixedLengthVec);
-                    self.bump(); Some(Some(i as uint))
-                }
-                _ => None
-            }
-        } else {
-            None
-        }
-    }
-
-    fn try_convert_ty_to_obsolete_fixed_length_vstore(sp: span, t: ast::ty_)
-        -> ast::ty_ {
-        match self.try_parse_obsolete_fixed_vstore() {
-            // Consider a fixed length vstore suffix (/N or /_)
-            None => t,
-            Some(v) => {
-                ast::ty_fixed_length(
-                    @{id: self.get_id(), node: t, span: sp}, v)
-            }
-        }
-    }
-
-    fn try_convert_expr_to_obsolete_fixed_length_vstore(
-        lo: uint, hi: uint, ex: ast::expr_
-    ) -> (uint, ast::expr_) {
-
-        let mut hi = hi;
-        let mut ex = ex;
-
-        // Vstore is legal following expr_lit(lit_str(...)) and expr_vec(...)
-        // only.
-        match ex {
-            ast::expr_lit(@{node: ast::lit_str(_), span: _}) |
-            ast::expr_vec(_, _)  => {
-                match self.try_parse_obsolete_fixed_vstore() {
-                    None => (),
-                    Some(v) => {
-                        hi = self.span.hi;
-                        ex = ast::expr_vstore(self.mk_expr(lo, hi, ex),
-                                              ast::expr_vstore_fixed(v));
-                    }
-                }
-            }
-            _ => ()
-        }
-
-        return (hi, ex);
-    }
-
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 63545a69608..db3f6abbf7b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -50,8 +50,8 @@ use ast::{_mod, add, arg, arm, attribute,
              match_tok, method, mode, module_ns, mt, mul, mutability,
              named_field, neg, noreturn, not, pat, pat_box, pat_enum,
              pat_ident, pat_lit, pat_range, pat_rec, pat_region, pat_struct,
-             pat_tup, pat_uniq, pat_wild, path, private, proto, proto_bare,
-             proto_block, proto_box, proto_uniq, provided, public, pure_fn,
+             pat_tup, pat_uniq, pat_wild, path, private, Proto, ProtoBare,
+             ProtoBorrowed, ProtoBox, ProtoUniq, provided, public, pure_fn,
              purity, re_static, re_self, re_anon, re_named, region,
              rem, required, ret_style,
              return_val, self_ty, shl, shr, stmt, stmt_decl, stmt_expr,
@@ -61,14 +61,14 @@ use ast::{_mod, add, arg, arm, attribute,
              tt_tok, tt_nonterminal, tuple_variant_kind, Ty, ty_, ty_bot,
              ty_box, ty_field, ty_fn, ty_infer, ty_mac, ty_method, ty_nil,
              ty_param, ty_param_bound, ty_path, ty_ptr, ty_rec, ty_rptr,
-             ty_tup, ty_u32, ty_uniq, ty_vec, ty_fixed_length, type_value_ns,
-             uniq, unnamed_field, unsafe_blk, unsafe_fn,
+             ty_tup, ty_u32, ty_uniq, ty_vec, ty_fixed_length_vec,
+             type_value_ns, uniq, unnamed_field, unsafe_blk, unsafe_fn,
              variant, view_item, view_item_, view_item_export,
              view_item_import, view_item_use, view_path, view_path_glob,
              view_path_list, view_path_simple, visibility, vstore, vstore_box,
              vstore_fixed, vstore_slice, vstore_uniq,
              expr_vstore_fixed, expr_vstore_slice, expr_vstore_box,
-             expr_vstore_uniq};
+             expr_vstore_uniq, TyFn, Onceness, Once, Many};
 
 export file_type;
 export Parser;
@@ -287,30 +287,90 @@ impl Parser {
 
     pure fn id_to_str(id: ident) -> @~str { self.sess.interner.get(id) }
 
-    fn parse_ty_fn(purity: ast::purity, onceness: ast::Onceness) -> ty_ {
-        let proto, bounds;
+    fn token_is_fn_keyword(+tok: token::Token) -> bool {
+        self.token_is_keyword(~"pure", tok) ||
+            self.token_is_keyword(~"unsafe", tok) ||
+            self.token_is_keyword(~"once", tok) ||
+            self.token_is_keyword(~"fn", tok) ||
+            self.token_is_keyword(~"extern", tok)
+    }
+
+    fn parse_ty_fn(pre_proto: Option<ast::Proto>,
+                       pre_region_name: Option<ident>) -> ty_
+    {
+        /*
+
+        (&|~|@) [r/] [pure|unsafe] [once] fn [:K] (S) -> T
+        ^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^    ^~~^ ^~^    ^
+           |     |     |             |        |    |     |
+           |     |     |             |        |    |   Return type
+           |     |     |             |        |  Argument types
+           |     |     |             |    Environment bounds
+           |     |     |          Once-ness (a.k.a., affine)
+           |     |   Purity
+           | Lifetime bound
+        Allocation type
+
+        */
+
+        // At this point, the allocation type and lifetime bound have been
+        // parsed.
+
+        let purity = parse_purity(&self);
+        let onceness = parse_onceness(&self);
+
+        let bounds, post_proto;
         if self.eat_keyword(~"extern") {
             self.expect_keyword(~"fn");
-            proto = ast::proto_bare;
+            post_proto = Some(ast::ProtoBare);
             bounds = @~[];
         } else {
             self.expect_keyword(~"fn");
-            proto = self.parse_fn_ty_proto();
+            post_proto = self.parse_fn_ty_proto();
             bounds = self.parse_optional_ty_param_bounds();
         };
-        ty_fn(proto, purity, onceness, bounds, self.parse_ty_fn_decl())
-    }
 
-    fn parse_ty_fn_with_onceness(purity: ast::purity) -> ty_ {
-        let onceness = self.parse_optional_onceness();
-        self.parse_ty_fn(purity, onceness)
-    }
+        let proto = match (pre_proto, post_proto) {
+            (None, None) => ast::ProtoBorrowed,
+            (Some(p), None) | (None, Some(p)) => p,
+            (Some(_), Some(_)) => {
+                self.fatal(~"cannot combine prefix and postfix \
+                             syntax for closure kind; note that \
+                             postfix syntax is obsolete");
+            }
+        };
+
+        let region = if pre_region_name.is_some() {
+            Some(self.region_from_name(pre_region_name))
+        } else {
+            None
+        };
+
+        return ty_fn(@TyFn {
+            proto: proto,
+            region: region,
+            purity: purity,
+            onceness: onceness,
+            bounds: bounds,
+            decl: self.parse_ty_fn_decl()
+        });
+
+        fn parse_purity(self: &Parser) -> purity {
+            if self.eat_keyword(~"pure") {
+                return pure_fn;
+            } else if self.eat_keyword(~"unsafe") {
+                return unsafe_fn;
+            } else {
+                return impure_fn;
+            }
+        }
 
-    fn parse_ty_fn_with_purity_and_onceness() -> ty_ {
-        let purity = self.parse_optional_purity();
-        self.parse_ty_fn_with_onceness(purity)
+        fn parse_onceness(self: &Parser) -> Onceness {
+            if self.eat_keyword(~"once") {Once} else {Many}
+        }
     }
 
+
     fn parse_ty_fn_decl() -> fn_decl {
         let inputs = do self.parse_unspanned_seq(
             token::LPAREN, token::RPAREN,
@@ -449,23 +509,6 @@ impl Parser {
         }
     }
 
-    // Parses something like "&x/" (note the trailing slash)
-    fn parse_region_with_sep() -> @region {
-        let name =
-            match copy self.token {
-              token::IDENT(sid, _) => {
-                if self.look_ahead(1u) == token::BINOP(token::SLASH) {
-                    self.bump(); self.bump();
-                    Some(sid)
-                } else {
-                    None
-                }
-              }
-              _ => { None }
-            };
-        self.region_from_name(name)
-    }
-
     fn parse_ty(colons_before_params: bool) -> @Ty {
         maybe_whole!(self, nt_ty);
 
@@ -498,10 +541,10 @@ impl Parser {
             }
         } else if self.token == token::AT {
             self.bump();
-            ty_box(self.parse_mt())
+            self.parse_box_or_uniq_pointee(ast::ProtoBox, ty_box)
         } else if self.token == token::TILDE {
             self.bump();
-            ty_uniq(self.parse_mt())
+            self.parse_box_or_uniq_pointee(ast::ProtoUniq, ty_uniq)
         } else if self.token == token::BINOP(token::STAR) {
             self.bump();
             ty_ptr(self.parse_mt())
@@ -516,51 +559,77 @@ impl Parser {
             ty_rec(elems)
         } else if self.token == token::LBRACKET {
             self.expect(token::LBRACKET);
-            let mut t = ty_vec(self.parse_mt());
+            let mt = self.parse_mt();
 
             // Parse the `* 3` in `[ int * 3 ]`
-            match self.maybe_parse_fixed_vstore_with_star() {
-                None => {}
-                Some(suffix) => {
-                    t = ty_fixed_length(@{
-                        id: self.get_id(),
-                        node: t,
-                        span: mk_sp(lo, self.last_span.hi)
-                    }, suffix)
-                }
-            }
+            let t = match self.maybe_parse_fixed_vstore_with_star() {
+                None => ty_vec(mt),
+                Some(suffix) => ty_fixed_length_vec(mt, suffix)
+            };
             self.expect(token::RBRACKET);
             t
         } else if self.token == token::BINOP(token::AND) {
             self.bump();
-            let region = self.parse_region_with_sep();
-            let mt = self.parse_mt();
-            ty_rptr(region, mt)
-        } else if self.eat_keyword(~"once") {
-            self.parse_ty_fn(ast::impure_fn, ast::Once)
-        } else if self.eat_keyword(~"pure") {
-            self.parse_ty_fn_with_onceness(ast::pure_fn)
-        } else if self.eat_keyword(~"unsafe") {
-            self.parse_ty_fn_with_onceness(ast::unsafe_fn)
-        } else if self.is_keyword(~"fn") {
-            self.parse_ty_fn_with_onceness(ast::impure_fn)
-        } else if self.eat_keyword(~"extern") {
-            self.expect_keyword(~"fn");
-            ty_fn(proto_bare, ast::impure_fn, ast::Many, @~[],
-                  self.parse_ty_fn_decl())
+            self.parse_borrowed_pointee()
+        } else if self.token_is_fn_keyword(self.token) {
+            self.parse_ty_fn(None, None)
         } else if self.token == token::MOD_SEP || is_ident(self.token) {
             let path = self.parse_path_with_tps(colons_before_params);
             ty_path(path, self.get_id())
         } else { self.fatal(~"expected type"); };
 
         let sp = mk_sp(lo, self.last_span.hi);
-        return {
-            let node =
-                self.try_convert_ty_to_obsolete_fixed_length_vstore(sp, t);
-            @{id: self.get_id(),
-              node: node,
-              span: sp}
+        return @{id: self.get_id(), node: t, span: sp};
+    }
+
+    fn parse_box_or_uniq_pointee(
+        proto: ast::Proto,
+        ctor: &fn(+v: mt) -> ty_) -> ty_
+    {
+        // @foo/fn() or @fn() are parsed directly as fn types:
+        match copy self.token {
+            token::IDENT(rname, _) => {
+                if self.look_ahead(1u) == token::BINOP(token::SLASH) &&
+                    self.token_is_fn_keyword(self.look_ahead(2u))
+                {
+                    self.bump(); self.bump();
+                    return self.parse_ty_fn(Some(proto), Some(rname));
+                } else if self.token_is_fn_keyword(self.token) {
+                    return self.parse_ty_fn(Some(proto), None);
+                }
+            }
+            _ => {}
+        }
+
+        // other things are parsed as @ + a type.  Note that constructs like
+        // @[] and @str will be resolved during typeck to slices and so forth,
+        // rather than boxed ptrs.  But the special casing of str/vec is not
+        // reflected in the AST type.
+        let mt = self.parse_mt();
+        ctor(mt)
+    }
+
+    fn parse_borrowed_pointee() -> ty_ {
+        // look for `&foo/` and interpret `foo` as the region name:
+        let rname = match copy self.token {
+            token::IDENT(sid, _) => {
+                if self.look_ahead(1u) == token::BINOP(token::SLASH) {
+                    self.bump(); self.bump();
+                    Some(sid)
+                } else {
+                    None
+                }
+            }
+            _ => { None }
         };
+
+        if self.token_is_fn_keyword(self.token) {
+            return self.parse_ty_fn(Some(ProtoBorrowed), rname);
+        }
+
+        let r = self.region_from_name(rname);
+        let mt = self.parse_mt();
+        return ty_rptr(r, mt);
     }
 
     fn parse_arg_mode() -> mode {
@@ -691,16 +760,19 @@ impl Parser {
         }
     }
 
-    fn maybe_parse_fixed_vstore_with_star() -> Option<Option<uint>> {
+    fn maybe_parse_fixed_vstore_with_star() -> Option<uint> {
         if self.eat(token::BINOP(token::STAR)) {
             match copy self.token {
-              token::UNDERSCORE => {
-                self.bump(); Some(None)
-              }
-              token::LIT_INT_UNSUFFIXED(i) if i >= 0i64 => {
-                self.bump(); Some(Some(i as uint))
-              }
-              _ => None
+                token::LIT_INT_UNSUFFIXED(i) if i >= 0i64 => {
+                    self.bump();
+                    Some(i as uint)
+                }
+                _ => {
+                    self.fatal(
+                        fmt!("expected integral vector length \
+                              but found `%s`",
+                             token_to_str(self.reader, self.token)));
+                }
             }
         } else {
             None
@@ -909,11 +981,13 @@ impl Parser {
         } else if self.eat_keyword(~"match") {
             return self.parse_alt_expr();
         } else if self.eat_keyword(~"fn") {
-            let proto = self.parse_fn_ty_proto();
-            match proto {
-              proto_bare => self.fatal(~"fn expr are deprecated, use fn@"),
-              _ => { /* fallthrough */ }
-            }
+            let opt_proto = self.parse_fn_ty_proto();
+            let proto = match opt_proto {
+                None | Some(ast::ProtoBare) => {
+                    self.fatal(~"fn expr are deprecated, use fn@")
+                }
+                Some(p) => { p }
+            };
             return self.parse_fn_expr(proto);
         } else if self.eat_keyword(~"unsafe") {
             return self.parse_block_expr(lo, unsafe_blk);
@@ -1055,9 +1129,6 @@ impl Parser {
             ex = expr_lit(@lit);
         }
 
-        let (hi, ex) =
-            self.try_convert_expr_to_obsolete_fixed_length_vstore(lo, hi, ex);
-
         return self.mk_expr(lo, hi, ex);
     }
 
@@ -1495,7 +1566,7 @@ impl Parser {
         return self.mk_expr(q.lo, q.hi, expr_if(q.cond, q.then, q.els));
     }
 
-    fn parse_fn_expr(proto: proto) -> @expr {
+    fn parse_fn_expr(proto: Proto) -> @expr {
         let lo = self.last_span.lo;
 
         // if we want to allow fn expression argument types to be inferred in
@@ -3188,23 +3259,23 @@ impl Parser {
         (id, item_enum(enum_definition, ty_params), None)
     }
 
-    fn parse_fn_ty_proto() -> proto {
+    fn parse_fn_ty_proto() -> Option<Proto> {
         match self.token {
-          token::AT => {
-            self.bump();
-            proto_box
-          }
-          token::TILDE => {
-            self.bump();
-            proto_uniq
-          }
-          token::BINOP(token::AND) => {
-            self.bump();
-            proto_block
-          }
-          _ => {
-            proto_block
-          }
+            token::AT => {
+                self.bump();
+                Some(ProtoBox)
+            }
+            token::TILDE => {
+                self.bump();
+                Some(ProtoUniq)
+            }
+            token::BINOP(token::AND) => {
+                self.bump();
+                Some(ProtoBorrowed)
+            }
+            _ => {
+                None
+            }
         }
     }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index e0b9958bcb7..ed64d02cea3 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -7,6 +7,7 @@ use ast_util::{operator_prec};
 use dvec::DVec;
 use parse::classify::*;
 use parse::token::ident_interner;
+use str::{push_str, push_char};
 
 // The ps is stored here to prevent recursive type.
 enum ann_node {
@@ -211,7 +212,9 @@ fn head(s: ps, w: ~str) {
     // head-box is inconsistent
     ibox(s, str::len(w) + 1);
     // keyword that starts the head
-    word_nbsp(s, w);
+    if !w.is_empty() {
+        word_nbsp(s, w);
+    }
 }
 
 fn bopen(s: ps) {
@@ -328,20 +331,19 @@ fn print_foreign_mod(s: ps, nmod: ast::foreign_mod,
     for nmod.items.each |item| { print_foreign_item(s, *item); }
 }
 
-fn print_region(s: ps, region: @ast::region, sep: ~str) {
+fn print_region(s: ps, prefix: ~str, region: @ast::region, sep: ~str) {
+    word(s.s, prefix);
     match region.node {
         ast::re_anon => {
-            word_space(s, ~"&");
             return;
         }
         ast::re_static => {
-            word_space(s, ~"&static")
+            word_space(s, ~"static")
         }
         ast::re_self => {
-            word_space(s, ~"&self")
+            word_space(s, ~"self")
         }
         ast::re_named(name) => {
-            word(s.s, ~"&");
             print_ident(s, name);
         }
     }
@@ -372,7 +374,7 @@ fn print_type_ex(s: ps, &&ty: @ast::Ty, print_colons: bool) {
       }
       ast::ty_ptr(mt) => { word(s.s, ~"*"); print_mt(s, mt); }
       ast::ty_rptr(region, mt) => {
-          print_region(s, region, ~"/");
+          print_region(s, ~"&", region, ~"/");
           print_mt(s, mt);
       }
       ast::ty_rec(fields) => {
@@ -394,26 +396,21 @@ fn print_type_ex(s: ps, &&ty: @ast::Ty, print_colons: bool) {
         commasep(s, inconsistent, elts, print_type);
         pclose(s);
       }
-      ast::ty_fn(proto, purity, onceness, bounds, d) => {
-        print_ty_fn(s, Some(proto), purity, onceness, bounds, d, None, None,
-                    None);
+      ast::ty_fn(f) => {
+        print_ty_fn(s, Some(f.proto), f.region, f.purity,
+                    f.onceness, f.bounds, f.decl, None, None, None);
       }
       ast::ty_path(path, _) => print_path(s, path, print_colons),
-      ast::ty_fixed_length(t, v) => {
+      ast::ty_fixed_length_vec(mt, v) => {
         word(s.s, ~"[");
-        match t.node {
-          ast::ty_vec(mt) => {
-            match mt.mutbl {
-              ast::m_mutbl => word_space(s, ~"mut"),
-              ast::m_const => word_space(s, ~"const"),
-              ast::m_imm => ()
-            }
-            print_type(s, mt.ty);
-          }
-          _ => fail ~"ty_fixed_length can only contain ty_vec as type"
+        match mt.mutbl {
+            ast::m_mutbl => word_space(s, ~"mut"),
+            ast::m_const => word_space(s, ~"const"),
+            ast::m_imm => ()
         }
+        print_type(s, mt.ty);
         word(s.s, ~" * ");
-        print_vstore(s, ast::vstore_fixed(v));
+        word(s.s, fmt!("%u", v));
         word(s.s, ~"]");
       }
       ast::ty_mac(_) => {
@@ -805,7 +802,7 @@ fn print_ty_method(s: ps, m: ast::ty_method) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, m.span.lo);
     print_outer_attributes(s, m.attrs);
-    print_ty_fn(s, None, m.purity, ast::Many,
+    print_ty_fn(s, None, None, m.purity, ast::Many,
                 @~[], m.decl, Some(m.ident), Some(m.tps),
                 Some(m.self_ty.node));
     word(s.s, ~";");
@@ -1023,7 +1020,7 @@ fn print_vstore(s: ps, t: ast::vstore) {
         ast::vstore_fixed(None) => word(s.s, ~"_"),
         ast::vstore_uniq => word(s.s, ~"~"),
         ast::vstore_box => word(s.s, ~"@"),
-        ast::vstore_slice(r) => print_region(s, r, ~"/")
+        ast::vstore_slice(r) => print_region(s, ~"&", r, ~"/")
     }
 }
 
@@ -1274,8 +1271,8 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
         cbox(s, indent_unit);
         // head-box, will be closed by print-block at start
         ibox(s, 0u);
-        word(s.s, fn_header_info_to_str(None, None, Some(proto), ast::Many,
-                                        ast::inherited));
+        print_fn_header_info(s, None, None, ast::Many,
+                             Some(proto), ast::inherited);
         print_fn_args_and_ret(s, decl, *cap_clause, None);
         space(s.s);
         print_block(s, body);
@@ -1481,7 +1478,7 @@ fn print_path(s: ps, &&path: @ast::path, colons_before_params: bool) {
           None => { /* ok */ }
           Some(r) => {
             word(s.s, ~"/");
-            print_region(s, r, ~"");
+            print_region(s, ~"&", r, ~"");
           }
         }
 
@@ -1614,8 +1611,9 @@ fn print_fn(s: ps,
             typarams: ~[ast::ty_param],
             opt_self_ty: Option<ast::self_ty_>,
             vis: ast::visibility) {
-    head(s, fn_header_info_to_str(opt_self_ty, purity, None, ast::Many,
-                                  vis));
+    head(s, ~"");
+    print_fn_header_info(s, opt_self_ty, purity, ast::Many, None, vis);
+    nbsp(s);
     print_ident(s, name);
     print_type_params(s, typarams);
     print_fn_args_and_ret(s, decl, ~[], opt_self_ty);
@@ -1836,7 +1834,8 @@ fn print_arg(s: ps, input: ast::arg) {
 }
 
 fn print_ty_fn(s: ps,
-               opt_proto: Option<ast::proto>,
+               opt_proto: Option<ast::Proto>,
+               opt_region: Option<@ast::region>,
                purity: ast::purity,
                onceness: ast::Onceness,
                bounds: @~[ast::ty_param_bound],
@@ -1844,8 +1843,15 @@ fn print_ty_fn(s: ps,
                tps: Option<~[ast::ty_param]>,
                opt_self_ty: Option<ast::self_ty_>) {
     ibox(s, indent_unit);
-    word(s.s, fn_header_info_to_str(opt_self_ty, Some(purity), opt_proto,
-                                    onceness, ast::inherited));
+
+    // Duplicates the logic in `print_fn_header_info()`.  This is because that
+    // function prints the proto in the wrong place.  That should be fixed.
+    print_self_ty_if_static(s, opt_self_ty);
+    print_opt_proto(s, opt_proto);
+    for opt_region.each |r| { print_region(s, ~"", *r, ~"/"); }
+    print_purity(s, purity);
+    print_onceness(s, onceness);
+    word(s.s, ~"fn");
     print_bounds(s, bounds);
     match id { Some(id) => { word(s.s, ~" "); print_ident(s, id); } _ => () }
     match tps { Some(tps) => print_type_params(s, tps), _ => () }
@@ -2066,39 +2072,50 @@ fn next_comment(s: ps) -> Option<comments::cmnt> {
     }
 }
 
-fn fn_header_info_to_str(opt_sty: Option<ast::self_ty_>,
-                         opt_purity: Option<ast::purity>,
-                         opt_p: Option<ast::proto>,
-                         onceness: ast::Onceness,
-                         vis: ast::visibility) -> ~str {
-
-    let mut s = visibility_qualified(vis, ~"");
-
-    match opt_sty {
-        Some(ast::sty_static) => str::push_str(&mut s, ~"static "),
-        _ => ()
-    };
+fn print_self_ty_if_static(s: ps,
+                           opt_self_ty: Option<ast::self_ty_>) {
+    match opt_self_ty {
+        Some(ast::sty_static) => { word(s.s, ~"static "); }
+        _ => {}
+    }
+}
 
+fn print_opt_purity(s: ps, opt_purity: Option<ast::purity>) {
     match opt_purity {
-      Some(ast::impure_fn) => { }
-      Some(purity) => {
-        str::push_str(&mut s, purity_to_str(purity));
-        str::push_char(&mut s, ' ');
-      }
-      None => {}
+        Some(ast::impure_fn) => { }
+        Some(purity) => {
+            word_nbsp(s, purity_to_str(purity));
+        }
+        None => {}
     }
+}
 
-    str::push_str(&mut s, opt_proto_to_str(opt_p));
-
-    match onceness {
-        ast::Once => str::push_str(&mut s, ~"once "),
-        ast::Many => {}
-    }
+fn print_opt_proto(s: ps, opt_proto: Option<ast::Proto>) {
+    match opt_proto {
+        Some(ast::ProtoBare) => { word(s.s, ~"extern "); }
+        Some(ast::ProtoBorrowed) => { word(s.s, ~"&"); }
+        Some(ast::ProtoUniq) => { word(s.s, ~"~"); }
+        Some(ast::ProtoBox) => { word(s.s, ~"@"); }
+        None => {}
+    };
+}
 
-    return s;
+fn print_fn_header_info(s: ps,
+                        opt_sty: Option<ast::self_ty_>,
+                        opt_purity: Option<ast::purity>,
+                        onceness: ast::Onceness,
+                        opt_proto: Option<ast::Proto>,
+                        vis: ast::visibility)
+{
+    word(s.s, visibility_qualified(vis, ~""));
+    print_self_ty_if_static(s, opt_sty);
+    print_opt_purity(s, opt_purity);
+    print_onceness(s, onceness);
+    word(s.s, ~"fn");
+    print_opt_proto(s, opt_proto);
 }
 
-fn opt_proto_to_str(opt_p: Option<ast::proto>) -> ~str {
+fn opt_proto_to_str(opt_p: Option<ast::Proto>) -> ~str {
     match opt_p {
       None => ~"fn",
       Some(p) => proto_to_str(p)
@@ -2128,12 +2145,19 @@ fn print_purity(s: ps, p: ast::purity) {
     }
 }
 
-fn proto_to_str(p: ast::proto) -> ~str {
+fn print_onceness(s: ps, o: ast::Onceness) {
+    match o {
+        ast::Once => { word_nbsp(s, ~"once"); }
+        ast::Many => {}
+    }
+}
+
+fn proto_to_str(p: ast::Proto) -> ~str {
     return match p {
-      ast::proto_bare => ~"extern fn",
-      ast::proto_block => ~"fn&",
-      ast::proto_uniq => ~"fn~",
-      ast::proto_box => ~"fn@"
+      ast::ProtoBare => ~"extern fn",
+      ast::ProtoBorrowed => ~"fn&",
+      ast::ProtoUniq => ~"fn~",
+      ast::ProtoBox => ~"fn@"
     };
 }
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index be6fb4cefa8..97cc52bd35a 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -15,7 +15,7 @@ enum vt<E> { mk_vt(visitor<E>), }
 enum fn_kind {
     fk_item_fn(ident, ~[ty_param], purity), //< an item declared with fn()
     fk_method(ident, ~[ty_param], @method),
-    fk_anon(proto, capture_clause),  //< an anonymous function like fn@(...)
+    fk_anon(Proto, capture_clause),  //< an anonymous function like fn@(...)
     fk_fn_block(capture_clause),     //< a block {||...}
     fk_dtor(~[ty_param], ~[attribute], node_id /* self id */,
             def_id /* parent class id */) // class destructor
@@ -203,13 +203,13 @@ fn visit_ty<E>(t: @Ty, e: E, v: vt<E>) {
       ty_tup(ts) => for ts.each |tt| {
         v.visit_ty(*tt, e, v);
       },
-      ty_fn(_, _, _, bounds, decl) => {
-        for decl.inputs.each |a| { v.visit_ty(a.ty, e, v); }
-        visit_ty_param_bounds(bounds, e, v);
-        v.visit_ty(decl.output, e, v);
+      ty_fn(f) => {
+        for f.decl.inputs.each |a| { v.visit_ty(a.ty, e, v); }
+        visit_ty_param_bounds(f.bounds, e, v);
+        v.visit_ty(f.decl.output, e, v);
       }
       ty_path(p, _) => visit_path(p, e, v),
-      ty_fixed_length(t, _) => v.visit_ty(t, e, v),
+      ty_fixed_length_vec(mt, _) => v.visit_ty(mt.ty, e, v),
       ty_nil |
       ty_bot |
       ty_mac(_) |
diff --git a/src/rustc/front/test.rs b/src/rustc/front/test.rs
index f0c9de4f2a2..c839be0739f 100644
--- a/src/rustc/front/test.rs
+++ b/src/rustc/front/test.rs
@@ -406,7 +406,7 @@ fn mk_test_wrapper(cx: test_ctxt,
     let wrapper_expr: ast::expr = {
         id: cx.sess.next_node_id(),
         callee_id: cx.sess.next_node_id(),
-        node: ast::expr_fn(ast::proto_bare, wrapper_decl,
+        node: ast::expr_fn(ast::ProtoBare, wrapper_decl,
                            wrapper_body, @~[]),
         span: span
     };
diff --git a/src/rustc/metadata/tydecode.rs b/src/rustc/metadata/tydecode.rs
index f15c254e71c..51c56cb8a64 100644
--- a/src/rustc/metadata/tydecode.rs
+++ b/src/rustc/metadata/tydecode.rs
@@ -103,11 +103,13 @@ 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(st: @pstate) -> ty::fn_proto {
+fn parse_proto(st: @pstate) -> ast::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)
+        '_' => ast::ProtoBare,
+        '@' => ast::ProtoBox,
+        '~' => ast::ProtoUniq,
+        '&' => ast::ProtoBorrowed,
+        _ => fail ~"parse_proto(): bad input"
     }
 }
 
@@ -293,13 +295,8 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
       }
       'Y' => return ty::mk_type(st.tcx),
       'C' => {
-        let ck = match next(st) {
-          '&' => ty::ck_block,
-          '@' => ty::ck_box,
-          '~' => ty::ck_uniq,
-          _ => fail ~"parse_ty: bad closure kind"
-        };
-        return ty::mk_opaque_closure_ptr(st.tcx, ck);
+        let proto = parse_proto(st);
+        return ty::mk_opaque_closure_ptr(st.tcx, proto);
       }
       '#' => {
         let pos = parse_hex(st);
@@ -415,6 +412,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::FnTy {
     let proto = parse_proto(st);
     let purity = parse_purity(next(st));
     let onceness = parse_onceness(next(st));
+    let region = parse_region(st);
     let bounds = parse_bounds(st, conv);
     assert (next(st) == '[');
     let mut inputs: ~[ty::arg] = ~[];
@@ -429,6 +427,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::FnTy {
                       proto: proto,
                       onceness: onceness,
                       bounds: bounds,
+                      region: region,
                       ret_style: ret_style},
         sig: FnSig {inputs: inputs,
                     output: ret_ty}
diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs
index 725b8c41f5c..4129066ff28 100644
--- a/src/rustc/metadata/tyencode.rs
+++ b/src/rustc/metadata/tyencode.rs
@@ -296,9 +296,10 @@ fn enc_sty(w: io::Writer, cx: @ctxt, st: ty::sty) {
         w.write_char('s');
       }
       ty::ty_type => w.write_char('Y'),
-      ty::ty_opaque_closure_ptr(ty::ck_block) => w.write_str(&"C&"),
-      ty::ty_opaque_closure_ptr(ty::ck_box) => w.write_str(&"C@"),
-      ty::ty_opaque_closure_ptr(ty::ck_uniq) => w.write_str(&"C~"),
+      ty::ty_opaque_closure_ptr(p) => {
+          w.write_str(&"C&");
+          enc_proto(w, p);
+      }
       ty::ty_opaque_box => w.write_char('B'),
       ty::ty_class(def, substs) => {
           debug!("~~~~ %s", ~"a[");
@@ -315,14 +316,13 @@ fn enc_sty(w: io::Writer, cx: @ctxt, st: ty::sty) {
     }
 }
 
-fn enc_proto(w: io::Writer, cx: @ctxt, proto: ty::fn_proto) {
+fn enc_proto(w: io::Writer, proto: Proto) {
     w.write_str(&"f");
     match proto {
-        ty::proto_bare => w.write_str(&"n"),
-        ty::proto_vstore(vstore) => {
-            w.write_str(&"v");
-            enc_vstore(w, cx, vstore);
-        }
+        ProtoBare => w.write_str(&"_"),
+        ProtoBox => w.write_str(&"@"),
+        ProtoUniq => w.write_str(&"~"),
+        ProtoBorrowed => w.write_str(&"&"),
     }
 }
 
@@ -357,9 +357,10 @@ fn enc_onceness(w: io::Writer, o: Onceness) {
 }
 
 fn enc_ty_fn(w: io::Writer, cx: @ctxt, ft: ty::FnTy) {
-    enc_proto(w, cx, ft.meta.proto);
+    enc_proto(w, ft.meta.proto);
     enc_purity(w, ft.meta.purity);
     enc_onceness(w, ft.meta.onceness);
+    enc_region(w, cx, ft.meta.region);
     enc_bounds(w, cx, ft.meta.bounds);
     w.write_char('[');
     for ft.sig.inputs.each |arg| {
diff --git a/src/rustc/middle/borrowck/check_loans.rs b/src/rustc/middle/borrowck/check_loans.rs
index efde1985677..d63f52a4a58 100644
--- a/src/rustc/middle/borrowck/check_loans.rs
+++ b/src/rustc/middle/borrowck/check_loans.rs
@@ -234,7 +234,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);
-        return ty::is_blockish(proto);
+        return proto == ast::ProtoBorrowed;
     }
 
     fn is_allowed_pure_arg(expr: @ast::expr) -> bool {
diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs
index 23f0d9edbfa..9875e8600ea 100644
--- a/src/rustc/middle/borrowck/gather_loans.rs
+++ b/src/rustc/middle/borrowck/gather_loans.rs
@@ -241,12 +241,18 @@ impl gather_loan_ctxt {
                                              autoref.mutbl,
                                              autoref.region)
                     }
-                    ty::AutoSlice => {
+                    ty::AutoBorrowVec => {
                         let cmt_index = mcx.cat_index(expr, cmt);
                         self.guarantee_valid(cmt_index,
                                              autoref.mutbl,
                                              autoref.region)
                     }
+                    ty::AutoBorrowFn => {
+                        let cmt_deref = mcx.cat_deref_fn(expr, cmt, 0);
+                        self.guarantee_valid(cmt_deref,
+                                             autoref.mutbl,
+                                             autoref.region)
+                    }
                 }
             }
         }
diff --git a/src/rustc/middle/capture.rs b/src/rustc/middle/capture.rs
index 563ea8f84be..dae17f66d15 100644
--- a/src/rustc/middle/capture.rs
+++ b/src/rustc/middle/capture.rs
@@ -58,7 +58,7 @@ fn check_capture_clause(tcx: ty::ctxt,
 
 fn compute_capture_vars(tcx: ty::ctxt,
                         fn_expr_id: ast::node_id,
-                        fn_proto: ty::fn_proto,
+                        fn_proto: ast::Proto,
                         cap_clause: ast::capture_clause) -> ~[capture_var] {
     let freevars = freevars::get_freevars(tcx, fn_expr_id);
     let cap_map = map::HashMap();
@@ -101,7 +101,7 @@ fn compute_capture_vars(tcx: ty::ctxt,
     // named and add that
 
     let implicit_mode;
-    if ty::is_blockish(fn_proto) {
+    if fn_proto == ast::ProtoBorrowed {
         implicit_mode = cap_ref;
     } else {
         implicit_mode = cap_copy;
diff --git a/src/rustc/middle/check_loop.rs b/src/rustc/middle/check_loop.rs
index 3fa7f34fb33..de275fdcfc4 100644
--- a/src/rustc/middle/check_loop.rs
+++ b/src/rustc/middle/check_loop.rs
@@ -24,8 +24,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 = ty::is_blockish(ty::ty_fn_proto(ty::expr_ty(tcx,
-                                                                      e)));
+                let proto = ty::ty_fn_proto(ty::expr_ty(tcx, e));
+                let blk = (proto == ProtoBorrowed);
                 v.visit_block(b, {in_loop: true, can_ret: blk}, v);
               }
               expr_break(_) => {
diff --git a/src/rustc/middle/freevars.rs b/src/rustc/middle/freevars.rs
index 1b42c9bb4b6..16f4a66ff0b 100644
--- a/src/rustc/middle/freevars.rs
+++ b/src/rustc/middle/freevars.rs
@@ -40,7 +40,7 @@ fn collect_freevars(def_map: resolve::DefMap, blk: ast::blk)
     let walk_expr = fn@(expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
             match expr.node {
               ast::expr_fn(proto, _, _, _) => {
-                if proto != ast::proto_bare {
+                if proto != ast::ProtoBare {
                     visit::visit_expr(expr, depth + 1, v);
                 }
               }
diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs
index 8eace4f5cf1..c0887150f24 100644
--- a/src/rustc/middle/kind.rs
+++ b/src/rustc/middle/kind.rs
@@ -159,12 +159,10 @@ 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) {
-      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"
+        ProtoUniq => b(check_for_uniq),
+        ProtoBox => b(check_for_box),
+        ProtoBare => b(check_for_bare),
+        ProtoBorrowed => b(check_for_block),
     }
 }
 
diff --git a/src/rustc/middle/lint.rs b/src/rustc/middle/lint.rs
index 9d28e35acb0..3be1e6d1a61 100644
--- a/src/rustc/middle/lint.rs
+++ b/src/rustc/middle/lint.rs
@@ -841,29 +841,15 @@ fn check_fn_deprecated_modes(tcx: ty::ctxt, fn_ty: ty::t, decl: ast::fn_decl,
                         let span = arg_ast.ty.span;
                         // Recurse to check fn-type argument
                         match arg_ast.ty.node {
-                            ast::ty_fn(_, _, _, _, decl) => {
+                            ast::ty_fn(f) => {
                                 check_fn_deprecated_modes(tcx, arg_ty.ty,
-                                                          decl, span, id);
+                                                          f.decl, span, id);
                             }
                             ast::ty_path(*) => {
                                 // This is probably a typedef, so we can't
                                 // see the actual fn decl
                                 // e.g. fn foo(f: InitOp<T>)
                             }
-                            ast::ty_rptr(_, mt)
-                            | ast::ty_box(mt)
-                            | ast::ty_uniq(mt) => {
-                                // Functions with preceding sigil are parsed
-                                // as pointers of functions
-                                match mt.ty.node {
-                                    ast::ty_fn(_, _, _, _, decl) => {
-                                        check_fn_deprecated_modes(
-                                            tcx, arg_ty.ty,
-                                            decl, span, id);
-                                    }
-                                    _ => fail
-                                }
-                            }
                             _ => {
                                 tcx.sess.span_warn(span, ~"what");
                                 error!("arg %d, ty=%s, mode=%s",
@@ -889,10 +875,10 @@ fn check_item_deprecated_modes(tcx: ty::ctxt, it: @ast::item) {
     match it.node {
         ast::item_ty(ty, _) => {
             match ty.node {
-                ast::ty_fn(_, _, _, _, decl) => {
+                ast::ty_fn(f) => {
                     let fn_ty = ty::node_id_to_type(tcx, it.id);
                     check_fn_deprecated_modes(
-                        tcx, fn_ty, decl, ty.span, it.id)
+                        tcx, fn_ty, f.decl, ty.span, it.id)
                 }
                 _ => ()
             }
diff --git a/src/rustc/middle/mem_categorization.rs b/src/rustc/middle/mem_categorization.rs
index 55bf41b573e..a43dc0747de 100644
--- a/src/rustc/middle/mem_categorization.rs
+++ b/src/rustc/middle/mem_categorization.rs
@@ -305,18 +305,30 @@ fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
         Some(deref_ptr(uniq_ptr))
       }
 
+      ty::ty_fn(f) if f.meta.proto == ast::ProtoUniq => {
+        Some(deref_ptr(uniq_ptr))
+      }
+
       ty::ty_rptr(r, _) |
       ty::ty_evec(_, ty::vstore_slice(r)) |
       ty::ty_estr(ty::vstore_slice(r)) => {
         Some(deref_ptr(region_ptr(r)))
       }
 
+      ty::ty_fn(f) if f.meta.proto == ast::ProtoBorrowed => {
+        Some(deref_ptr(region_ptr(f.meta.region)))
+      }
+
       ty::ty_box(*) |
       ty::ty_evec(_, ty::vstore_box) |
       ty::ty_estr(ty::vstore_box) => {
         Some(deref_ptr(gc_ptr))
       }
 
+      ty::ty_fn(f) if f.meta.proto == ast::ProtoBox => {
+        Some(deref_ptr(gc_ptr))
+      }
+
       ty::ty_ptr(*) => {
         Some(deref_ptr(unsafe_ptr))
       }
@@ -563,22 +575,23 @@ 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 {
-              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}
-              }
-              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"
+                ast::ProtoBorrowed => {
+                    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::ProtoUniq | ast::ProtoBox => {
+                    // 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}
+                }
+                ast::ProtoBare => {
+                    self.tcx.sess.span_bug(
+                        span,
+                        fmt!("Upvar in a bare closure?"));
+                }
             }
           }
 
@@ -648,16 +661,16 @@ impl &mem_categorization_ctxt {
                              base_cmt: cmt,
                              f_name: ast::ident,
                              field_id: ast::node_id) -> cmt {
-        let f_mutbl = match field_mutbl(self.tcx, base_cmt.ty, f_name,
-                                        field_id) {
-          Some(f_mutbl) => f_mutbl,
-          None => {
-            self.tcx.sess.span_bug(
-                node.span(),
-                fmt!("Cannot find field `%s` in type `%s`",
-                     self.tcx.sess.str_of(f_name),
-                     ty_to_str(self.tcx, base_cmt.ty)));
-          }
+        let f_mutbl = match field_mutbl(self.tcx, base_cmt.ty,
+                                        f_name, field_id) {
+            Some(f_mutbl) => f_mutbl,
+            None => {
+                self.tcx.sess.span_bug(
+                    node.span(),
+                    fmt!("Cannot find field `%s` in type `%s`",
+                         self.tcx.sess.str_of(f_name),
+                         ty_to_str(self.tcx, base_cmt.ty)));
+            }
         };
         let m = self.inherited_mutability(base_cmt.mutbl, f_mutbl);
         let f_comp = comp_field(f_name, f_mutbl);
@@ -667,9 +680,24 @@ impl &mem_categorization_ctxt {
           mutbl: m, ty: self.tcx.ty(node)}
     }
 
+    fn cat_deref_fn<N:ast_node>(node: N,
+                                base_cmt: cmt,
+                                deref_cnt: uint) -> cmt
+    {
+        // Bit of a hack: the "dereference" of a function pointer like
+        // `@fn()` is a mere logical concept. We interpret it as
+        // dereferencing the environment pointer; of course, we don't
+        // know what type lies at the other end, so we just call it
+        // `()` (the empty tuple).
+
+        let mt = {ty: ty::mk_tup(self.tcx, ~[]), mutbl: m_imm};
+        return self.cat_deref_common(node, base_cmt, deref_cnt, mt);
+    }
+
     fn cat_deref<N:ast_node>(node: N,
                              base_cmt: cmt,
-                             deref_cnt: uint) -> cmt {
+                             deref_cnt: uint) -> cmt
+    {
         let mt = match ty::deref(self.tcx, base_cmt.ty, true) {
             Some(mt) => mt,
             None => {
@@ -680,6 +708,14 @@ impl &mem_categorization_ctxt {
             }
         };
 
+        return self.cat_deref_common(node, base_cmt, deref_cnt, mt);
+    }
+
+    fn cat_deref_common<N:ast_node>(node: N,
+                                    base_cmt: cmt,
+                                    deref_cnt: uint,
+                                    mt: ty::mt) -> cmt
+    {
         match deref_kind(self.tcx, base_cmt.ty) {
             deref_ptr(ptr) => {
                 let lp = do base_cmt.lp.chain_ref |l| {
diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs
index a98ec2181d9..0be27483a10 100644
--- a/src/rustc/middle/region.rs
+++ b/src/rustc/middle/region.rs
@@ -615,23 +615,35 @@ fn determine_rp_in_ty(ty: @ast::Ty,
     // region is expected (and hence is a supertype of those
     // locations)
     match ty.node {
-      ast::ty_rptr(r, _) => {
-        debug!("referenced rptr type %s",
-               pprust::ty_to_str(ty, cx.sess.intr()));
+        ast::ty_rptr(r, _) => {
+            debug!("referenced rptr type %s",
+                   pprust::ty_to_str(ty, cx.sess.intr()));
 
-        if cx.region_is_relevant(r) {
-            cx.add_rp(cx.item_id, cx.add_variance(rv_contravariant))
+            if cx.region_is_relevant(r) {
+                cx.add_rp(cx.item_id, cx.add_variance(rv_contravariant))
+            }
         }
-      }
 
-      ast::ty_fn(ast::proto_bare, _, _, _, _) |
-      ast::ty_fn(ast::proto_block, _, _, _, _) if cx.anon_implies_rp => {
-        debug!("referenced bare fn type with regions %s",
-               pprust::ty_to_str(ty, cx.sess.intr()));
-        cx.add_rp(cx.item_id, cx.add_variance(rv_contravariant));
-      }
+        ast::ty_fn(f) => {
+            debug!("referenced fn type: %s",
+                   pprust::ty_to_str(ty, cx.sess.intr()));
+            match f.region {
+                Some(r) => {
+                    if cx.region_is_relevant(r) {
+                        cx.add_rp(cx.item_id,
+                                  cx.add_variance(rv_contravariant))
+                    }
+                }
+                None => {
+                    if f.proto == ast::ProtoBorrowed && cx.anon_implies_rp {
+                        cx.add_rp(cx.item_id,
+                                  cx.add_variance(rv_contravariant));
+                    }
+                }
+            }
+        }
 
-      _ => {}
+        _ => {}
     }
 
     // if this references another named type, add the dependency
@@ -666,25 +678,6 @@ fn determine_rp_in_ty(ty: @ast::Ty,
       _ => {}
     }
 
-    // temporary hack: right now, fn() is short for &fn(), but @(fn())
-    // is `@fn()`, so catch this and set anon_implies_rp to none in
-    // that case
-    match ty.node {
-      ast::ty_box(mt) | ast::ty_uniq(mt) => {
-        match mt.ty.node {
-          ast::ty_fn(ast::proto_bare, _, _, _, _) |
-          ast::ty_fn(ast::proto_block, _, _, _, _) => {
-            do cx.with(cx.item_id, false) {
-                visit_mt(mt, cx, visitor);
-            }
-            return;
-          }
-          _ => {}
-        }
-      }
-      _ => {}
-    }
-
     match ty.node {
       ast::ty_box(mt) | ast::ty_uniq(mt) | ast::ty_vec(mt) |
       ast::ty_rptr(_, mt) | ast::ty_ptr(mt) => {
@@ -706,18 +699,18 @@ fn determine_rp_in_ty(ty: @ast::Ty,
         }
       }
 
-      ast::ty_fn(_, _, _, bounds, decl) => {
+      ast::ty_fn(f) => {
         // fn() binds the & region, so do not consider &T types that
         // appear *inside* a fn() type to affect the enclosing item:
         do cx.with(cx.item_id, false) {
             // parameters are contravariant
             do cx.with_ambient_variance(rv_contravariant) {
-                for decl.inputs.each |a| {
+                for f.decl.inputs.each |a| {
                     visitor.visit_ty(a.ty, cx, visitor);
                 }
             }
-            visit::visit_ty_param_bounds(bounds, cx, visitor);
-            visitor.visit_ty(decl.output, cx, visitor);
+            visit::visit_ty_param_bounds(f.bounds, cx, visitor);
+            visitor.visit_ty(f.decl.output, cx, visitor);
         }
       }
 
diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs
index 3997076f987..b42d823f0c6 100644
--- a/src/rustc/middle/trans/closure.rs
+++ b/src/rustc/middle/trans/closure.rs
@@ -144,9 +144,7 @@ fn mk_closure_tys(tcx: ty::ctxt,
     return cdata_ty;
 }
 
-fn allocate_cbox(bcx: block,
-                 ck: ty::closure_kind,
-                 cdata_ty: ty::t)
+fn allocate_cbox(bcx: block, proto: ast::Proto, cdata_ty: ty::t)
     -> Result
 {
     let _icx = bcx.insn_ctxt("closure::allocate_cbox");
@@ -163,15 +161,23 @@ fn allocate_cbox(bcx: block,
     }
 
     // Allocate and initialize the box:
-    match ck {
-      ty::ck_box => malloc_raw(bcx, cdata_ty, heap_shared),
-      ty::ck_uniq => malloc_raw(bcx, cdata_ty, heap_exchange),
-      ty::ck_block => {
-          let cbox_ty = tuplify_box_ty(tcx, cdata_ty);
-          let llbox = base::alloc_ty(bcx, cbox_ty);
-          nuke_ref_count(bcx, llbox);
-          rslt(bcx, llbox)
-      }
+    match proto {
+        ast::ProtoBox => {
+            malloc_raw(bcx, cdata_ty, heap_shared)
+        }
+        ast::ProtoUniq => {
+            malloc_raw(bcx, cdata_ty, heap_exchange)
+        }
+        ast::ProtoBorrowed => {
+            let cbox_ty = tuplify_box_ty(tcx, cdata_ty);
+            let llbox = base::alloc_ty(bcx, cbox_ty);
+            nuke_ref_count(bcx, llbox);
+            rslt(bcx, llbox)
+        }
+        ast::ProtoBare => {
+            let cdata_llty = type_of(bcx.ccx(), cdata_ty);
+            rslt(bcx, C_null(cdata_llty))
+        }
     }
 }
 
@@ -187,7 +193,7 @@ type closure_result = {
 // Otherwise, it is stack allocated and copies pointers to the upvars.
 fn store_environment(bcx: block,
                      bound_values: ~[EnvValue],
-                     ck: ty::closure_kind) -> closure_result {
+                     proto: ast::Proto) -> closure_result {
     let _icx = bcx.insn_ctxt("closure::store_environment");
     let ccx = bcx.ccx(), tcx = ccx.tcx;
 
@@ -195,7 +201,7 @@ fn store_environment(bcx: block,
     let cdata_ty = mk_closure_tys(tcx, bound_values);
 
     // allocate closure in the heap
-    let Result {bcx: bcx, val: llbox} = allocate_cbox(bcx, ck, cdata_ty);
+    let Result {bcx: bcx, val: llbox} = allocate_cbox(bcx, proto, cdata_ty);
     let mut temp_cleanups = ~[];
 
     // cbox_ty has the form of a tuple: (a, b, c) we want a ptr to a
@@ -243,7 +249,7 @@ fn store_environment(bcx: block,
 // collects the upvars and packages them up for store_environment.
 fn build_closure(bcx0: block,
                  cap_vars: ~[capture::capture_var],
-                 ck: ty::closure_kind,
+                 proto: ast::Proto,
                  include_ret_handle: Option<ValueRef>) -> closure_result {
     let _icx = bcx0.insn_ctxt("closure::build_closure");
     // If we need to, package up the iterator body to call
@@ -257,7 +263,7 @@ fn build_closure(bcx0: block,
         let datum = expr::trans_local_var(bcx, cap_var.def);
         match cap_var.mode {
             capture::cap_ref => {
-                assert ck == ty::ck_block;
+                assert proto == ast::ProtoBorrowed;
                 env_vals.push(EnvValue {action: EnvRef,
                                         datum: datum});
             }
@@ -298,7 +304,7 @@ fn build_closure(bcx0: block,
                                 datum: ret_datum});
     }
 
-    return store_environment(bcx, env_vals, ck);
+    return store_environment(bcx, env_vals, proto);
 }
 
 // Given an enclosing block context, a new function context, a closure type,
@@ -308,7 +314,7 @@ fn load_environment(fcx: fn_ctxt,
                     cdata_ty: ty::t,
                     cap_vars: ~[capture::capture_var],
                     load_ret_handle: bool,
-                    ck: ty::closure_kind) {
+                    proto: ast::Proto) {
     let _icx = fcx.insn_ctxt("closure::load_environment");
     let bcx = raw_block(fcx, false, fcx.llloadenv);
 
@@ -322,9 +328,9 @@ fn load_environment(fcx: fn_ctxt,
           capture::cap_drop => { /* ignore */ }
           _ => {
             let mut upvarptr = GEPi(bcx, llcdata, [0u, i]);
-            match ck {
-              ty::ck_block => { upvarptr = Load(bcx, upvarptr); }
-              ty::ck_uniq | ty::ck_box => ()
+            match proto {
+                ast::ProtoBorrowed => { upvarptr = Load(bcx, upvarptr); }
+                ast::ProtoBox | ast::ProtoUniq | ast::ProtoBare => {}
             }
             let def_id = ast_util::def_id_of_def(cap_var.def);
             fcx.llupvars.insert(def_id.node, upvarptr);
@@ -341,7 +347,7 @@ fn load_environment(fcx: fn_ctxt,
 }
 
 fn trans_expr_fn(bcx: block,
-                 proto: ty::fn_proto,
+                 proto: ast::Proto,
                  decl: ast::fn_decl,
                  body: ast::blk,
                  id: ast::node_id,
@@ -365,16 +371,16 @@ fn trans_expr_fn(bcx: block,
     let s = mangle_internal_name_by_path_and_seq(ccx, sub_path, ~"expr_fn");
     let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
 
-    let trans_closure_env = fn@(ck: ty::closure_kind) -> Result {
+    let trans_closure_env = fn@(proto: ast::Proto) -> Result {
         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,
+        let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, proto,
                                                    ret_handle);
         trans_closure(ccx, sub_path, decl, body, llfn, no_self,
                       bcx.fcx.param_substs, id, None, |fcx| {
             load_environment(fcx, cdata_ty, cap_vars,
-                             ret_handle.is_some(), ck);
+                             ret_handle.is_some(), proto);
                       }, |bcx| {
             if is_loop_body.is_some() {
                 Store(bcx, C_bool(true), bcx.fcx.llretptr);
@@ -384,23 +390,14 @@ fn trans_expr_fn(bcx: block,
     };
 
     let Result {bcx: bcx, val: closure} = match proto {
-        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)
+        ast::ProtoBorrowed | ast::ProtoBox | ast::ProtoUniq => {
+            trans_closure_env(proto)
         }
-        ty::proto_bare => {
+        ast::ProtoBare => {
             trans_closure(ccx, sub_path, decl, body, llfn, no_self, None,
                           id, None, |_fcx| { }, |_bcx| { });
             rslt(bcx, C_null(T_opaque_box_ptr(ccx)))
         }
-        ty::proto_vstore(ty::vstore_fixed(_)) => {
-            fail ~"vstore_fixed unexpected"
-        }
     };
     fill_fn_pair(bcx, dest_addr, llfn, closure);
 
@@ -412,48 +409,48 @@ fn make_fn_glue(
     v: ValueRef,
     t: ty::t,
     glue_fn: fn@(block, v: ValueRef, t: ty::t) -> block)
-    -> block {
+    -> block
+{
     let _icx = cx.insn_ctxt("closure::make_fn_glue");
     let bcx = cx;
     let tcx = cx.tcx();
 
-    let fn_env = fn@(ck: ty::closure_kind) -> block {
-        let box_cell_v = GEPi(cx, v, [0u, abi::fn_field_box]);
-        let box_ptr_v = Load(cx, box_cell_v);
-        do with_cond(cx, IsNotNull(cx, box_ptr_v)) |bcx| {
-            let closure_ty = ty::mk_opaque_closure_ptr(tcx, ck);
-            glue_fn(bcx, box_cell_v, closure_ty)
-        }
-    };
-
     let proto = ty::ty_fn_proto(t);
     match proto {
-        ty::proto_bare | ty::proto_vstore(ty::vstore_slice(_)) => bcx,
-        ty::proto_vstore(ty::vstore_uniq) => fn_env(ty::ck_uniq),
-        ty::proto_vstore(ty::vstore_box) => fn_env(ty::ck_box),
-        ty::proto_vstore(ty::vstore_fixed(_)) => {
-            cx.sess().bug(~"Closure with fixed vstore");
+        ast::ProtoBare | ast::ProtoBorrowed => bcx,
+        ast::ProtoUniq | ast::ProtoBox => {
+            let box_cell_v = GEPi(cx, v, [0u, abi::fn_field_box]);
+            let box_ptr_v = Load(cx, box_cell_v);
+            do with_cond(cx, IsNotNull(cx, box_ptr_v)) |bcx| {
+                let closure_ty = ty::mk_opaque_closure_ptr(tcx, proto);
+                glue_fn(bcx, box_cell_v, closure_ty)
+            }
         }
     }
 }
 
 fn make_opaque_cbox_take_glue(
     bcx: block,
-    ck: ty::closure_kind,
+    proto: ast::Proto,
     cboxptr: ValueRef)     // ptr to ptr to the opaque closure
-    -> block {
+    -> block
+{
     // Easy cases:
     let _icx = bcx.insn_ctxt("closure::make_opaque_cbox_take_glue");
-    match ck {
-        ty::ck_block => return bcx,
-        ty::ck_box => {
+    match proto {
+        ast::ProtoBare | ast::ProtoBorrowed => {
+            return bcx;
+        }
+        ast::ProtoBox => {
             glue::incr_refcnt_of_boxed(bcx, Load(bcx, cboxptr));
             return bcx;
         }
-        ty::ck_uniq => { /* hard case: */ }
+        ast::ProtoUniq => {
+            /* hard case: fallthrough to code below */
+        }
     }
 
-    // Hard case, a deep copy:
+    // fn~ requires a deep copy.
     let ccx = bcx.ccx(), tcx = ccx.tcx;
     let llopaquecboxty = T_opaque_box_ptr(ccx);
     let cbox_in = Load(bcx, cboxptr);
@@ -492,34 +489,38 @@ fn make_opaque_cbox_take_glue(
 
 fn make_opaque_cbox_drop_glue(
     bcx: block,
-    ck: ty::closure_kind,
+    proto: ast::Proto,
     cboxptr: ValueRef)     // ptr to the opaque closure
     -> block {
     let _icx = bcx.insn_ctxt("closure::make_opaque_cbox_drop_glue");
-    match ck {
-        ty::ck_block => bcx,
-        ty::ck_box => {
+    match proto {
+        ast::ProtoBare | ast::ProtoBorrowed => bcx,
+        ast::ProtoBox => {
             glue::decr_refcnt_maybe_free(
                 bcx, Load(bcx, cboxptr),
-                ty::mk_opaque_closure_ptr(bcx.tcx(), ck))
+                ty::mk_opaque_closure_ptr(bcx.tcx(), proto))
         }
-        ty::ck_uniq => {
+        ast::ProtoUniq => {
             glue::free_ty(
                 bcx, cboxptr,
-                ty::mk_opaque_closure_ptr(bcx.tcx(), ck))
+                ty::mk_opaque_closure_ptr(bcx.tcx(), proto))
         }
     }
 }
 
 fn make_opaque_cbox_free_glue(
     bcx: block,
-    ck: ty::closure_kind,
+    proto: ast::Proto,
     cbox: ValueRef)     // ptr to ptr to the opaque closure
     -> block {
     let _icx = bcx.insn_ctxt("closure::make_opaque_cbox_free_glue");
-    match ck {
-      ty::ck_block => return bcx,
-      ty::ck_box | ty::ck_uniq => { /* hard cases: */ }
+    match proto {
+        ast::ProtoBare | ast::ProtoBorrowed => {
+            return bcx;
+        }
+        ast::ProtoBox | ast::ProtoUniq => {
+            /* hard cases: fallthrough to code below */
+        }
     }
 
     let ccx = bcx.ccx();
@@ -537,10 +538,12 @@ fn make_opaque_cbox_free_glue(
                                     abi::tydesc_field_drop_glue, None);
 
         // Free the ty descr (if necc) and the box itself
-        match ck {
-            ty::ck_block => fail ~"Impossible",
-            ty::ck_box => glue::trans_free(bcx, cbox),
-            ty::ck_uniq => glue::trans_unique_free(bcx, cbox)
+        match proto {
+            ast::ProtoBox => glue::trans_free(bcx, cbox),
+            ast::ProtoUniq => glue::trans_unique_free(bcx, cbox),
+            ast::ProtoBare | ast::ProtoBorrowed => {
+                bcx.sess().bug(~"impossible")
+            }
         }
     }
 }
diff --git a/src/rustc/middle/trans/expr.rs b/src/rustc/middle/trans/expr.rs
index 1bd44ee4bda..06d56f4542f 100644
--- a/src/rustc/middle/trans/expr.rs
+++ b/src/rustc/middle/trans/expr.rs
@@ -109,7 +109,7 @@ use base::*;
 use syntax::print::pprust::{expr_to_str};
 use util::ppaux::ty_to_str;
 use util::common::indenter;
-use ty::{AutoPtr, AutoSlice};
+use ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn};
 use callee::{AutorefArg, DoAutorefArg, DontAutorefArg};
 
 // The primary two functions for translating expressions:
@@ -188,9 +188,15 @@ fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
                         AutoPtr => {
                             unpack_datum!(bcx, auto_ref(bcx, datum))
                         }
-                        AutoSlice => {
+                        AutoBorrowVec => {
                             unpack_datum!(bcx, auto_slice(bcx, datum))
                         }
+                        AutoBorrowFn => {
+                            // currently, all closure types are
+                            // represented precisely the same, so no
+                            // runtime adjustment is required:
+                            datum
+                        }
                     }
                 }
             };
@@ -520,20 +526,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
         ast::expr_fn(proto, decl, body, cap_clause) => {
             // Don't use this function for anything real. Use the one in
             // astconv instead.
-            fn ast_proto_to_proto_simple(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))
-                    }
-                }
-            }
-
-            return closure::trans_expr_fn(bcx,
-                                          ast_proto_to_proto_simple(proto),
+            return closure::trans_expr_fn(bcx, proto,
                                           decl, body, expr.id, cap_clause,
                                           None, dest);
         }
diff --git a/src/rustc/middle/trans/foreign.rs b/src/rustc/middle/trans/foreign.rs
index 933fb7eedfb..b4aeface943 100644
--- a/src/rustc/middle/trans/foreign.rs
+++ b/src/rustc/middle/trans/foreign.rs
@@ -997,10 +997,9 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
                 ty::mk_mach_uint(bcx.tcx(), ast::ty_u8));
             let fty = ty::mk_fn(bcx.tcx(), FnTyBase {
                 meta: FnMeta {purity: ast::impure_fn,
-                              proto:
-                                  ty::proto_vstore(ty::vstore_slice(
-                                      ty::re_bound(ty::br_anon(0)))),
+                              proto: ast::ProtoBorrowed,
                               onceness: ast::Many,
+                              region: ty::re_bound(ty::br_anon(0)),
                               bounds: @~[],
                               ret_style: ast::return_val},
                 sig: FnSig {inputs: ~[{mode: ast::expl(ast::by_val),
diff --git a/src/rustc/middle/trans/monomorphize.rs b/src/rustc/middle/trans/monomorphize.rs
index 0c93c610b68..2e18fb2a2e9 100644
--- a/src/rustc/middle/trans/monomorphize.rs
+++ b/src/rustc/middle/trans/monomorphize.rs
@@ -251,18 +251,19 @@ fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> Option<ty::t> {
                 FnTyBase {meta: FnMeta {purity: ast::impure_fn,
                                         proto: fty.meta.proto,
                                         onceness: ast::Many,
+                                        region: ty::re_static,
                                         bounds: @~[],
                                         ret_style: ast::return_val},
                           sig: FnSig {inputs: ~[],
                                       output: ty::mk_nil(tcx)}}))
         }
         ty::ty_trait(_, _, _) => {
-            let box_proto = ty::proto_vstore(ty::vstore_box);
             Some(ty::mk_fn(
                 tcx,
                 FnTyBase {meta: FnMeta {purity: ast::impure_fn,
-                                        proto: box_proto,
+                                        proto: ast::ProtoBox,
                                         onceness: ast::Many,
+                                        region: ty::re_static,
                                         bounds: @~[],
                                         ret_style: ast::return_val},
                           sig: FnSig {inputs: ~[],
diff --git a/src/rustc/middle/trans/reflect.rs b/src/rustc/middle/trans/reflect.rs
index c52b653d536..5724c5ada22 100644
--- a/src/rustc/middle/trans/reflect.rs
+++ b/src/rustc/middle/trans/reflect.rs
@@ -186,14 +186,7 @@ impl reflector {
               ast::impure_fn => 2u,
               ast::extern_fn => 3u
             };
-            let protoval = match fty.meta.proto {
-              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 protoval = ast_proto_constant(fty.meta.proto);
             let retval = match fty.meta.ret_style {
               ast::noreturn => 0u,
               ast::return_val => 1u
@@ -278,11 +271,7 @@ impl reflector {
           ty::ty_type => self.leaf(~"type"),
           ty::ty_opaque_box => self.leaf(~"opaque_box"),
           ty::ty_opaque_closure_ptr(ck) => {
-            let ckval = match ck {
-              ty::ck_block => 0u,
-              ty::ck_box => 1u,
-              ty::ck_uniq => 2u
-            };
+            let ckval = ast_proto_constant(ck);
             self.visit(~"closure_ptr", ~[self.c_uint(ckval)])
           }
         }
@@ -309,3 +298,12 @@ fn emit_calls_to_trait_visit_ty(bcx: block, t: ty::t,
     Br(r.bcx, final.llbb);
     return final;
 }
+
+fn ast_proto_constant(proto: ast::Proto) -> uint {
+    match proto {
+        ast::ProtoBare => 0u,
+        ast::ProtoUniq => 2u,
+        ast::ProtoBox => 3u,
+        ast::ProtoBorrowed => 4u,
+    }
+}
\ No newline at end of file
diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs
index b8a7580e03c..53889369361 100644
--- a/src/rustc/middle/trans/type_use.rs
+++ b/src/rustc/middle/trans/type_use.rs
@@ -213,16 +213,13 @@ 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)) {
-          ty::proto_bare | ty::proto_vstore(ty::vstore_uniq) => {}
-          ty::proto_vstore(ty::vstore_box) |
-          ty::proto_vstore(ty::vstore_slice(_)) => {
+          ast::ProtoBare | ast::ProtoUniq => {}
+          ast::ProtoBox | ast::ProtoBorrowed => {
             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 69b4d985f6f..14c5ed5e71e 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -157,10 +157,6 @@ export set_default_mode;
 export variant_info;
 export walk_ty, maybe_walk_ty;
 export occurs_check;
-export closure_kind;
-export ck_block;
-export ck_box;
-export ck_uniq;
 export param_ty;
 export param_bound, param_bounds, bound_copy, bound_owned;
 export param_bounds_to_str, param_bound_to_str;
@@ -190,9 +186,7 @@ export purity_to_str;
 export onceness_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;
 export method_call_bounds;
 export hash_region;
 export region_variance, rv_covariant, rv_invariant, rv_contravariant;
@@ -200,10 +194,11 @@ export opt_region_variance;
 export determine_inherited_purity;
 export provided_trait_methods;
 export trait_supertraits;
-export AutoAdjustment;
-export AutoRef, AutoRefKind, AutoSlice, AutoPtr;
 export DerivedMethodInfo;
 export DerivedFieldInfo;
+export AutoAdjustment;
+export AutoRef;
+export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowFn;
 
 // Data types
 
@@ -304,14 +299,14 @@ impl region_variance : cmp::Eq {
 
 #[auto_serialize]
 #[auto_deserialize]
-type AutoAdjustment = {
+pub type AutoAdjustment = {
     autoderefs: uint,
     autoref: Option<AutoRef>
 };
 
 #[auto_serialize]
 #[auto_deserialize]
-type AutoRef = {
+pub type AutoRef = {
     kind: AutoRefKind,
     region: Region,
     mutbl: ast::mutability
@@ -320,11 +315,14 @@ type AutoRef = {
 #[auto_serialize]
 #[auto_deserialize]
 enum AutoRefKind {
+    /// Convert from T to &T
+    AutoPtr,
+
     /// Convert from @[]/~[] to &[] (or str)
-    AutoSlice,
+    AutoBorrowVec,
 
-    /// Convert from T to &T
-    AutoPtr
+    /// Convert from @fn()/~fn() to &fn()
+    AutoBorrowFn,
 }
 
 struct ProvidedMethodSource {
@@ -450,62 +448,6 @@ pure fn type_has_regions(t: t) -> bool { tbox_has_flag(get(t), has_regions) }
 pure fn type_def_id(t: t) -> Option<ast::def_id> { get(t).o_def_id }
 pure fn type_id(t: t) -> uint { get(t).id }
 
-enum closure_kind {
-    ck_block,
-    ck_box,
-    ck_uniq,
-}
-
-impl closure_kind : to_bytes::IterBytes {
-    pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
-        (self as u8).iter_bytes(lsb0, f)
-    }
-}
-
-impl closure_kind : cmp::Eq {
-    pure fn eq(other: &closure_kind) -> bool {
-        (self as uint) == ((*other) as uint)
-    }
-    pure fn ne(other: &closure_kind) -> bool { !self.eq(other) }
-}
-
-enum fn_proto {
-    proto_bare,             // supertype of all other protocols
-    proto_vstore(vstore)
-}
-
-impl fn_proto : to_bytes::IterBytes {
-    pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
-        match self {
-          proto_bare =>
-          0u8.iter_bytes(lsb0, f),
-
-          proto_vstore(ref v) =>
-          to_bytes::iter_bytes_2(&1u8, v, lsb0, f)
-        }
-    }
-}
-
-impl fn_proto : cmp::Eq {
-    pure fn eq(other: &fn_proto) -> bool {
-        match self {
-            proto_bare => {
-                match (*other) {
-                    proto_bare => true,
-                    _ => false
-                }
-            }
-            proto_vstore(e0a) => {
-                match (*other) {
-                    proto_vstore(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-        }
-    }
-    pure fn ne(other: &fn_proto) -> bool { !self.eq(other) }
-}
-
 /**
  * Meta information about a closure.
  *
@@ -513,12 +455,14 @@ impl fn_proto : cmp::Eq {
  * - `proto` is the protocol (fn@, fn~, etc).
  * - `onceness` indicates whether the function can be called one time or many
  *   times.
+ * - `region` is the region bound on the function's upvars (often &static).
  * - `bounds` is the parameter bounds on the function's upvars.
  * - `ret_style` indicates whether the function returns a value or fails. */
 struct FnMeta {
     purity: ast::purity,
-    proto: fn_proto,
+    proto: ast::Proto,
     onceness: ast::Onceness,
+    region: Region,
     bounds: @~[param_bound],
     ret_style: ret_style
 }
@@ -671,7 +615,7 @@ enum sty {
     // "Fake" types, used for trans purposes
     ty_type, // type_desc*
     ty_opaque_box, // used by monomorphizer to represent any @ box
-    ty_opaque_closure_ptr(closure_kind), // ptr to env for fn, fn@, fn~
+    ty_opaque_closure_ptr(ast::Proto), // ptr to env for fn, fn@, fn~
     ty_unboxed_vec(mt),
 }
 
@@ -691,7 +635,7 @@ enum type_err {
     terr_purity_mismatch(expected_found<purity>),
     terr_onceness_mismatch(expected_found<Onceness>),
     terr_mutability,
-    terr_proto_mismatch(expected_found<ty::fn_proto>),
+    terr_proto_mismatch(expected_found<ast::Proto>),
     terr_box_mutability,
     terr_ptr_mutability,
     terr_ref_mutability,
@@ -1036,10 +980,7 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option<ast::def_id>) -> t {
       ty_rec(flds) => for flds.each |f| { flags |= get(f.mt.ty).flags; },
       ty_tup(ts) => for ts.each |tt| { flags |= get(*tt).flags; },
       ty_fn(ref f) => {
-        match f.meta.proto {
-            ty::proto_vstore(vstore_slice(r)) => flags |= rflags(r),
-            ty::proto_bare | ty::proto_vstore(_) => {}
-        }
+        flags |= rflags(f.meta.region);
         for f.sig.inputs.each |a| { flags |= get(a.ty).flags; }
         flags |= get(f.sig.output).flags;
       }
@@ -1172,8 +1113,8 @@ fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
 
 fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) }
 
-fn mk_opaque_closure_ptr(cx: ctxt, ck: closure_kind) -> t {
-    mk_t(cx, ty_opaque_closure_ptr(ck))
+fn mk_opaque_closure_ptr(cx: ctxt, proto: ast::Proto) -> t {
+    mk_t(cx, ty_opaque_closure_ptr(proto))
 }
 
 fn mk_opaque_box(cx: ctxt) -> t { mk_t(cx, ty_opaque_box) }
@@ -1197,8 +1138,10 @@ fn default_arg_mode_for_ty(tcx: ctxt, ty: ty::t) -> ast::rmode {
         // memory leak that otherwise results when @fn is upcast to &fn.
     if type_is_fn(ty) {
         match ty_fn_proto(ty) {
-           proto_vstore(vstore_slice(_)) => return ast::by_ref,
-            _ => ()
+            ast::ProtoBorrowed => {
+                return ast::by_ref;
+            }
+            _ => {}
         }
     }
     return if tcx.legacy_modes {
@@ -1409,25 +1352,18 @@ fn fold_regions_and_ty(
         ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), vst)
       }
       ty_fn(ref f) => {
-        let new_proto;
-        match f.meta.proto {
-            proto_bare =>
-                new_proto = proto_bare,
-            proto_vstore(vstore_slice(r)) =>
-                new_proto = proto_vstore(vstore_slice(fldr(r))),
-            proto_vstore(old_vstore) =>
-                new_proto = proto_vstore(old_vstore)
-        }
-        let new_args = vec::map(f.sig.inputs, |a| {
-            let new_ty = fldfnt(a.ty);
-            {mode: a.mode, ty: new_ty}
-        });
-        let new_output = fldfnt(f.sig.output);
-        ty::mk_fn(cx, FnTyBase {
-            meta: FnMeta {proto: new_proto, ..f.meta},
-            sig: FnSig {inputs: new_args,
-                        output: new_output}
-        })
+          let new_region = fldr(f.meta.region);
+          let new_args = vec::map(f.sig.inputs, |a| {
+              let new_ty = fldfnt(a.ty);
+              {mode: a.mode, ty: new_ty}
+          });
+          let new_output = fldfnt(f.sig.output);
+          ty::mk_fn(cx, FnTyBase {
+              meta: FnMeta {region: new_region,
+                            ..f.meta},
+              sig: FnSig {inputs: new_args,
+                          output: new_output}
+          })
       }
       ref sty => {
         fold_sty_to_ty(cx, sty, |t| fldt(t))
@@ -1789,8 +1725,8 @@ fn type_needs_drop(cx: ctxt, ty: t) -> bool {
       }
       ty_fn(ref fty) => {
         match fty.meta.proto {
-          proto_bare | proto_vstore(vstore_slice(_)) => false,
-          _ => true
+          ast::ProtoBare | ast::ProtoBorrowed => false,
+          ast::ProtoBox | ast::ProtoUniq => true,
         }
       }
     };
@@ -2016,16 +1952,18 @@ pure fn kind_is_owned(k: Kind) -> bool {
 
 fn meta_kind(p: FnMeta) -> Kind {
     match p.proto { // XXX consider the kind bounds!
-      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()
+        ast::ProtoBare => {
+            kind_safe_for_default_mode_send() | kind_const() | kind_owned()
+        }
+        ast::ProtoBorrowed => {
+            kind_noncopyable() | kind_(KIND_MASK_DEFAULT_MODE)
+        }
+        ast::ProtoBox => {
+            kind_safe_for_default_mode() | kind_owned()
+        }
+        ast::ProtoUniq => {
+            kind_send_copy() | kind_owned()
+        }
     }
 }
 
@@ -2721,8 +2659,27 @@ impl field : to_bytes::IterBytes {
 
 impl arg : to_bytes::IterBytes {
     pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
-          to_bytes::iter_bytes_2(&self.mode,
-                                 &self.ty, lsb0, f)
+        to_bytes::iter_bytes_2(&self.mode,
+                               &self.ty, lsb0, f)
+    }
+}
+
+impl FnMeta : to_bytes::IterBytes {
+    pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
+        to_bytes::iter_bytes_5(&self.purity,
+                               &self.proto,
+                               &self.region,
+                               &self.bounds,
+                               &self.ret_style,
+                               lsb0, f);
+    }
+}
+
+impl FnSig : to_bytes::IterBytes {
+    pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
+        to_bytes::iter_bytes_2(&self.inputs,
+                               &self.output,
+                               lsb0, f);
     }
 }
 
@@ -2763,13 +2720,9 @@ impl sty : to_bytes::IterBytes {
           to_bytes::iter_bytes_2(&11u8, fs, lsb0, f),
 
           ty_fn(ref ft) =>
-          to_bytes::iter_bytes_7(&12u8,
-                                 &ft.meta.purity,
-                                 &ft.meta.proto,
-                                 &ft.meta.bounds,
-                                 &ft.sig.inputs,
-                                 &ft.sig.output,
-                                 &ft.meta.ret_style,
+          to_bytes::iter_bytes_3(&12u8,
+                                 &ft.meta,
+                                 &ft.sig,
                                  lsb0, f),
 
           ty_self => 13u8.iter_bytes(lsb0, f),
@@ -2840,7 +2793,7 @@ fn ty_fn_args(fty: t) -> ~[arg] {
     }
 }
 
-fn ty_fn_proto(fty: t) -> fn_proto {
+fn ty_fn_proto(fty: t) -> Proto {
     match get(fty).sty {
       ty_fn(ref f) => f.meta.proto,
       _ => fail ~"ty_fn_proto() called on non-fn type"
@@ -4091,12 +4044,11 @@ fn normalize_ty(cx: ctxt, t: t) -> t {
             mk_rptr(cx, re_static, normalize_mt(cx, mt)),
 
         ty_fn(ref fn_ty) => {
-            let proto = match fn_ty.meta.proto {
-                proto_bare => proto_bare,
-                proto_vstore(vstore) => proto_vstore(normalize_vstore(vstore))
-            };
             mk_fn(cx, FnTyBase {
-                meta: FnMeta {proto: proto, ..fn_ty.meta},
+                meta: FnMeta {
+                    region: ty::re_static,
+                    ..fn_ty.meta
+                },
                 sig: fn_ty.sig
             })
         }
@@ -4160,27 +4112,17 @@ fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr, span: span) -> uint {
     }
 }
 
-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"
-    }
-}
-
 // Determine what purity to check a nested function under
 pure fn determine_inherited_purity(parent_purity: ast::purity,
                                    child_purity: ast::purity,
-                                   child_proto: ty::fn_proto) -> ast::purity {
+                                   child_proto: ast::Proto) -> ast::purity {
     // If the closure is a stack closure and hasn't had some non-standard
     // purity inferred for it, then check it under its parent's purity.
     // Otherwise, use its own
-    if ty::is_blockish(child_proto) && child_purity == ast::impure_fn {
-        parent_purity
-    } else { child_purity }
+    match child_proto {
+        ast::ProtoBorrowed if child_purity == ast::impure_fn => parent_purity,
+        _ => child_purity
+    }
 }
 
 impl mt : cmp::Eq {
diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs
index b18b032e0a6..f80b655a860 100644
--- a/src/rustc/middle/typeck/astconv.rs
+++ b/src/rustc/middle/typeck/astconv.rs
@@ -166,76 +166,57 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
     // Handle @, ~, and & being able to mean estrs and evecs.
     // If a_seq_ty is a str or a vec, make it an estr/evec.
     // Also handle function sigils and first-class trait types.
-    fn mk_maybe_vstore<AC: ast_conv, RS: region_scope Copy Owned>(
-        self: AC, rscope: RS, a_seq_ty: ast::mt, vst: ty::vstore,
-        span: span, constr: fn(ty::mt) -> ty::t) -> ty::t {
-
+    fn mk_pointer<AC: ast_conv, RS: region_scope Copy Owned>(
+        self: AC,
+        rscope: RS,
+        a_seq_ty: ast::mt,
+        vst: ty::vstore,
+        constr: fn(ty::mt) -> ty::t) -> ty::t
+    {
         let tcx = self.tcx();
 
         match a_seq_ty.ty.node {
-          // to convert to an e{vec,str}, there can't be a mutability argument
-          _ if a_seq_ty.mutbl != ast::m_imm => (),
-          ast::ty_vec(mt) => {
-            return ty::mk_evec(tcx, ast_mt_to_mt(self, rscope, mt), vst);
-          }
-          ast::ty_path(path, id) => {
-            match tcx.def_map.find(id) {
-              Some(ast::def_prim_ty(ast::ty_str)) => {
-                check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-                return ty::mk_estr(tcx, vst);
-              }
-              Some(ast::def_ty(type_def_id)) => {
-                let result = ast_path_to_substs_and_ty(self, rscope,
-                                                       type_def_id, path);
-                match ty::get(result.ty).sty {
-                    ty::ty_trait(trait_def_id, substs, _) => {
-                        match vst {
-                            ty::vstore_box | ty::vstore_slice(*) |
-                            ty::vstore_uniq => {}
-                            _ => {
-                                tcx.sess.span_err(path.span,
-                                                  ~"@trait, ~trait or &trait \
-                                                    are the only supported \
-                                                    forms of casting-to-\
-                                                    trait");
+            // to convert to an e{vec,str}, there can't be a
+            // mutability argument
+            _ if a_seq_ty.mutbl != ast::m_imm => (),
+            ast::ty_vec(mt) => {
+                return ty::mk_evec(tcx, ast_mt_to_mt(self, rscope, mt), vst);
+            }
+            ast::ty_path(path, id) => {
+                match tcx.def_map.find(id) {
+                    Some(ast::def_prim_ty(ast::ty_str)) => {
+                        check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                        return ty::mk_estr(tcx, vst);
+                    }
+                    Some(ast::def_ty(type_def_id)) => {
+                        let result = ast_path_to_substs_and_ty(
+                            self, rscope,
+                            type_def_id, path);
+                        match ty::get(result.ty).sty {
+                            ty::ty_trait(trait_def_id, substs, _) => {
+                                match vst {
+                                    ty::vstore_box | ty::vstore_slice(*) |
+                                    ty::vstore_uniq => {}
+                                    _ => {
+                                        tcx.sess.span_err(
+                                            path.span,
+                                            ~"@trait, ~trait or &trait \
+                                              are the only supported \
+                                              forms of casting-to-\
+                                              trait");
+                                    }
+                                }
+                                return ty::mk_trait(tcx, trait_def_id,
+                                                    substs, vst);
+
                             }
+                            _ => {}
                         }
-                        return ty::mk_trait(tcx, trait_def_id, substs, vst);
                     }
                     _ => {}
                 }
-              }
-              _ => ()
             }
-          }
-          ast::ty_fn(ast::proto_block, purity, onceness, ast_bounds,
-                     ast_fn_decl) => {
-            let new_proto;
-            match vst {
-                ty::vstore_fixed(_) => {
-                    tcx.sess.span_err(span, ~"fixed-length functions are not \
-                                              allowed");
-                    new_proto = ast::proto_block;
-                }
-                ty::vstore_uniq => new_proto = ast::proto_uniq,
-                ty::vstore_box => new_proto = ast::proto_box,
-                ty::vstore_slice(_) => new_proto = ast::proto_block
-            }
-
-            // Run through the normal function type conversion process.
-            let bounds = collect::compute_bounds(self.ccx(), ast_bounds);
-            let fn_decl = ty_of_fn_decl(self,
-                                        rscope,
-                                        new_proto,
-                                        purity,
-                                        onceness,
-                                        bounds,
-                                        ast_fn_decl,
-                                        None,
-                                        span);
-            return ty::mk_fn(tcx, fn_decl);
-          }
-          _ => ()
+            _ => {}
         }
 
         let seq_ty = ast_mt_to_mt(self, rscope, a_seq_ty);
@@ -279,12 +260,12 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
       ast::ty_nil => ty::mk_nil(tcx),
       ast::ty_bot => ty::mk_bot(tcx),
       ast::ty_box(mt) => {
-        mk_maybe_vstore(self, rscope, mt, ty::vstore_box, ast_ty.span,
-                        |tmt| ty::mk_box(tcx, tmt))
+        mk_pointer(self, rscope, mt, ty::vstore_box,
+                   |tmt| ty::mk_box(tcx, tmt))
       }
       ast::ty_uniq(mt) => {
-        mk_maybe_vstore(self, rscope, mt, ty::vstore_uniq, ast_ty.span,
-                        |tmt| ty::mk_uniq(tcx, tmt))
+        mk_pointer(self, rscope, mt, ty::vstore_uniq,
+                   |tmt| ty::mk_uniq(tcx, tmt))
       }
       ast::ty_vec(mt) => {
         tcx.sess.span_err(ast_ty.span,
@@ -298,12 +279,8 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
       }
       ast::ty_rptr(region, mt) => {
         let r = ast_region_to_region(self, rscope, ast_ty.span, region);
-        mk_maybe_vstore(self,
-                        in_anon_rscope(rscope, r),
-                        mt,
-                        ty::vstore_slice(r),
-                        ast_ty.span,
-                        |tmt| ty::mk_rptr(tcx, r, tmt))
+        mk_pointer(self, in_anon_rscope(rscope, r), mt, ty::vstore_slice(r),
+                   |tmt| ty::mk_rptr(tcx, r, tmt))
       }
       ast::ty_tup(fields) => {
         let flds = vec::map(fields, |t| ast_ty_to_ty(self, rscope, *t));
@@ -316,10 +293,11 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
         };
         ty::mk_rec(tcx, flds)
       }
-      ast::ty_fn(proto, purity, onceness, ast_bounds, decl) => {
-        let bounds = collect::compute_bounds(self.ccx(), ast_bounds);
-        let fn_decl = ty_of_fn_decl(self, rscope, proto, purity,
-                                    onceness, bounds, decl, None,
+      ast::ty_fn(f) => {
+        let bounds = collect::compute_bounds(self.ccx(), f.bounds);
+        let fn_decl = ty_of_fn_decl(self, rscope, f.proto,
+                                    f.purity, f.onceness,
+                                    bounds, f.region, f.decl, None,
                                     ast_ty.span);
         ty::mk_fn(tcx, fn_decl)
       }
@@ -377,22 +355,9 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
           }
         }
       }
-      ast::ty_fixed_length(a_t, Some(u)) => {
-        mk_maybe_vstore(self, rscope, {ty: a_t, mutbl: ast::m_imm},
-                        ty::vstore_fixed(u),
-                        ast_ty.span,
-                        |ty| {
-                            tcx.sess.span_err(
-                                a_t.span,
-                                fmt!("bound not allowed on a %s",
-                                     ty::ty_sort_str(tcx, ty.ty)));
-                            ty.ty
-                        })
-      }
-      ast::ty_fixed_length(_, None) => {
-        tcx.sess.span_bug(
-            ast_ty.span,
-            ~"implied fixed length for bound");
+      ast::ty_fixed_length_vec(a_mt, u) => {
+        ty::mk_evec(tcx, ast_mt_to_mt(self, rscope, a_mt),
+                    ty::vstore_fixed(u))
       }
       ast::ty_infer => {
         // ty_infer should only appear as the type of arguments or return
@@ -459,38 +424,44 @@ fn ty_of_arg<AC: ast_conv, RS: region_scope Copy Owned>(
     {mode: mode, ty: ty}
 }
 
-fn ast_proto_to_proto<AC: ast_conv, RS: region_scope Copy Owned>(
-    self: AC, rscope: RS, span: span, 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 => {
-            let result = rscope.anon_region(span);
-            let region = get_region_reporting_err(self.tcx(), span, result);
-            ty::proto_vstore(ty::vstore_slice(region))
-        }
-    }
-}
-
 type expected_tys = Option<{inputs: ~[ty::arg],
                             output: ty::t}>;
 
 fn ty_of_fn_decl<AC: ast_conv, RS: region_scope Copy Owned>(
     self: AC, rscope: RS,
-    ast_proto: ast::proto,
+    ast_proto: ast::Proto,
     purity: ast::purity,
     onceness: ast::Onceness,
     bounds: @~[ty::param_bound],
+    opt_region: Option<@ast::region>,
     decl: ast::fn_decl,
     expected_tys: expected_tys,
-    span: span) -> ty::FnTy {
-
+    span: span) -> ty::FnTy
+{
     debug!("ty_of_fn_decl");
     do indent {
+        // resolve the function bound region in the original region
+        // scope `rscope`, not the scope of the function parameters
+        let bound_region = match opt_region {
+            Some(region) => {
+                ast_region_to_region(self, rscope, span, region)
+            }
+            None => {
+                match ast_proto {
+                    ast::ProtoBare | ast::ProtoUniq | ast::ProtoBox => {
+                        // @fn(), ~fn() default to static as the bound
+                        // on their upvars:
+                        ty::re_static
+                    }
+                    ast::ProtoBorrowed => {
+                        // &fn() defaults to an anonymous region:
+                        let r_result = rscope.anon_region(span);
+                        get_region_reporting_err(self.tcx(), span, r_result)
+                    }
+                }
+            }
+        };
+
         // new region names that appear inside of the fn decl are bound to
         // that function type
         let rb = in_binding_rscope(rscope);
@@ -511,12 +482,11 @@ fn ty_of_fn_decl<AC: ast_conv, RS: region_scope Copy Owned>(
           _ => ast_ty_to_ty(self, rb, decl.output)
         };
 
-        let proto = ast_proto_to_proto(self, rscope, span, ast_proto);
-
         FnTyBase {
             meta: FnMeta {purity: purity,
-                          proto: proto,
+                          proto: ast_proto,
                           onceness: onceness,
+                          region: bound_region,
                           bounds: bounds,
                           ret_style: decl.cf},
             sig: FnSig {inputs: input_tys,
@@ -524,5 +494,3 @@ fn ty_of_fn_decl<AC: ast_conv, RS: region_scope Copy Owned>(
         }
     }
 }
-
-
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index 09225b4fef8..3de99554554 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -1294,7 +1294,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
 
     fn check_expr_fn(fcx: @fn_ctxt,
                      expr: @ast::expr,
-                     ast_proto_opt: Option<ast::proto>,
+                     ast_proto_opt: Option<ast::Proto>,
                      decl: ast::fn_decl,
                      body: ast::blk,
                      is_loop_body: bool,
@@ -1313,56 +1313,39 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         let (expected_tys,
              expected_purity,
              expected_proto,
-             expected_onceness) =
+             expected_onceness) = {
             match expected_sty {
-              Some(ty::ty_fn(ref fn_ty)) => {
-                let {fn_ty, _} =
-                    replace_bound_regions_in_fn_ty(
-                        tcx, @Nil, None, fn_ty,
-                        |br| ty::re_bound(ty::br_cap_avoid(expr.id, @br)));
-                (Some({inputs: fn_ty.sig.inputs,
-                       output: fn_ty.sig.output}),
-                 fn_ty.meta.purity,
-                 fn_ty.meta.proto,
-                 fn_ty.meta.onceness)
-              }
-              _ => {
-                (None,
-                 ast::impure_fn,
-                 ty::proto_vstore(ty::vstore_box),
-                 ast::Many)
-              }
-            };
-
+                Some(ty::ty_fn(ref fn_ty)) => {
+                    let id = expr.id;
+                    let {fn_ty, _} =
+                        replace_bound_regions_in_fn_ty(
+                            tcx, @Nil, None, fn_ty,
+                            |br| ty::re_bound(ty::br_cap_avoid(id, @br)));
+                    (Some({inputs: fn_ty.sig.inputs,
+                           output: fn_ty.sig.output}),
+                     fn_ty.meta.purity,
+                     fn_ty.meta.proto,
+                     fn_ty.meta.onceness)
+                }
+                _ => {
+                    (None, ast::impure_fn, ast::ProtoBox, ast::Many)
+                }
+            }
+        };
 
-        // Generate AST prototypes and purity.
-        // If this is a block lambda (ast_proto == none), these values
-        // are bogus. We'll fill in the type with the real one later.
-        // XXX: This is a hack.
-        let ast_proto = ast_proto_opt.get_default(ast::proto_box);
-        let ast_purity = ast::impure_fn;
-        let ast_onceness = ast::Many;
+        // If the proto is specified, use that, otherwise select a
+        // proto based on inference.
+        let (proto, purity) = match ast_proto_opt {
+            Some(p) => (p, ast::impure_fn),
+            None => (expected_proto, expected_purity)
+        };
 
         // construct the function type
-        let mut fn_ty = astconv::ty_of_fn_decl(fcx,
-                                               fcx,
-                                               ast_proto,
-                                               ast_purity,
-                                               ast_onceness,
-                                               @~[],
-                                               decl,
-                                               expected_tys,
-                                               expr.span);
-
-        // Patch up the function declaration, if necessary.
-        match ast_proto_opt {
-          None => {
-            fn_ty.meta.purity = expected_purity;
-            fn_ty.meta.proto = expected_proto;
-            fn_ty.meta.onceness = expected_onceness;
-          }
-          Some(_) => { }
-        }
+        let mut fn_ty = astconv::ty_of_fn_decl(
+            fcx, fcx,
+            proto, purity, expected_onceness,
+            /*bounds:*/ @~[], /*opt_region:*/ None,
+            decl, expected_tys, expr.span);
 
         let fty = ty::mk_fn(tcx, fn_ty);
 
@@ -2815,9 +2798,9 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
       ~"frame_address" => {
         let fty = ty::mk_fn(ccx.tcx, FnTyBase {
             meta: FnMeta {purity: ast::impure_fn,
-                          proto: ty::proto_vstore(ty::vstore_slice(
-                              ty::re_bound(ty::br_anon(0)))),
-                          onceness: ast::Many,
+                          proto: ast::ProtoBorrowed,
+                          onceness: ast::Once,
+                          region: ty::re_bound(ty::br_anon(0)),
                           bounds: @~[],
                           ret_style: ast::return_val},
             sig: FnSig {inputs: ~[{mode: ast::expl(ast::by_val),
@@ -2840,8 +2823,9 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
     };
     let fty = ty::mk_fn(tcx, FnTyBase {
         meta: FnMeta {purity: ast::impure_fn,
-                      proto: ty::proto_bare,
+                      proto: ast::ProtoBare,
                       onceness: ast::Many,
+                      region: ty::re_static,
                       bounds: @~[],
                       ret_style: ast::return_val},
         sig: FnSig {inputs: inputs,
diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs
index f1185181f55..dd3f4069a9c 100644
--- a/src/rustc/middle/typeck/check/method.rs
+++ b/src/rustc/middle/typeck/check/method.rs
@@ -625,7 +625,7 @@ impl LookupContext {
             ty_evec(mt, vstore_uniq) |
             ty_evec(mt, vstore_fixed(_)) => {
                 self.search_for_some_kind_of_autorefd_method(
-                    AutoSlice, autoderefs, [m_const, m_imm, m_mutbl],
+                    AutoBorrowVec, autoderefs, [m_const, m_imm, m_mutbl],
                     |m,r| ty::mk_evec(tcx,
                                       {ty:mt.ty, mutbl:m},
                                       vstore_slice(r)))
@@ -635,7 +635,7 @@ impl LookupContext {
             ty_estr(vstore_uniq) |
             ty_estr(vstore_fixed(_)) => {
                 self.search_for_some_kind_of_autorefd_method(
-                    AutoSlice, autoderefs, [m_imm],
+                    AutoBorrowVec, autoderefs, [m_imm],
                     |_m,r| ty::mk_estr(tcx, vstore_slice(r)))
             }
 
diff --git a/src/rustc/middle/typeck/check/regionck.rs b/src/rustc/middle/typeck/check/regionck.rs
index a38b805c7b4..970e86d00de 100644
--- a/src/rustc/middle/typeck/check/regionck.rs
+++ b/src/rustc/middle/typeck/check/regionck.rs
@@ -22,10 +22,11 @@ use ppaux::{note_and_explain_region, ty_to_str};
 use syntax::print::pprust;
 use infer::{resolve_and_force_all_but_regions, fres};
 use syntax::ast::{def_arg, def_binding, def_local, def_self, def_upvar};
+use syntax::ast::{ProtoBare, ProtoBox, ProtoUniq, ProtoBorrowed};
 use middle::freevars::get_freevars;
 use middle::kind::check_owned;
 use middle::pat_util::pat_bindings;
-use middle::ty::{encl_region, proto_bare, proto_vstore, re_scope};
+use middle::ty::{encl_region, re_scope};
 use middle::ty::{ty_fn_proto, vstore_box, vstore_fixed, vstore_slice};
 use middle::ty::{vstore_uniq};
 
@@ -40,14 +41,9 @@ fn encl_region_of_def(fcx: @fn_ctxt, def: ast::def) -> ty::Region {
             return encl_region(tcx, node_id),
         def_upvar(_, subdef, closure_id, body_id) => {
             match ty_fn_proto(fcx.node_ty(closure_id)) {
-                proto_bare =>
-                    tcx.sess.bug(~"proto_bare in encl_region_of_def?!"),
-                proto_vstore(vstore_fixed(_)) =>
-                    tcx.sess.bug(~"vstore_fixed in encl_region_of_def?!"),
-                proto_vstore(vstore_slice(_)) =>
-                    encl_region_of_def(fcx, *subdef),
-                proto_vstore(vstore_uniq) | proto_vstore(vstore_box) =>
-                    re_scope(body_id)
+                ProtoBare => tcx.sess.bug(~"ProtoBare with upvars?!"),
+                ProtoBorrowed => encl_region_of_def(fcx, *subdef),
+                ProtoBox | ProtoUniq => re_scope(body_id)
             }
         }
         _ => {
@@ -244,12 +240,9 @@ fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) {
                 result::Ok(function_type) => {
                     match ty::get(function_type).sty {
                         ty::ty_fn(ref fn_ty) => {
-                            match fn_ty.meta.proto {
-                                proto_vstore(vstore_slice(region)) => {
-                                    constrain_free_variables(rcx, region,
-                                                             expr);
-                                }
-                                _ => {}
+                            if fn_ty.meta.proto == ast::ProtoBorrowed {
+                                constrain_free_variables(
+                                    rcx, fn_ty.meta.region, expr);
                             }
                         }
                         _ => ()
diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs
index 04f7aae0bf2..ebc26d4b4df 100644
--- a/src/rustc/middle/typeck/collect.rs
+++ b/src/rustc/middle/typeck/collect.rs
@@ -133,9 +133,10 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
                 });
                 result_ty = Some(ty::mk_fn(tcx, FnTyBase {
                     meta: FnMeta {purity: ast::pure_fn,
-                                  proto: ty::proto_vstore(ty::vstore_box),
+                                  proto: ast::ProtoBare,
                                   onceness: ast::Many,
                                   bounds: @~[],
+                                  region: ty::re_static,
                                   ret_style: ast::return_val},
                     sig: FnSig {inputs: args,
                                 output: enum_ty}
@@ -604,9 +605,11 @@ fn convert_struct(ccx: @crate_ctxt,
         // Write the dtor type
         let t_dtor = ty::mk_fn(
             tcx,
-            ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
-                          ast::impure_fn, ast::Many, @~[],
-                          ast_util::dtor_dec(), None, dtor.span));
+            ty_of_fn_decl(
+                ccx, type_rscope(rp), ast::ProtoBare,
+                ast::impure_fn, ast::Many,
+                /*bounds:*/ @~[], /*opt_region:*/ None,
+                ast_util::dtor_dec(), None, dtor.span));
         write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
         tcx.tcache.insert(local_def(dtor.node.id),
                           {bounds: tpt.bounds,
@@ -643,9 +646,10 @@ fn convert_struct(ccx: @crate_ctxt,
                 let ctor_fn_ty = ty::mk_fn(tcx, FnTyBase {
                     meta: FnMeta {
                         purity: ast::pure_fn,
-                        proto: ty::proto_bare,
+                        proto: ast::ProtoBare,
                         onceness: ast::Many,
                         bounds: @~[],
+                        region: ty::re_static,
                         ret_style: ast::return_val,
                     },
                     sig: FnSig {
@@ -684,15 +688,10 @@ fn ty_of_method(ccx: @crate_ctxt,
                 rp: Option<ty::region_variance>) -> ty::method {
     {ident: m.ident,
      tps: ty_param_bounds(ccx, m.tps),
-     fty: ty_of_fn_decl(ccx,
-                        type_rscope(rp),
-                        ast::proto_bare,
-                        m.purity,
-                        ast::Many,
-                        @~[],
-                        m.decl,
-                        None,
-                        m.span),
+     fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::ProtoBare,
+                        m.purity, ast::Many,
+                        /*bounds:*/ @~[], /*opt_region:*/ None,
+                        m.decl, None, m.span),
      self_ty: m.self_ty.node,
      vis: m.vis,
      def_id: local_def(m.id)}
@@ -704,15 +703,10 @@ fn ty_of_ty_method(self: @crate_ctxt,
                    id: ast::def_id) -> ty::method {
     {ident: m.ident,
      tps: ty_param_bounds(self, m.tps),
-     fty: ty_of_fn_decl(self,
-                        type_rscope(rp),
-                        ast::proto_bare,
-                        m.purity,
-                        ast::Many,
-                        @~[],
-                        m.decl,
-                        None,
-                        m.span),
+     fty: ty_of_fn_decl(self, type_rscope(rp), ast::ProtoBare,
+                        m.purity, ast::Many,
+                        /*bounds:*/ @~[], /*opt_region:*/ None,
+                        m.decl, None, m.span),
      // assume public, because this is only invoked on trait methods
      self_ty: m.self_ty.node,
      vis: ast::public,
@@ -767,15 +761,10 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
       }
       ast::item_fn(decl, purity, tps, _) => {
         let bounds = ty_param_bounds(ccx, tps);
-        let tofd = ty_of_fn_decl(ccx,
-                                 empty_rscope,
-                                 ast::proto_bare,
-                                 purity,
-                                 ast::Many,
-                                 @~[],
-                                 decl,
-                                 None,
-                                 it.span);
+        let tofd = ty_of_fn_decl(ccx, empty_rscope,
+                                 ast::ProtoBare, purity, ast::Many,
+                                 /*bounds:*/ @~[], /*opt_region:*/ None,
+                                 decl, None, it.span);
         let tpt = {bounds: bounds,
                    region_param: None,
                    ty: ty::mk_fn(ccx.tcx, tofd)};
@@ -930,9 +919,10 @@ fn ty_of_foreign_fn_decl(ccx: @crate_ctxt,
 
     let t_fn = ty::mk_fn(ccx.tcx, FnTyBase {
         meta: FnMeta {purity: purity,
-                      proto: ty::proto_bare,
                       onceness: ast::Many,
+                      proto: ast::ProtoBare,
                       bounds: @~[],
+                      region: ty::re_static,
                       ret_style: ast::return_val},
         sig: FnSig {inputs: input_tys,
                     output: output_ty}
diff --git a/src/rustc/middle/typeck/infer/assignment.rs b/src/rustc/middle/typeck/infer/assignment.rs
index a5af58904dd..e5be4c7a19d 100644
--- a/src/rustc/middle/typeck/infer/assignment.rs
+++ b/src/rustc/middle/typeck/infer/assignment.rs
@@ -126,6 +126,14 @@ priv impl Assign {
             }
         }
 
+        fn borrowable_protos(a_p: ast::Proto, b_p: ast::Proto) -> bool {
+            match (a_p, b_p) {
+                (ast::ProtoBox, ast::ProtoBorrowed) => true,
+                (ast::ProtoUniq, ast::ProtoBorrowed) => true,
+                _ => false
+            }
+        }
+
         match (a_bnd, b_bnd) {
             (Some(a_bnd), Some(b_bnd)) => {
                 // check for a case where a non-region pointer (@, ~) is
@@ -149,7 +157,7 @@ priv impl Assign {
                      ty::ty_estr(ty::vstore_slice(r_b)))
                     if is_borrowable(vs_a) => {
                         let nr_b = ty::mk_estr(self.infcx.tcx, vs_a);
-                        self.try_assign(0, ty::AutoSlice,
+                        self.try_assign(0, ty::AutoBorrowVec,
                                         a, nr_b,
                                         m_imm, r_b)
                     }
@@ -160,11 +168,22 @@ priv impl Assign {
                         let nr_b = ty::mk_evec(self.infcx.tcx,
                                                {ty: mt_b.ty, mutbl: m_const},
                                                vs_a);
-                        self.try_assign(0, ty::AutoSlice,
+                        self.try_assign(0, ty::AutoBorrowVec,
                                         a, nr_b,
                                         mt_b.mutbl, r_b)
                     }
 
+                    (ty::ty_fn(ref a_f), ty::ty_fn(ref b_f))
+                    if borrowable_protos(a_f.meta.proto, b_f.meta.proto) => {
+                        let nr_b = ty::mk_fn(self.infcx.tcx, ty::FnTyBase {
+                            meta: ty::FnMeta {proto: a_f.meta.proto,
+                                              ..b_f.meta},
+                            sig: b_f.sig
+                        });
+                        self.try_assign(0, ty::AutoBorrowFn,
+                                        a, nr_b, m_imm, b_f.meta.region)
+                    }
+
                     _ => {
                         // otherwise, assignment follows normal subtype rules:
                         to_ares(Sub(*self).tys(a, b))
diff --git a/src/rustc/middle/typeck/infer/combine.rs b/src/rustc/middle/typeck/infer/combine.rs
index 87f313f68bd..c43f1e9c386 100644
--- a/src/rustc/middle/typeck/infer/combine.rs
+++ b/src/rustc/middle/typeck/infer/combine.rs
@@ -48,6 +48,8 @@ use to_str::ToStr;
 use ty::{FnTyBase, FnMeta, FnSig};
 use syntax::ast::Onceness;
 
+fn macros() { include!("macros.rs"); } // FIXME(#3114): Macro import/export.
+
 trait combine {
     fn infcx() -> infer_ctxt;
     fn tag() -> ~str;
@@ -70,7 +72,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: ty::fn_proto, p2: ty::fn_proto) -> cres<ty::fn_proto>;
+    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto>;
     fn ret_styles(r1: ret_style, r2: ret_style) -> cres<ret_style>;
     fn purities(a: purity, b: purity) -> cres<purity>;
     fn oncenesses(a: Onceness, b: Onceness) -> cres<Onceness>;
@@ -310,20 +312,17 @@ fn super_vstores<C:combine>(
 fn super_fn_metas<C:combine>(
     self: &C, a_f: &ty::FnMeta, b_f: &ty::FnMeta) -> cres<ty::FnMeta>
 {
-    do self.protos(a_f.proto, b_f.proto).chain |p| {
-        do self.ret_styles(a_f.ret_style, b_f.ret_style).chain |rs| {
-            do self.purities(a_f.purity, b_f.purity).chain |purity| {
-                do self.oncenesses(a_f.onceness, b_f.onceness).chain
-                        |onceness| {
-                    Ok(FnMeta {purity: purity,
-                               proto: p,
-                               onceness: onceness,
-                               bounds: a_f.bounds, // XXX: This is wrong!
-                               ret_style: rs})
-                }
-            }
-        }
-    }
+    let p = if_ok!(self.protos(a_f.proto, b_f.proto));
+    let r = if_ok!(self.contraregions(a_f.region, b_f.region));
+    let rs = if_ok!(self.ret_styles(a_f.ret_style, b_f.ret_style));
+    let purity = if_ok!(self.purities(a_f.purity, b_f.purity));
+    let onceness = if_ok!(self.oncenesses(a_f.onceness, b_f.onceness));
+    Ok(FnMeta {purity: purity,
+               proto: p,
+               region: r,
+               onceness: onceness,
+               bounds: a_f.bounds, // XXX: This is wrong!
+               ret_style: rs})
 }
 
 fn super_fn_sigs<C:combine>(
diff --git a/src/rustc/middle/typeck/infer/glb.rs b/src/rustc/middle/typeck/infer/glb.rs
index 0e81d97426f..fb4bd1af199 100644
--- a/src/rustc/middle/typeck/infer/glb.rs
+++ b/src/rustc/middle/typeck/infer/glb.rs
@@ -71,22 +71,8 @@ impl Glb: combine {
         Lub(*self).tys(a, b)
     }
 
-    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)
-        }
+    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
+        if p1 == p2 {Ok(p1)} else {Ok(ast::ProtoBare)}
     }
 
     fn purities(a: purity, b: purity) -> cres<purity> {
diff --git a/src/rustc/middle/typeck/infer/lub.rs b/src/rustc/middle/typeck/infer/lub.rs
index 285b05736c6..a323ae720b2 100644
--- a/src/rustc/middle/typeck/infer/lub.rs
+++ b/src/rustc/middle/typeck/infer/lub.rs
@@ -54,21 +54,12 @@ impl Lub: combine {
         Glb(*self).tys(a, b)
     }
 
-    // XXX: Wrong.
-    fn protos(p1: ty::fn_proto, p2: ty::fn_proto) -> cres<ty::fn_proto> {
+    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::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)))
-                })
-            }
+            (ast::ProtoBare, _) => Ok(p2),
+            (_, ast::ProtoBare) => Ok(p1),
+            _ if p1 == p2 => Ok(p1),
+            _ => Err(ty::terr_proto_mismatch(expected_found(&self, p1, p2)))
         }
     }
 
diff --git a/src/rustc/middle/typeck/infer/sub.rs b/src/rustc/middle/typeck/infer/sub.rs
index 9e27235b30d..80f9eb85aab 100644
--- a/src/rustc/middle/typeck/infer/sub.rs
+++ b/src/rustc/middle/typeck/infer/sub.rs
@@ -63,27 +63,11 @@ impl Sub: combine {
         }
     }
 
-    fn protos(a: ty::fn_proto, b: ty::fn_proto) -> cres<ty::fn_proto> {
-        match (a, b) {
-            (ty::proto_bare, _) =>
-                Ok(ty::proto_bare),
-
-            (ty::proto_vstore(ty::vstore_box),
-             ty::proto_vstore(ty::vstore_slice(_))) =>
-                Ok(ty::proto_vstore(ty::vstore_box)),
-
-            (ty::proto_vstore(ty::vstore_uniq),
-             ty::proto_vstore(ty::vstore_slice(_))) =>
-                Ok(ty::proto_vstore(ty::vstore_uniq)),
-
-            (_, ty::proto_bare) =>
-                Err(ty::terr_proto_mismatch(expected_found(&self, a, b))),
-
-            (ty::proto_vstore(vs_a), ty::proto_vstore(vs_b)) => {
-                do self.vstores(ty::terr_fn, vs_a, vs_b).chain |vs_c| {
-                    Ok(ty::proto_vstore(vs_c))
-                }
-            }
+    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
+        match (p1, p2) {
+            (ast::ProtoBare, _) => Ok(p1),
+            _ if p1 == p2 => Ok(p1),
+            _ => Err(ty::terr_proto_mismatch(expected_found(&self, p1, p2)))
         }
     }
 
diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs
index c7062baaea5..a9b67a7ff29 100644
--- a/src/rustc/util/ppaux.rs
+++ b/src/rustc/util/ppaux.rs
@@ -4,7 +4,7 @@ use middle::ty::{arg, canon_mode};
 use middle::ty::{bound_copy, bound_const, bound_owned, bound_send,
         bound_trait};
 use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid};
-use middle::ty::{ck_block, ck_box, ck_uniq, ctxt, field, method};
+use middle::ty::{ctxt, field, method};
 use middle::ty::{mt, t, param_bound};
 use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region};
 use middle::ty::{ReSkolemized, ReVar};
@@ -111,22 +111,19 @@ fn explain_region_and_span(cx: ctxt, region: ty::Region)
 }
 
 fn bound_region_to_str(cx: ctxt, br: bound_region) -> ~str {
-    match br {
-      br_named(id)                   => fmt!("&%s", cx.sess.str_of(id)),
-      br_self if cx.sess.verbose() => ~"&<self>",
-      br_self                        => ~"&self",
+    bound_region_to_str_adorned(cx, ~"&", br, ~"")
+}
 
-      br_anon(idx) => {
-        if cx.sess.verbose() {fmt!("&%u", idx)} else {~"&"}
-      }
+fn bound_region_to_str_adorned(cx: ctxt, prefix: ~str,
+                               br: bound_region, sep: ~str) -> ~str {
+    if cx.sess.verbose() { return fmt!("%s%?%s", prefix, br, sep); }
 
-      br_cap_avoid(id, br) => {
-        if cx.sess.verbose() {
-            fmt!("br_cap_avoid(%?, %s)", id, bound_region_to_str(cx, *br))
-        } else {
-            bound_region_to_str(cx, *br)
-        }
-      }
+    match br {
+      br_named(id)         => fmt!("%s%s%s", prefix, cx.sess.str_of(id), sep),
+      br_self              => fmt!("%sself%s", prefix, sep),
+      br_anon(_)           => prefix,
+      br_cap_avoid(_, br)  => bound_region_to_str_adorned(cx, prefix,
+                                                          *br, sep)
     }
 }
 
@@ -174,8 +171,13 @@ fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str {
 // you should use `explain_region()` or, better yet,
 // `note_and_explain_region()`
 fn region_to_str(cx: ctxt, region: Region) -> ~str {
+    region_to_str_adorned(cx, ~"&", region, ~"")
+}
+
+fn region_to_str_adorned(cx: ctxt, prefix: ~str,
+                         region: Region, sep: ~str) -> ~str {
     if cx.sess.verbose() {
-        return fmt!("&%?", region);
+        return fmt!("%s%?%s", prefix, region, sep);
     }
 
     // These printouts are concise.  They do not contain all the information
@@ -183,12 +185,14 @@ fn region_to_str(cx: ctxt, region: Region) -> ~str {
     // to fit that into a short string.  Hence the recommendation to use
     // `explain_region()` or `note_and_explain_region()`.
     match region {
-      re_scope(_) => ~"&",
-      re_bound(br) => bound_region_to_str(cx, br),
-      re_free(_, br) => bound_region_to_str(cx, br),
-      re_infer(ReSkolemized(_, br)) => bound_region_to_str(cx, br),
-      re_infer(ReVar(_)) => ~"&",
-      re_static => ~"&static"
+        re_scope(_) => prefix,
+        re_bound(br) => bound_region_to_str_adorned(cx, prefix, br, sep),
+        re_free(_, br) => bound_region_to_str_adorned(cx, prefix, br, sep),
+        re_infer(ReSkolemized(_, br)) => {
+            bound_region_to_str_adorned(cx, prefix, br, sep)
+        }
+        re_infer(ReVar(_)) => prefix,
+        re_static => fmt!("%sstatic%s", prefix, sep)
     }
 }
 
@@ -222,10 +226,12 @@ 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 {
+fn proto_ty_to_str(_cx: ctxt, proto: ast::Proto) -> ~str {
     match proto {
-      ty::proto_bare => ~"",
-      ty::proto_vstore(vstore) => vstore_to_str(cx, vstore)
+        ast::ProtoBare => ~"",
+        ast::ProtoBox => ~"@",
+        ast::ProtoBorrowed => ~"&",
+        ast::ProtoUniq => ~"~",
     }
 }
 
@@ -268,8 +274,9 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
         modestr + ty_to_str(cx, ty)
     }
     fn fn_to_str(cx: ctxt,
+                 proto: ast::Proto,
+                 region: ty::Region,
                  purity: ast::purity,
-                 proto: ty::fn_proto,
                  onceness: ast::Onceness,
                  ident: Option<ast::ident>,
                  inputs: ~[arg],
@@ -287,9 +294,21 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
             ast::Once => onceness_to_str(onceness) + ~" "
         };
 
+        s += proto_ty_to_str(cx, proto);
+
+        match (proto, region) {
+            (ast::ProtoBox, ty::re_static) |
+            (ast::ProtoUniq, ty::re_static) |
+            (ast::ProtoBare, ty::re_static) => {
+            }
+
+            (_, region) => {
+                s += region_to_str_adorned(cx, ~"", region, ~"/");
+            }
+        }
+
         s += ~"fn";
 
-        s += proto_ty_to_str(cx, proto);
         match ident {
           Some(i) => { s += ~" "; s += cx.sess.str_of(i); }
           _ => { }
@@ -310,8 +329,9 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
     fn method_to_str(cx: ctxt, m: method) -> ~str {
         return fn_to_str(
             cx,
-            m.fty.meta.purity,
             m.fty.meta.proto,
+            m.fty.meta.region,
+            m.fty.meta.purity,
             m.fty.meta.onceness,
             Some(m.ident),
             m.fty.sig.inputs,
@@ -345,12 +365,7 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
       ty_uniq(tm) => ~"~" + mt_to_str(cx, tm),
       ty_ptr(tm) => ~"*" + mt_to_str(cx, tm),
       ty_rptr(r, tm) => {
-        let rs = region_to_str(cx, r);
-        if rs == ~"&" {
-            rs + mt_to_str(cx, tm)
-        } else {
-            rs + ~"/" + mt_to_str(cx, tm)
-        }
+        region_to_str_adorned(cx, ~"&", r, ~"/") + mt_to_str(cx, tm)
       }
       ty_unboxed_vec(tm) => { ~"unboxed_vec<" + mt_to_str(cx, tm) + ~">" }
       ty_type => ~"type",
@@ -364,8 +379,9 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
       }
       ty_fn(ref f) => {
         fn_to_str(cx,
-                  f.meta.purity,
                   f.meta.proto,
+                  f.meta.region,
+                  f.meta.purity,
                   f.meta.onceness,
                   None,
                   f.sig.inputs,
@@ -393,9 +409,10 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
       }
       ty_estr(vs) => vstore_ty_to_str(cx, ~"str", vs),
       ty_opaque_box => ~"@?",
-      ty_opaque_closure_ptr(ck_block) => ~"closure&",
-      ty_opaque_closure_ptr(ck_box) => ~"closure@",
-      ty_opaque_closure_ptr(ck_uniq) => ~"closure~"
+      ty_opaque_closure_ptr(ast::ProtoBorrowed) => ~"closure&",
+      ty_opaque_closure_ptr(ast::ProtoBox) => ~"closure@",
+      ty_opaque_closure_ptr(ast::ProtoUniq) => ~"closure~",
+      ty_opaque_closure_ptr(ast::ProtoBare) => ~"closure"
     }
 }
 
diff --git a/src/test/compile-fail/block-coerce-no.rs b/src/test/compile-fail/block-coerce-no.rs
index f4445685665..94375d4ffcb 100644
--- a/src/test/compile-fail/block-coerce-no.rs
+++ b/src/test/compile-fail/block-coerce-no.rs
@@ -2,11 +2,11 @@
 // other tycons.
 
 fn coerce(b: fn()) -> extern fn() {
-    fn lol(f: extern fn(fn()) -> extern fn(),
-           g: fn()) -> extern fn() { return f(g); }
-    fn fn_id(f: extern fn()) -> extern fn() { return f }
+    fn lol(+f: extern fn(+v: fn()) -> extern fn(),
+           +g: fn()) -> extern fn() { return f(g); }
+    fn fn_id(+f: extern fn()) -> extern fn() { return f }
     return lol(fn_id, b);
-    //~^ ERROR mismatched types: expected `fn(fn&()) -> fn()`
+    //~^ ERROR mismatched types
 }
 
 fn main() {
diff --git a/src/test/compile-fail/extern-wrong-value-type.rs b/src/test/compile-fail/extern-wrong-value-type.rs
index dccd1279871..c9bcfc41119 100644
--- a/src/test/compile-fail/extern-wrong-value-type.rs
+++ b/src/test/compile-fail/extern-wrong-value-type.rs
@@ -1,8 +1,7 @@
-// error-pattern:expected `fn&()` but found `*u8`
 extern fn f() {
 }
 
 fn main() {
     // extern functions are *u8 types
-    let _x: fn() = f;
+    let _x: fn() = f; //~ ERROR mismatched types: expected `&fn()` but found `*u8`
 }
diff --git a/src/test/run-pass/issue-1896-1.rs b/src/test/compile-fail/issue-1896-1.rs
index bee92bc9c9a..d95611cbeb7 100644
--- a/src/test/run-pass/issue-1896-1.rs
+++ b/src/test/compile-fail/issue-1896-1.rs
@@ -1,7 +1,7 @@
 type boxedFn = { theFn: fn () -> uint };
 
 fn createClosure (closedUint: uint) -> boxedFn {
-    { theFn: fn@ () -> uint { closedUint } }
+    { theFn: fn@ () -> uint { closedUint } } //~ ERROR mismatched types
 }
 
 fn main () {
diff --git a/src/test/run-pass/issue-1896-2.rs b/src/test/compile-fail/issue-1896-2.rs
index 671d80a1227..af245dbeae8 100644
--- a/src/test/run-pass/issue-1896-2.rs
+++ b/src/test/compile-fail/issue-1896-2.rs
@@ -5,6 +5,6 @@ fn add(n: int) -> fn@(int) -> int {
 fn main()
 {
       assert add(3)(4) == 7;
-        let add3 : fn(int)->int = add(3);
-          assert add3(4) == 7;
+      let add3 : fn(int)->int = add(3); //~ ERROR mismatched types
+      assert add3(4) == 7;
 }
\ No newline at end of file
diff --git a/src/test/run-pass/issue-1896-3.rs b/src/test/compile-fail/issue-1896-3.rs
index 7cc254d7c19..05aea8f0fca 100644
--- a/src/test/run-pass/issue-1896-3.rs
+++ b/src/test/compile-fail/issue-1896-3.rs
@@ -12,6 +12,6 @@ fn main()
     let add2 : &(fn@(int)->int) = &add(2);
     assert (*add2)(5) == 7;
 
-    let add3 : fn(int)->int = add(3);
+    let add3 : fn(int)->int = add(3); //~ ERROR mismatched types
     assert add3(4) == 7;
 }
diff --git a/src/test/compile-fail/issue-1896.rs b/src/test/compile-fail/issue-1896.rs
index 91b2ec490df..cd00b0088a7 100644
--- a/src/test/compile-fail/issue-1896.rs
+++ b/src/test/compile-fail/issue-1896.rs
@@ -3,6 +3,7 @@ type t<T> = { f: fn() -> T };
 fn f<T>(_x: t<T>) {}
 
 fn main() {
-    let x: t<()> = { f: { || () } };
-    f(x); //~ ERROR copying a noncopyable value
+    let x: t<()> = { f: { || () } }; //~ ERROR expected & closure, found @ closure
+    //~^ ERROR in field `f`, expected & closure, found @ closure
+    f(x);
 }
\ No newline at end of file
diff --git a/src/test/compile-fail/missing-do.rs b/src/test/compile-fail/missing-do.rs
index c9fe0faab8a..1726a527d14 100644
--- a/src/test/compile-fail/missing-do.rs
+++ b/src/test/compile-fail/missing-do.rs
@@ -4,6 +4,6 @@ fn foo(f: fn()) { f() }
 
 fn main() {
     ~"" || 42; //~ ERROR binary operation || cannot be applied to type `~str`
-    foo || {}; //~ ERROR binary operation || cannot be applied to type `fn(fn&())`
+    foo || {}; //~ ERROR binary operation || cannot be applied to type `fn(&fn())`
     //~^ NOTE did you forget the 'do' keyword for the call?
 }
diff --git a/src/test/compile-fail/obsolete-syntax.rs b/src/test/compile-fail/obsolete-syntax.rs
index 4be54708428..96fb676e425 100644
--- a/src/test/compile-fail/obsolete-syntax.rs
+++ b/src/test/compile-fail/obsolete-syntax.rs
@@ -56,22 +56,11 @@ fn obsolete_with() {
     //~^ ERROR obsolete syntax: with
 }
 
-fn obsolete_fixed_length_vec() {
-    let foo: [int]/1;
-    //~^ ERROR obsolete syntax: fixed-length vector
-    foo = [1]/_;
-    //~^ ERROR obsolete syntax: fixed-length vector
-    let foo: [int]/1;
-    //~^ ERROR obsolete syntax: fixed-length vector
-    foo = [1]/1;
-    //~^ ERROR obsolete syntax: fixed-length vector
-}
-
 fn obsolete_moves() {
     let mut x = 0;
     let y <- x;
     //~^ ERROR obsolete syntax: initializer-by-move
-    y <- x; 
+    y <- x;
     //~^ ERROR obsolete syntax: binary move
 }
 
diff --git a/src/test/compile-fail/pure-subtyping.rs b/src/test/compile-fail/pure-subtyping.rs
index c6f3568087c..efc4a720ab1 100644
--- a/src/test/compile-fail/pure-subtyping.rs
+++ b/src/test/compile-fail/pure-subtyping.rs
@@ -1,35 +1,37 @@
 // Test rules governing higher-order pure fns.
 
+fn take<T>(_v: T) {}
+
 fn assign_to_pure(x: pure fn(), y: fn(), z: unsafe fn()) {
-    let a: pure fn() = x;
-    let b: pure fn() = y; //~ ERROR expected pure fn but found impure fn
-    let c: pure fn() = z; //~ ERROR expected pure fn but found unsafe fn
+    take::<pure fn()>(x);
+    take::<pure fn()>(y); //~ ERROR expected pure fn but found impure fn
+    take::<pure fn()>(z); //~ ERROR expected pure fn but found unsafe fn
 }
 
 fn assign_to_impure(x: pure fn(), y: fn(), z: unsafe fn()) {
-    let h: fn() = x;
-    let i: fn() = y;
-    let j: fn() = z; //~ ERROR expected impure fn but found unsafe fn
+    take::<fn()>(x);
+    take::<fn()>(y);
+    take::<fn()>(z); //~ ERROR expected impure fn but found unsafe fn
 }
 
 fn assign_to_unsafe(x: pure fn(), y: fn(), z: unsafe fn()) {
-    let m: unsafe fn() = x;
-    let n: unsafe fn() = y;
-    let o: unsafe fn() = z;
+    take::<unsafe fn()>(x);
+    take::<unsafe fn()>(y);
+    take::<unsafe fn()>(z);
 }
 
 fn assign_to_pure2(x: pure fn@(), y: fn@(), z: unsafe fn@()) {
-    let a: pure fn() = x;
-    let b: pure fn() = y; //~ ERROR expected pure fn but found impure fn
-    let c: pure fn() = z; //~ ERROR expected pure fn but found unsafe fn
+    take::<pure fn()>(x);
+    take::<pure fn()>(y); //~ ERROR expected pure fn but found impure fn
+    take::<pure fn()>(z); //~ ERROR expected pure fn but found unsafe fn
 
-    let a: pure fn~() = x; //~ ERROR fn storage differs: expected ~ but found @
-    let b: pure fn~() = y; //~ ERROR fn storage differs: expected ~ but found @
-    let c: pure fn~() = z; //~ ERROR fn storage differs: expected ~ but found @
+    take::<pure fn~()>(x); //~ ERROR expected ~ closure, found @ closure
+    take::<pure fn~()>(y); //~ ERROR expected ~ closure, found @ closure
+    take::<pure fn~()>(z); //~ ERROR expected ~ closure, found @ closure
 
-    let a: unsafe fn~() = x; //~ ERROR fn storage differs: expected ~ but found @
-    let b: unsafe fn~() = y; //~ ERROR fn storage differs: expected ~ but found @
-    let c: unsafe fn~() = z; //~ ERROR fn storage differs: expected ~ but found @
+    take::<unsafe fn~()>(x); //~ ERROR expected ~ closure, found @ closure
+    take::<unsafe fn~()>(y); //~ ERROR expected ~ closure, found @ closure
+    take::<unsafe fn~()>(z); //~ ERROR expected ~ closure, found @ closure
 }
 
 fn main() {
diff --git a/src/test/compile-fail/regions-fn-bound.rs b/src/test/compile-fail/regions-fn-bound.rs
new file mode 100644
index 00000000000..ce2839b1caf
--- /dev/null
+++ b/src/test/compile-fail/regions-fn-bound.rs
@@ -0,0 +1,21 @@
+fn of<T>() -> @fn(T) { fail; }
+fn subtype<T>(x: @fn(T)) { fail; }
+
+fn test_fn<T>(_x: &x/T, _y: &y/T, _z: &z/T) {
+    // Here, x, y, and z are free.  Other letters
+    // are bound.  Note that the arrangement
+    // subtype::<T1>(of::<T2>()) will typecheck
+    // iff T1 <: T2.
+
+    // should be the default:
+    subtype::<@static/fn()>(of::<@fn()>());
+    subtype::<@fn()>(of::<@static/fn()>());
+
+    //
+    subtype::<@x/fn()>(of::<@fn()>());    //~ ERROR mismatched types
+    subtype::<@x/fn()>(of::<@y/fn()>());  //~ ERROR mismatched types
+
+    subtype::<@x/fn()>(of::<@static/fn()>()); //~ ERROR mismatched types
+    subtype::<@static/fn()>(of::<@x/fn()>());
+
+}
diff --git a/src/test/compile-fail/regions-freevar.rs b/src/test/compile-fail/regions-freevar.rs
index b163006c50a..e5b33d725c7 100644
--- a/src/test/compile-fail/regions-freevar.rs
+++ b/src/test/compile-fail/regions-freevar.rs
@@ -2,8 +2,7 @@ fn wants_static_fn(_x: &static/fn()) {}
 
 fn main() {
     let i = 3;
-    do wants_static_fn {
+    do wants_static_fn { //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements
         debug!("i=%d", i);
-          //~^ ERROR captured variable does not outlive the enclosing closure
     }
 }
diff --git a/src/test/compile-fail/sendfn-is-not-a-lambda.rs b/src/test/compile-fail/sendfn-is-not-a-lambda.rs
index 081c400d71d..f47cf51b4be 100644
--- a/src/test/compile-fail/sendfn-is-not-a-lambda.rs
+++ b/src/test/compile-fail/sendfn-is-not-a-lambda.rs
@@ -4,5 +4,5 @@ fn test(f: fn@(uint) -> uint) -> uint {
 
 fn main() {
     let f = fn~(x: uint) -> uint { return 4u; };
-    log(debug, test(f)); //~ ERROR expected `fn@(uint) -> uint`
+    log(debug, test(f)); //~ ERROR expected @ closure, found ~ closure
 }
diff --git a/src/test/pretty/disamb-stmt-expr.rs b/src/test/pretty/disamb-stmt-expr.rs
index 3ad709d991d..9fb898991e8 100644
--- a/src/test/pretty/disamb-stmt-expr.rs
+++ b/src/test/pretty/disamb-stmt-expr.rs
@@ -4,7 +4,7 @@
 // preserved.  They are needed to disambiguate `{return n+1}; - 0` from
 // `({return n+1}-0)`.
 
-fn id(f: fn&() -> int) -> int { f() }
+fn id(f: &fn() -> int) -> int { f() }
 
 fn wsucc(n: int) -> int { (do id || { 1 }) - 0 }
 fn main() { }
diff --git a/src/test/pretty/fn-types.rs b/src/test/pretty/fn-types.rs
index 9132c5475ff..a1fdf5094c1 100644
--- a/src/test/pretty/fn-types.rs
+++ b/src/test/pretty/fn-types.rs
@@ -1,7 +1,7 @@
 // pp-exact
 
 fn from_foreign_fn(x: extern fn()) { }
-fn from_stack_closure(x: fn&()) { }
-fn from_box_closure(x: fn@()) { }
-fn from_unique_closure(x: fn~()) { }
+fn from_stack_closure(x: &fn()) { }
+fn from_box_closure(x: @fn()) { }
+fn from_unique_closure(x: ~fn()) { }
 fn main() { }
diff --git a/src/test/run-pass/issue-2185.rs b/src/test/run-pass/issue-2185.rs
index 8913ac3d304..c95e8417954 100644
--- a/src/test/run-pass/issue-2185.rs
+++ b/src/test/run-pass/issue-2185.rs
@@ -1,3 +1,4 @@
+// xfail-test FIXME #2263
 // xfail-fast
 // This test had to do with an outdated version of the iterable trait.
 // However, the condition it was testing seemed complex enough to
diff --git a/src/test/run-pass/task-killjoin-rsrc.rs b/src/test/run-pass/task-killjoin-rsrc.rs
index 1cea7d61f8c..1e8da40b5b3 100644
--- a/src/test/run-pass/task-killjoin-rsrc.rs
+++ b/src/test/run-pass/task-killjoin-rsrc.rs
@@ -37,7 +37,7 @@ fn joinable(+f: fn~()) -> comm::Port<bool> {
     }
     let p = comm::Port();
     let c = comm::Chan(&p);
-    do task::spawn_unlinked { wrapper(c, copy f) };
+    do task::spawn_unlinked { wrapper(c, f) };
     p
 }