about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/front/config.rs25
-rw-r--r--src/librustc/front/test.rs113
-rw-r--r--src/librustc/metadata/decoder.rs24
-rw-r--r--src/librustc/metadata/encoder.rs10
-rw-r--r--src/librustc/metadata/tydecode.rs79
-rw-r--r--src/librustc/metadata/tyencode.rs54
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs60
-rw-r--r--src/librustc/middle/check_const.rs2
-rw-r--r--src/librustc/middle/check_loop.rs4
-rw-r--r--src/librustc/middle/check_match.rs14
-rw-r--r--src/librustc/middle/freevars.rs6
-rw-r--r--src/librustc/middle/kind.rs58
-rw-r--r--src/librustc/middle/lint.rs17
-rw-r--r--src/librustc/middle/mem_categorization.rs99
-rw-r--r--src/librustc/middle/moves.rs34
-rw-r--r--src/librustc/middle/region.rs12
-rw-r--r--src/librustc/middle/trans/_match.rs2
-rw-r--r--src/librustc/middle/trans/base.rs32
-rw-r--r--src/librustc/middle/trans/callee.rs9
-rw-r--r--src/librustc/middle/trans/closure.rs116
-rw-r--r--src/librustc/middle/trans/controlflow.rs12
-rw-r--r--src/librustc/middle/trans/expr.rs71
-rw-r--r--src/librustc/middle/trans/foreign.rs25
-rw-r--r--src/librustc/middle/trans/glue.rs15
-rw-r--r--src/librustc/middle/trans/inline.rs4
-rw-r--r--src/librustc/middle/trans/machine.rs7
-rw-r--r--src/librustc/middle/trans/meth.rs6
-rw-r--r--src/librustc/middle/trans/monomorphize.rs65
-rw-r--r--src/librustc/middle/trans/reflect.rs93
-rw-r--r--src/librustc/middle/trans/type_of.rs14
-rw-r--r--src/librustc/middle/trans/type_use.rs29
-rw-r--r--src/librustc/middle/ty.rs538
-rw-r--r--src/librustc/middle/typeck/astconv.rs146
-rw-r--r--src/librustc/middle/typeck/check/method.rs8
-rw-r--r--src/librustc/middle/typeck/check/mod.rs531
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs19
-rw-r--r--src/librustc/middle/typeck/check/regionmanip.rs17
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs2
-rw-r--r--src/librustc/middle/typeck/coherence.rs6
-rw-r--r--src/librustc/middle/typeck/collect.rs186
-rw-r--r--src/librustc/middle/typeck/infer/coercion.rs43
-rw-r--r--src/librustc/middle/typeck/infer/combine.rs78
-rw-r--r--src/librustc/middle/typeck/infer/glb.rs18
-rw-r--r--src/librustc/middle/typeck/infer/lattice.rs17
-rw-r--r--src/librustc/middle/typeck/infer/lub.rs18
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs4
-rw-r--r--src/librustc/middle/typeck/infer/region_inference.rs3
-rw-r--r--src/librustc/middle/typeck/infer/sub.rs18
-rw-r--r--src/librustc/middle/typeck/infer/to_str.rs14
-rw-r--r--src/librustc/middle/typeck/mod.rs6
-rw-r--r--src/librustc/util/ppaux.rs159
51 files changed, 1398 insertions, 1544 deletions
diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs
index a7c071919ff..cf75db3a900 100644
--- a/src/librustc/front/config.rs
+++ b/src/librustc/front/config.rs
@@ -64,12 +64,13 @@ fn filter_view_item(cx: ctxt, &&view_item: @ast::view_item
 }
 
 fn fold_mod(cx: ctxt, m: ast::_mod, fld: fold::ast_fold) -> ast::_mod {
-    let filtered_items = vec::filter_map(m.items, |a| filter_item(cx, *a));
-    let filtered_view_items = vec::filter_map(m.view_items,
-                                              |a| filter_view_item(cx, *a));
+    let filtered_items =
+        m.items.filter_mapped(|a| filter_item(cx, *a));
+    let filtered_view_items =
+        m.view_items.filter_mapped(|a| filter_view_item(cx, *a));
     ast::_mod {
         view_items: filtered_view_items.map(|x| fld.fold_view_item(*x)),
-        items: filtered_items.filter_map(|x| fld.fold_item(*x)),
+        items: vec::filter_map(filtered_items, |x| fld.fold_item(x))
     }
 }
 
@@ -85,10 +86,10 @@ fn fold_foreign_mod(
     nm: ast::foreign_mod,
     fld: fold::ast_fold
 ) -> ast::foreign_mod {
-    let filtered_items = vec::filter_map(nm.items,
-                                         |a| filter_foreign_item(cx, *a));
-    let filtered_view_items = vec::filter_map(nm.view_items,
-                                              |a| filter_view_item(cx, *a));
+    let filtered_items =
+        nm.items.filter_mapped(|a| filter_foreign_item(cx, *a));
+    let filtered_view_items =
+        nm.view_items.filter_mapped(|a| filter_view_item(cx, *a));
     ast::foreign_mod {
         sort: nm.sort,
         abi: nm.abi,
@@ -136,7 +137,8 @@ fn fold_block(
     b: ast::blk_,
     fld: fold::ast_fold
 ) -> ast::blk_ {
-    let filtered_stmts = vec::filter_map(b.stmts, |a| filter_stmt(cx, *a));
+    let filtered_stmts =
+        b.stmts.filter_mapped(|a| filter_stmt(cx, *a));
     ast::blk_ {
         view_items: /*bad*/copy b.view_items,
         stmts: vec::map(filtered_stmts, |x| fld.fold_stmt(*x)),
@@ -183,8 +185,9 @@ pub fn metas_in_cfg(cfg: ast::crate_cfg,
     // Pull the inner meta_items from the #[cfg(meta_item, ...)]  attributes,
     // so we can match against them. This is the list of configurations for
     // which the item is valid
-    let cfg_metas = vec::concat(vec::filter_map(cfg_metas,
-        |i| attr::get_meta_item_list(*i)));
+    let cfg_metas =
+        vec::concat(
+            vec::filter_map(cfg_metas, |i| attr::get_meta_item_list(i)));
 
     let has_cfg_metas = vec::len(cfg_metas) > 0u;
     if !has_cfg_metas { return true; }
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
index 91eb8148bb7..9fa1cea3e10 100644
--- a/src/librustc/front/test.rs
+++ b/src/librustc/front/test.rs
@@ -168,9 +168,11 @@ fn is_test_fn(i: @ast::item) -> bool {
 fn is_ignored(cx: test_ctxt, i: @ast::item) -> bool {
     let ignoreattrs = attr::find_attrs_by_name(i.attrs, "ignore");
     let ignoreitems = attr::attr_metas(ignoreattrs);
-    let cfg_metas = vec::concat(vec::filter_map(ignoreitems,
-        |i| attr::get_meta_item_list(*i)));
     return if !ignoreitems.is_empty() {
+        let cfg_metas =
+            vec::concat(
+                vec::filter_map(ignoreitems,
+                                |i| attr::get_meta_item_list(i)));
         config::metas_in_cfg(/*bad*/copy cx.crate.node.config, cfg_metas)
     } else {
         false
@@ -277,7 +279,7 @@ fn mk_std(cx: test_ctxt) -> @ast::view_item {
 }
 
 fn mk_tests(cx: test_ctxt) -> @ast::item {
-    let ret_ty = mk_test_desc_vec_ty(cx);
+    let ret_ty = mk_test_desc_and_fn_vec_ty(cx);
 
     let decl = ast::fn_decl {
         inputs: ~[],
@@ -286,7 +288,7 @@ fn mk_tests(cx: test_ctxt) -> @ast::item {
     };
 
     // The vector of test_descs for this crate
-    let test_descs = mk_test_desc_vec(cx);
+    let test_descs = mk_test_desc_and_fn_vec(cx);
 
     let body_: ast::blk_ =
         default_block(~[], option::Some(test_descs), cx.sess.next_node_id());
@@ -327,19 +329,21 @@ fn mk_path(cx: test_ctxt, +path: ~[ast::ident]) -> @ast::path {
     }
 }
 
-// The ast::Ty of ~[std::test::test_desc]
-fn mk_test_desc_vec_ty(cx: test_ctxt) -> @ast::Ty {
-    let test_desc_ty_path =
+// The ast::Ty of ~[std::test::TestDescAndFn]
+fn mk_test_desc_and_fn_vec_ty(cx: test_ctxt) -> @ast::Ty {
+    let test_desc_and_fn_ty_path =
         mk_path(cx, ~[cx.sess.ident_of(~"test"),
-                      cx.sess.ident_of(~"TestDesc")]);
+                      cx.sess.ident_of(~"TestDescAndFn")]);
 
-    let test_desc_ty = ast::Ty {
+    let test_desc_and_fn_ty = ast::Ty {
         id: cx.sess.next_node_id(),
-        node: ast::ty_path(test_desc_ty_path, cx.sess.next_node_id()),
+        node: ast::ty_path(test_desc_and_fn_ty_path,
+                           cx.sess.next_node_id()),
         span: dummy_sp(),
     };
 
-    let vec_mt = ast::mt {ty: @test_desc_ty, mutbl: ast::m_imm};
+    let vec_mt = ast::mt {ty: @test_desc_and_fn_ty,
+                          mutbl: ast::m_imm};
 
     let inner_ty = @ast::Ty {
         id: cx.sess.next_node_id(),
@@ -354,11 +358,11 @@ fn mk_test_desc_vec_ty(cx: test_ctxt) -> @ast::Ty {
     }
 }
 
-fn mk_test_desc_vec(cx: test_ctxt) -> @ast::expr {
+fn mk_test_desc_and_fn_vec(cx: test_ctxt) -> @ast::expr {
     debug!("building test vector from %u tests", cx.testfns.len());
     let mut descs = ~[];
     for cx.testfns.each |test| {
-        descs.push(mk_test_desc_rec(cx, *test));
+        descs.push(mk_test_desc_and_fn_rec(cx, *test));
     }
 
     let inner_expr = @ast::expr {
@@ -376,7 +380,7 @@ fn mk_test_desc_vec(cx: test_ctxt) -> @ast::expr {
     }
 }
 
-fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {
+fn mk_test_desc_and_fn_rec(cx: test_ctxt, test: test) -> @ast::expr {
     let span = test.span;
     let path = /*bad*/copy test.path;
 
@@ -407,23 +411,6 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {
         expr: @name_expr,
     });
 
-    let fn_path = path_node_global(path);
-
-    let fn_expr = ast::expr {
-        id: cx.sess.next_node_id(),
-        callee_id: cx.sess.next_node_id(),
-        node: ast::expr_path(fn_path),
-        span: span,
-    };
-
-    let fn_wrapper_expr = mk_test_wrapper(cx, fn_expr, span);
-
-    let fn_field = nospan(ast::field_ {
-        mutbl: ast::m_imm,
-        ident: cx.sess.ident_of(~"testfn"),
-        expr: fn_wrapper_expr,
-    });
-
     let ignore_lit: ast::lit = nospan(ast::lit_bool(test.ignore));
 
     let ignore_expr = ast::expr {
@@ -460,62 +447,52 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {
 
     let desc_rec_ = ast::expr_struct(
         test_desc_path,
-        ~[name_field, fn_field, ignore_field, fail_field],
+        ~[name_field, ignore_field, fail_field],
         option::None
     );
 
-    let desc_rec = ast::expr {
+    let desc_rec = @ast::expr {
         id: cx.sess.next_node_id(),
         callee_id: cx.sess.next_node_id(),
         node: desc_rec_,
         span: span,
     };
 
-    return @desc_rec;
-}
+    let desc_field = nospan(ast::field_ {
+        mutbl: ast::m_imm,
+        ident: cx.sess.ident_of(~"desc"),
+        expr: desc_rec
+    });
 
-// Produces a bare function that wraps the test function
+    let fn_path = path_node_global(path);
 
-// FIXME (#1281): This can go away once fn is the type of bare function.
-fn mk_test_wrapper(cx: test_ctxt,
-                   +fn_path_expr: ast::expr,
-                   span: span) -> @ast::expr {
-    let call_expr = ast::expr {
+    let fn_expr = @ast::expr {
         id: cx.sess.next_node_id(),
         callee_id: cx.sess.next_node_id(),
-        node: ast::expr_call(@fn_path_expr, ~[], false),
+        node: ast::expr_path(fn_path),
         span: span,
     };
 
-    let call_stmt: ast::stmt = nospan(
-        ast::stmt_semi(@call_expr, cx.sess.next_node_id()));
-
-    let wrapper_decl = ast::fn_decl {
-        inputs: ~[],
-        output: @ast::Ty {
-            id: cx.sess.next_node_id(),
-            node: ast::ty_nil,
-            span: span,
-        },
-        cf: ast::return_val
-    };
-
-    let wrapper_body = nospan(ast::blk_ {
-        view_items: ~[],
-        stmts: ~[@call_stmt],
-        expr: option::None,
-        id: cx.sess.next_node_id(),
-        rules: ast::default_blk
+    let fn_field = nospan(ast::field_ {
+        mutbl: ast::m_imm,
+        ident: cx.sess.ident_of(~"testfn"),
+        expr: fn_expr,
     });
 
-    let wrapper_expr = ast::expr  {
+    let test_desc_and_fn_path =
+        mk_path(cx, ~[cx.sess.ident_of(~"test"),
+                      cx.sess.ident_of(~"TestDescAndFn")]);
+
+    let desc_and_fn_rec = @ast::expr {
         id: cx.sess.next_node_id(),
         callee_id: cx.sess.next_node_id(),
-        node: ast::expr_fn(ast::ProtoBare, wrapper_decl, wrapper_body, @()),
-        span: span
+        node: ast::expr_struct(test_desc_and_fn_path,
+                               ~[fn_field, desc_field],
+                               option::None),
+        span: span,
     };
 
-    return @wrapper_expr;
+    return desc_and_fn_rec;
 }
 
 fn mk_main(cx: test_ctxt) -> @ast::item {
@@ -567,7 +544,7 @@ fn mk_test_main_call(cx: test_ctxt) -> @ast::expr {
     let args_call_expr = ast::expr {
         id: cx.sess.next_node_id(),
         callee_id: cx.sess.next_node_id(),
-        node: ast::expr_call(@args_path_expr, ~[], false),
+        node: ast::expr_call(@args_path_expr, ~[], ast::NoSugar),
         span: dummy_sp(),
     };
 
@@ -584,7 +561,7 @@ fn mk_test_main_call(cx: test_ctxt) -> @ast::expr {
     let test_call_expr = ast::expr {
         id: cx.sess.next_node_id(),
         callee_id: cx.sess.next_node_id(),
-        node: ast::expr_call(@test_path_expr, ~[], false),
+        node: ast::expr_call(@test_path_expr, ~[], ast::NoSugar),
         span: dummy_sp(),
     };
 
@@ -606,7 +583,7 @@ fn mk_test_main_call(cx: test_ctxt) -> @ast::expr {
         node: ast::expr_call(
             @test_main_path_expr,
             ~[@args_call_expr, @test_call_expr],
-            false
+            ast::NoSugar
         ),
         span: dummy_sp(),
     };
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 9a6a2f7e954..67498ad5aaf 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -586,10 +586,8 @@ pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::node_id,
                                 item, tcx, cdata);
         let name = item_name(intr, item);
         let arg_tys = match ty::get(ctor_ty).sty {
-          ty::ty_fn(ref f) => (*f).sig.inputs.map(|a| a.ty),
-
-          // Nullary enum variant.
-          _ => ~[],
+          ty::ty_bare_fn(ref f) => f.sig.inputs.map(|a| a.ty),
+          _ => ~[], // Nullary enum variant.
         };
         match variant_disr_val(item) {
           Some(val) => { disr_val = val; }
@@ -705,11 +703,12 @@ pub fn get_trait_methods(intr: @ident_interner, cdata: cmd, id: ast::node_id,
         let ty = doc_type(mth, tcx, cdata);
         let def_id = item_def_id(mth, cdata);
         let fty = match ty::get(ty).sty {
-          ty::ty_fn(ref f) => (/*bad*/copy *f),
-          _ => {
-            tcx.diag.handler().bug(
-                ~"get_trait_methods: id has non-function type");
-        } };
+            ty::ty_bare_fn(ref f) => copy *f,
+            _ => {
+                tcx.diag.handler().bug(
+                    ~"get_trait_methods: id has non-function type");
+            }
+        };
         let self_ty = get_self_ty(mth);
         result.push({ident: name, tps: bounds, fty: fty, self_ty: self_ty,
                      vis: ast::public, def_id: def_id});
@@ -734,14 +733,13 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd,
         let name = item_name(intr, mth);
         let ty = doc_type(mth, tcx, cdata);
 
-        let fty;
-        match ty::get(ty).sty {
-            ty::ty_fn(ref f) => fty = (/*bad*/copy *f),
+        let fty = match ty::get(ty).sty {
+            ty::ty_bare_fn(ref f) => copy *f,
             _ => {
                 tcx.diag.handler().bug(~"get_provided_trait_methods(): id \
                                          has non-function type");
             }
-        }
+        };
 
         let self_ty = get_self_ty(mth);
         let ty_method = {ident: name, tps: bounds, fty: fty, self_ty: self_ty,
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 072b974d042..b0a424447b3 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -768,8 +768,9 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: writer::Encoder,
                 encode_name(ecx, ebml_w, mty.ident);
                 encode_type_param_bounds(ebml_w, ecx,
                                          (*ty_m).tps);
-                encode_type(ecx, ebml_w, ty::mk_fn(tcx, /*bad*/copy mty.fty));
-                encode_family(ebml_w, purity_fn_family(mty.fty.meta.purity));
+                encode_type(ecx, ebml_w,
+                            ty::mk_bare_fn(tcx, copy mty.fty));
+                encode_family(ebml_w, purity_fn_family(mty.fty.purity));
                 encode_self_type(ebml_w, mty.self_ty);
                 encode_method_sort(ebml_w, 'r');
                 ebml_w.end_tag();
@@ -781,8 +782,9 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: writer::Encoder,
                 encode_def_id(ebml_w, local_def(m.id));
                 encode_name(ecx, ebml_w, mty.ident);
                 encode_type_param_bounds(ebml_w, ecx, m.tps);
-                encode_type(ecx, ebml_w, ty::mk_fn(tcx, /*bad*/copy mty.fty));
-                encode_family(ebml_w, purity_fn_family(mty.fty.meta.purity));
+                encode_type(ecx, ebml_w,
+                            ty::mk_bare_fn(tcx, copy mty.fty));
+                encode_family(ebml_w, purity_fn_family(mty.fty.purity));
                 encode_self_type(ebml_w, mty.self_ty);
                 encode_method_sort(ebml_w, 'p');
                 ebml_w.end_tag();
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index ea13325ad49..3f989339e27 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -17,8 +17,6 @@
 use core::prelude::*;
 
 use middle::ty;
-use middle::ty::{FnTyBase, FnMeta, FnSig, arg, creader_cache_key, field};
-use middle::ty::{substs};
 
 use core::io;
 use core::str;
@@ -124,17 +122,12 @@ fn parse_path(st: @pstate) -> @ast::path {
     };
 }
 
-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) -> ast::Proto {
+fn parse_sigil(st: @pstate) -> ast::Sigil {
     match next(st) {
-        '_' => ast::ProtoBare,
-        '@' => ast::ProtoBox,
-        '~' => ast::ProtoUniq,
-        '&' => ast::ProtoBorrowed,
-        _ => die!(~"parse_proto(): bad input")
+        '@' => ast::ManagedSigil,
+        '~' => ast::OwnedSigil,
+        '&' => ast::BorrowedSigil,
+        c => st.tcx.sess.bug(fmt!("parse_sigil(): bad input '%c'", c))
     }
 }
 
@@ -152,7 +145,7 @@ fn parse_vstore(st: @pstate) -> ty::vstore {
       '~' => ty::vstore_uniq,
       '@' => ty::vstore_box,
       '&' => ty::vstore_slice(parse_region(st)),
-      _ => die!(~"parse_vstore: bad input")
+      c => st.tcx.sess.bug(fmt!("parse_vstore(): bad input '%c'", c))
     }
 }
 
@@ -166,7 +159,7 @@ fn parse_substs(st: @pstate, conv: conv_did) -> ty::substs {
     while peek(st) != ']' { params.push(parse_ty(st, conv)); }
     st.pos = st.pos + 1u;
 
-    return substs {
+    return ty::substs {
         self_r: self_r,
         self_ty: self_ty,
         tps: params
@@ -316,19 +309,24 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
         return ty::mk_tup(st.tcx, params);
       }
       'f' => {
-        parse_ty_rust_fn(st, conv)
+        return ty::mk_closure(st.tcx, parse_closure_ty(st, conv));
+      }
+      'F' => {
+        return ty::mk_bare_fn(st.tcx, parse_bare_fn_ty(st, conv));
       }
       'Y' => return ty::mk_type(st.tcx),
       'C' => {
-        let proto = parse_proto(st);
-        return ty::mk_opaque_closure_ptr(st.tcx, proto);
+        let sigil = parse_sigil(st);
+        return ty::mk_opaque_closure_ptr(st.tcx, sigil);
       }
       '#' => {
         let pos = parse_hex(st);
         assert (next(st) == ':');
         let len = parse_hex(st);
         assert (next(st) == '#');
-        let key = creader_cache_key { cnum: st.crate, pos: pos, len: len };
+        let key = ty::creader_cache_key {cnum: st.crate,
+                                         pos: pos,
+                                         len: len };
         match st.tcx.rcache.find(&key) {
           Some(tt) => return tt,
           None => {
@@ -408,6 +406,13 @@ fn parse_purity(c: char) -> purity {
     }
 }
 
+fn parse_abi(c: char) -> Abi {
+    match c {
+      'r' => ast::RustAbi,
+      _ => die!(fmt!("parse_abi: bad ABI '%c'", c))
+    }
+}
+
 fn parse_onceness(c: char) -> ast::Onceness {
     match c {
         'o' => ast::Once,
@@ -430,12 +435,33 @@ fn parse_mode(st: @pstate) -> ast::mode {
     return m;
 }
 
-fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::FnTy {
-    let proto = parse_proto(st);
+fn parse_closure_ty(st: @pstate, conv: conv_did) -> ty::ClosureTy {
+    let sigil = parse_sigil(st);
     let purity = parse_purity(next(st));
     let onceness = parse_onceness(next(st));
     let region = parse_region(st);
-    let bounds = parse_bounds(st, conv);
+    let sig = parse_sig(st, conv);
+    ty::ClosureTy {
+        purity: purity,
+        sigil: sigil,
+        onceness: onceness,
+        region: region,
+        sig: sig
+    }
+}
+
+fn parse_bare_fn_ty(st: @pstate, conv: conv_did) -> ty::BareFnTy {
+    let purity = parse_purity(next(st));
+    let abi = parse_abi(next(st));
+    let sig = parse_sig(st, conv);
+    ty::BareFnTy {
+        purity: purity,
+        abi: abi,
+        sig: sig
+    }
+}
+
+fn parse_sig(st: @pstate, conv: conv_did) -> ty::FnSig {
     assert (next(st) == '[');
     let mut inputs: ~[ty::arg] = ~[];
     while peek(st) != ']' {
@@ -444,18 +470,9 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::FnTy {
     }
     st.pos += 1u; // eat the ']'
     let ret_ty = parse_ty(st, conv);
-    return FnTyBase {
-        meta: FnMeta {purity: purity,
-                      proto: proto,
-                      onceness: onceness,
-                      bounds: bounds,
-                      region: region},
-        sig: FnSig {inputs: inputs,
-                    output: ret_ty}
-    };
+    ty::FnSig {inputs: inputs, output: ret_ty}
 }
 
-
 // Rust metadata parsing
 pub fn parse_def_id(buf: &[u8]) -> ast::def_id {
     let mut colon_idx = 0u;
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 0d66862c79f..a87ce02d5a3 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -288,8 +288,13 @@ fn enc_sty(w: io::Writer, cx: @ctxt, +st: ty::sty) {
         }
         w.write_char(']');
       }
-      ty::ty_fn(ref f) => {
-        enc_ty_fn(w, cx, (*f));
+      ty::ty_closure(ref f) => {
+        w.write_char('f');
+        enc_closure_ty(w, cx, f);
+      }
+      ty::ty_bare_fn(ref f) => {
+        w.write_char('F');
+        enc_bare_fn_ty(w, cx, f);
       }
       ty::ty_infer(_) => {
         cx.diag.handler().bug(~"Cannot encode inference variable types");
@@ -306,7 +311,7 @@ fn enc_sty(w: io::Writer, cx: @ctxt, +st: ty::sty) {
       ty::ty_type => w.write_char('Y'),
       ty::ty_opaque_closure_ptr(p) => {
           w.write_str(&"C&");
-          enc_proto(w, p);
+          enc_sigil(w, p);
       }
       ty::ty_opaque_box => w.write_char('B'),
       ty::ty_struct(def, ref substs) => {
@@ -325,13 +330,11 @@ fn enc_sty(w: io::Writer, cx: @ctxt, +st: ty::sty) {
     }
 }
 
-fn enc_proto(w: io::Writer, proto: Proto) {
-    w.write_str(&"f");
-    match proto {
-        ProtoBare => w.write_str(&"_"),
-        ProtoBox => w.write_str(&"@"),
-        ProtoUniq => w.write_str(&"~"),
-        ProtoBorrowed => w.write_str(&"&"),
+fn enc_sigil(w: io::Writer, sigil: Sigil) {
+    match sigil {
+        ManagedSigil => w.write_str("@"),
+        OwnedSigil => w.write_str("~"),
+        BorrowedSigil => w.write_str("&"),
     }
 }
 
@@ -357,6 +360,12 @@ fn enc_purity(w: io::Writer, p: purity) {
     }
 }
 
+fn enc_abi(w: io::Writer, a: Abi) {
+    match a {
+        RustAbi => w.write_char('r'),
+    }
+}
+
 fn enc_onceness(w: io::Writer, o: Onceness) {
     match o {
         Once => w.write_char('o'),
@@ -364,18 +373,27 @@ fn enc_onceness(w: io::Writer, o: Onceness) {
     }
 }
 
-fn enc_ty_fn(w: io::Writer, cx: @ctxt, ft: ty::FnTy) {
-    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);
+fn enc_bare_fn_ty(w: io::Writer, cx: @ctxt, ft: &ty::BareFnTy) {
+    enc_purity(w, ft.purity);
+    enc_abi(w, ft.abi);
+    enc_fn_sig(w, cx, &ft.sig);
+}
+
+fn enc_closure_ty(w: io::Writer, cx: @ctxt, ft: &ty::ClosureTy) {
+    enc_sigil(w, ft.sigil);
+    enc_purity(w, ft.purity);
+    enc_onceness(w, ft.onceness);
+    enc_region(w, cx, ft.region);
+    enc_fn_sig(w, cx, &ft.sig);
+}
+
+fn enc_fn_sig(w: io::Writer, cx: @ctxt, fsig: &ty::FnSig) {
     w.write_char('[');
-    for ft.sig.inputs.each |arg| {
+    for fsig.inputs.each |arg| {
         enc_arg(w, cx, *arg);
     }
     w.write_char(']');
-    enc_ty(w, cx, ft.sig.output);
+    enc_ty(w, cx, fsig.output);
 }
 
 pub fn enc_bounds(w: io::Writer, cx: @ctxt, bs: @~[ty::param_bound]) {
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index 9b2d51289ad..dfc26000116 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -221,18 +221,19 @@ impl check_loan_ctxt {
 
         let callee_ty = ty::node_id_to_type(tcx, callee_id);
         match ty::get(callee_ty).sty {
-          ty::ty_fn(ref fn_ty) => {
-            match fn_ty.meta.purity {
-              ast::pure_fn => return, // case (c) above
-              ast::impure_fn | ast::unsafe_fn | ast::extern_fn => {
-                self.report_purity_error(
-                    pc, callee_span,
-                    fmt!("access to %s function",
-                         fn_ty.meta.purity.to_str()));
-              }
+            ty::ty_bare_fn(ty::BareFnTy {purity: purity, _}) |
+            ty::ty_closure(ty::ClosureTy {purity: purity, _}) => {
+                match purity {
+                    ast::pure_fn => return, // case (c) above
+                    ast::impure_fn | ast::unsafe_fn | ast::extern_fn => {
+                        self.report_purity_error(
+                            pc, callee_span,
+                            fmt!("access to %s function",
+                                 purity.to_str()));
+                    }
+                }
             }
-          }
-          _ => return, // case (d) above
+            _ => return, // case (d) above
         }
     }
 
@@ -240,8 +241,11 @@ impl check_loan_ctxt {
     // The expression must be an expr_fn(*) or expr_fn_block(*)
     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 proto == ast::ProtoBorrowed;
+        match ty::get(fn_ty).sty {
+            ty::ty_closure(ty::ClosureTy {sigil: ast::BorrowedSigil,
+                                          _}) => true,
+            _ => false
+        }
     }
 
     fn is_allowed_pure_arg(expr: @ast::expr) -> bool {
@@ -564,17 +568,27 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
 {
     let is_stack_closure = self.is_stack_closure(id);
     let fty = ty::node_id_to_type(self.tcx(), id);
-    let fty_proto = ty::ty_fn_proto(fty);
 
-    check_moves_from_captured_variables(self, id, fty_proto);
+    let declared_purity;
+    match fk {
+        visit::fk_item_fn(*) | visit::fk_method(*) |
+        visit::fk_dtor(*) => {
+            declared_purity = ty::ty_fn_purity(fty);
+        }
+
+        visit::fk_anon(*) | visit::fk_fn_block(*) => {
+            let fty_sigil = ty::ty_closure_sigil(fty);
+            check_moves_from_captured_variables(self, id, fty_sigil);
+            declared_purity = ty::determine_inherited_purity(
+                copy self.declared_purity, ty::ty_fn_purity(fty),
+                fty_sigil);
+        }
+    }
 
     debug!("purity on entry=%?", copy self.declared_purity);
     do save_and_restore(&mut(self.declared_purity)) {
         do save_and_restore(&mut(self.fn_args)) {
-            self.declared_purity = ty::determine_inherited_purity(
-                copy self.declared_purity,
-                ty::ty_fn_purity(fty),
-                fty_proto);
+            self.declared_purity = declared_purity;
 
             match fk {
                 visit::fk_anon(*) |
@@ -608,10 +622,10 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
 
     fn check_moves_from_captured_variables(&&self: check_loan_ctxt,
                                            id: ast::node_id,
-                                           fty_proto: ast::Proto)
+                                           fty_sigil: ast::Sigil)
     {
-        match fty_proto {
-            ast::ProtoBox | ast::ProtoUniq => {
+        match fty_sigil {
+            ast::ManagedSigil | ast::OwnedSigil => {
                 let cap_vars = self.bccx.capture_map.get(&id);
                 for cap_vars.each |cap_var| {
                     match cap_var.mode {
@@ -646,7 +660,7 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
                 }
             }
 
-            ast::ProtoBorrowed | ast::ProtoBare => {}
+            ast::BorrowedSigil => {}
         }
     }
 }
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 69ace0d7797..ad46d3b6f4d 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -150,7 +150,7 @@ pub fn check_expr(sess: Session,
               }
             }
           }
-          expr_call(callee, _, false) => {
+          expr_call(callee, _, NoSugar) => {
             match def_map.find(&callee.id) {
                 Some(def_struct(*)) => {}    // OK.
                 Some(def_variant(*)) => {}    // OK.
diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs
index 11c557f0249..38450de6b54 100644
--- a/src/librustc/middle/check_loop.rs
+++ b/src/librustc/middle/check_loop.rs
@@ -39,8 +39,8 @@ pub fn check_crate(tcx: ty::ctxt, crate: @crate) {
                 (v.visit_block)((*b), {in_loop: false, can_ret: false}, v);
               }
               expr_loop_body(@expr {node: expr_fn_block(_, ref b), _}) => {
-                let proto = ty::ty_fn_proto(ty::expr_ty(tcx, e));
-                let blk = (proto == ProtoBorrowed);
+                let sigil = ty::ty_closure_sigil(ty::expr_ty(tcx, e));
+                let blk = (sigil == BorrowedSigil);
                 (v.visit_block)((*b), {in_loop: true, can_ret: blk}, v);
               }
               expr_break(_) => {
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 978aaacb18a..6f9fe1edca5 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -100,7 +100,7 @@ pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, &&s: (), v: visit::vt<()>) {
           }
           _ => { /* We assume only enum types can be uninhabited */ }
        }
-       let arms = vec::concat(vec::filter_map((*arms), unguarded_pat));
+       let arms = vec::concat(arms.filter_mapped(unguarded_pat));
        check_exhaustive(cx, ex.span, arms);
      }
      _ => ()
@@ -255,7 +255,8 @@ pub fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: &[@pat]) -> useful {
             }
           }
           Some(ref ctor) => {
-            match is_useful(cx, vec::filter_map(m, |r| default(cx, copy *r)),
+            match is_useful(cx,
+                            vec::filter_map(m, |r| default(cx, r)),
                             vec::tail(v)) {
               useful_ => useful(left_ty, (/*bad*/copy *ctor)),
               ref u => (/*bad*/copy *u)
@@ -277,8 +278,7 @@ pub fn is_useful_specialized(cx: @MatchCheckCtxt,
                              arity: uint,
                              lty: ty::t)
                           -> useful {
-    let ms = vec::filter_map(m, |r| specialize(cx, *r,
-                                               ctor, arity, lty));
+    let ms = m.filter_mapped(|r| specialize(cx, *r, ctor, arity, lty));
     let could_be_useful = is_useful(
         cx, ms, specialize(cx, v, ctor, arity, lty).get());
     match could_be_useful {
@@ -387,9 +387,9 @@ pub fn missing_ctor(cx: @MatchCheckCtxt,
       ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
 
         // Find the lengths and tails of all vector patterns.
-        let vec_pat_lens = do m.filter_map |r| {
-            match /*bad*/copy r[0].node {
-                pat_vec(elems, tail) => {
+        let vec_pat_lens = do m.filter_mapped |r| {
+            match r[0].node {
+                pat_vec(ref elems, ref tail) => {
                     Some((elems.len(), tail.is_some()))
                 }
                 _ => None
diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs
index 5d65aba2a4d..e6091077210 100644
--- a/src/librustc/middle/freevars.rs
+++ b/src/librustc/middle/freevars.rs
@@ -48,10 +48,8 @@ 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::ProtoBare {
-                    visit::visit_expr(expr, depth + 1, v);
-                }
+              ast::expr_fn(_, _, _, _) => {
+                visit::visit_expr(expr, depth + 1, v);
               }
               ast::expr_fn_block(*) => {
                 visit::visit_expr(expr, depth + 1, v);
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index 8abafe6b079..35d5595fefd 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -150,11 +150,23 @@ 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) {
-        ProtoUniq => b(check_for_uniq),
-        ProtoBox => b(check_for_box),
-        ProtoBare => b(check_for_bare),
-        ProtoBorrowed => b(check_for_block),
+    match ty::get(fty).sty {
+        ty::ty_closure(ty::ClosureTy {sigil: OwnedSigil, _}) => {
+            b(check_for_uniq)
+        }
+        ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, _}) => {
+            b(check_for_box)
+        }
+        ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, _}) => {
+            b(check_for_block)
+        }
+        ty::ty_bare_fn(_) => {
+            b(check_for_bare)
+        }
+        ref s => {
+            cx.tcx.sess.bug(
+                fmt!("expect fn type in kind checker, not %?", s));
+        }
     }
 }
 
@@ -240,42 +252,6 @@ pub fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
                        expr.span,
                        "explicit copy requires a copyable argument");
         }
-        expr_rec(ref fields, def) | expr_struct(_, ref fields, def) => {
-            match def {
-                Some(ex) => {
-                    // All noncopyable fields must be overridden
-                    let t = ty::expr_ty(cx.tcx, ex);
-                    let ty_fields = match ty::get(t).sty {
-                        ty::ty_rec(ref f) => {
-                            copy *f
-                        }
-                        ty::ty_struct(did, ref substs) => {
-                            ty::struct_fields(cx.tcx, did, substs)
-                        }
-                        _ => {
-                            cx.tcx.sess.span_bug(
-                                ex.span,
-                                ~"bad base expr type in record")
-                        }
-                    };
-                    for ty_fields.each |tf| {
-                        // If this field would not be copied, ok.
-                        if fields.any(|f| f.node.ident == tf.ident) { loop; }
-
-                        // If this field is copyable, ok.
-                        let kind = ty::type_kind(cx.tcx, tf.mt.ty);
-                        if ty::kind_can_be_copied(kind) { loop; }
-
-                        cx.tcx.sess.span_err(
-                            e.span,
-                            fmt!("cannot copy field `%s` of base expression, \
-                                  which has a noncopyable type",
-                                 *cx.tcx.sess.intr().get(tf.ident)));
-                    }
-                }
-                _ => {}
-            }
-        }
         expr_repeat(element, count_expr, _) => {
             let count = ty::eval_repeat_count(cx.tcx, count_expr, e.span);
             if count > 1 {
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index 4601941f73a..51bbdfdc19c 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -897,9 +897,10 @@ fn check_fn(tcx: ty::ctxt, fk: visit::fn_kind, decl: ast::fn_decl,
 fn check_fn_deprecated_modes(tcx: ty::ctxt, fn_ty: ty::t, decl: ast::fn_decl,
                              span: span, id: ast::node_id) {
     match ty::get(fn_ty).sty {
-        ty::ty_fn(ref fn_ty) => {
+        ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) |
+        ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) => {
             let mut counter = 0;
-            for vec::each2(fn_ty.sig.inputs, decl.inputs) |arg_ty, arg_ast| {
+            for vec::each2(sig.inputs, decl.inputs) |arg_ty, arg_ast| {
                 counter += 1;
                 debug!("arg %d, ty=%s, mode=%s",
                        counter,
@@ -938,13 +939,14 @@ fn check_fn_deprecated_modes(tcx: ty::ctxt, fn_ty: ty::t, decl: ast::fn_decl,
                 }
 
                 match ty::get(arg_ty.ty).sty {
-                    ty::ty_fn(*) => {
+                    ty::ty_closure(*) | ty::ty_bare_fn(*) => {
                         let span = arg_ast.ty.span;
                         // Recurse to check fn-type argument
                         match arg_ast.ty.node {
-                            ast::ty_fn(f) => {
+                            ast::ty_closure(@ast::TyClosure{decl: ref d, _}) |
+                            ast::ty_bare_fn(@ast::TyBareFn{decl: ref d, _})=>{
                                 check_fn_deprecated_modes(tcx, arg_ty.ty,
-                                                          f.decl, span, id);
+                                                          *d, span, id);
                             }
                             ast::ty_path(*) => {
                                 // This is probably a typedef, so we can't
@@ -976,10 +978,11 @@ fn check_item_deprecated_modes(tcx: ty::ctxt, it: @ast::item) {
     match it.node {
         ast::item_ty(ty, _) => {
             match ty.node {
-                ast::ty_fn(f) => {
+                ast::ty_closure(@ast::TyClosure {decl: ref decl, _}) |
+                ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => {
                     let fn_ty = ty::node_id_to_type(tcx, it.id);
                     check_fn_deprecated_modes(
-                        tcx, fn_ty, f.decl, ty.span, it.id)
+                        tcx, fn_ty, *decl, ty.span, it.id)
                 }
                 _ => ()
             }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index abe8a64fea5..07de9987096 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -146,63 +146,55 @@ pub enum deref_kind {deref_ptr(ptr_kind), deref_comp(comp_kind)}
 // pointer adjustment).
 pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
     match ty::get(t).sty {
-      ty::ty_uniq(*) |
-      ty::ty_evec(_, ty::vstore_uniq) |
-      ty::ty_estr(ty::vstore_uniq) => {
-        Some(deref_ptr(uniq_ptr))
-      }
-
-      ty::ty_fn(ref f) if (*f).meta.proto == ast::ProtoUniq => {
-        Some(deref_ptr(uniq_ptr))
-      }
-
-      ty::ty_rptr(r, mt) |
-      ty::ty_evec(mt, ty::vstore_slice(r)) => {
-        Some(deref_ptr(region_ptr(mt.mutbl, r)))
-      }
-
-      ty::ty_estr(ty::vstore_slice(r)) => {
-        Some(deref_ptr(region_ptr(ast::m_imm, r)))
-      }
+        ty::ty_uniq(*) |
+        ty::ty_evec(_, ty::vstore_uniq) |
+        ty::ty_estr(ty::vstore_uniq) |
+        ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
+            Some(deref_ptr(uniq_ptr))
+        }
 
-      ty::ty_fn(ref f) if (*f).meta.proto == ast::ProtoBorrowed => {
-        Some(deref_ptr(region_ptr(ast::m_imm, (*f).meta.region)))
-      }
+        ty::ty_rptr(r, mt) |
+        ty::ty_evec(mt, ty::vstore_slice(r)) => {
+            Some(deref_ptr(region_ptr(mt.mutbl, r)))
+        }
 
-      ty::ty_box(mt) |
-      ty::ty_evec(mt, ty::vstore_box) => {
-        Some(deref_ptr(gc_ptr(mt.mutbl)))
-      }
+        ty::ty_estr(ty::vstore_slice(r)) |
+        ty::ty_closure(ty::ClosureTy {sigil: ast::BorrowedSigil,
+                                      region: r, _}) => {
+            Some(deref_ptr(region_ptr(ast::m_imm, r)))
+        }
 
-      ty::ty_estr(ty::vstore_box) => {
-        Some(deref_ptr(gc_ptr(ast::m_imm)))
-      }
+        ty::ty_box(mt) |
+        ty::ty_evec(mt, ty::vstore_box) => {
+            Some(deref_ptr(gc_ptr(mt.mutbl)))
+        }
 
-      ty::ty_fn(ref f) if (*f).meta.proto == ast::ProtoBox => {
-        Some(deref_ptr(gc_ptr(ast::m_imm)))
-      }
+        ty::ty_estr(ty::vstore_box) |
+        ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
+            Some(deref_ptr(gc_ptr(ast::m_imm)))
+        }
 
-      ty::ty_ptr(*) => {
-        Some(deref_ptr(unsafe_ptr))
-      }
+        ty::ty_ptr(*) => {
+            Some(deref_ptr(unsafe_ptr))
+        }
 
-      ty::ty_enum(did, _) => {
-        Some(deref_comp(comp_variant(did)))
-      }
+        ty::ty_enum(did, _) => {
+            Some(deref_comp(comp_variant(did)))
+        }
 
-      ty::ty_struct(_, _) => {
-        Some(deref_comp(comp_anon_field))
-      }
+        ty::ty_struct(_, _) => {
+            Some(deref_comp(comp_anon_field))
+        }
 
-      ty::ty_evec(mt, ty::vstore_fixed(_)) => {
-        Some(deref_comp(comp_index(t, mt.mutbl)))
-      }
+        ty::ty_evec(mt, ty::vstore_fixed(_)) => {
+            Some(deref_comp(comp_index(t, mt.mutbl)))
+        }
 
-      ty::ty_estr(ty::vstore_fixed(_)) => {
-        Some(deref_comp(comp_index(t, m_imm)))
-      }
+        ty::ty_estr(ty::vstore_fixed(_)) => {
+            Some(deref_comp(comp_index(t, m_imm)))
+        }
 
-      _ => None
+        _ => None
     }
 }
 
@@ -473,9 +465,9 @@ pub impl &mem_categorization_ctxt {
 
           ast::def_upvar(_, inner, fn_node_id, _) => {
             let ty = ty::node_id_to_type(self.tcx, fn_node_id);
-            let proto = ty::ty_fn_proto(ty);
-            match proto {
-                ast::ProtoBorrowed => {
+            let sigil = ty::ty_closure_sigil(ty);
+            match sigil {
+                ast::BorrowedSigil => {
                     let upcmt = self.cat_def(id, span, expr_ty, *inner);
                     @cmt_ {
                         id:id,
@@ -486,7 +478,7 @@ pub impl &mem_categorization_ctxt {
                         ty:upcmt.ty
                     }
                 }
-                ast::ProtoUniq | ast::ProtoBox => {
+                ast::OwnedSigil | ast::ManagedSigil => {
                     // FIXME #2152 allow mutation of moved upvars
                     @cmt_ {
                         id:id,
@@ -497,11 +489,6 @@ pub impl &mem_categorization_ctxt {
                         ty:expr_ty
                     }
                 }
-                ast::ProtoBare => {
-                    self.tcx.sess.span_bug(
-                        span,
-                        fmt!("Upvar in a bare closure?"));
-                }
             }
           }
 
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
index f7943d6edc0..aaa3156e27c 100644
--- a/src/librustc/middle/moves.rs
+++ b/src/librustc/middle/moves.rs
@@ -474,7 +474,35 @@ impl VisitContext {
                 }
 
                 for opt_with.each |with_expr| {
-                    self.consume_expr(*with_expr, visitor);
+                    // If there are any fields whose type is move-by-default,
+                    // then `with` is consumed, otherwise it is only read
+                    let with_ty = ty::expr_ty(self.tcx, *with_expr);
+                    let with_fields = match ty::get(with_ty).sty {
+                        ty::ty_rec(ref f) => copy *f,
+                        ty::ty_struct(did, ref substs) => {
+                            ty::struct_fields(self.tcx, did, substs)
+                        }
+                        ref r => {
+                           self.tcx.sess.span_bug(
+                                with_expr.span,
+                                fmt!("bad base expr type in record: %?", r))
+                        }
+                    };
+
+                    // The `with` expr must be consumed if it contains
+                    // any fields which (1) were not explicitly
+                    // specified and (2) have a type that
+                    // moves-by-default:
+                    let consume_with = with_fields.any(|tf| {
+                        !fields.any(|f| f.node.ident == tf.ident) &&
+                            ty::type_implicitly_moves(self.tcx, tf.mt.ty)
+                    });
+
+                    if consume_with {
+                        self.consume_expr(*with_expr, visitor);
+                    } else {
+                        self.use_expr(*with_expr, Read, visitor);
+                    }
                 }
             }
 
@@ -786,9 +814,9 @@ impl VisitContext {
         let _indenter = indenter();
 
         let fn_ty = ty::node_id_to_type(self.tcx, fn_expr_id);
-        let proto = ty::ty_fn_proto(fn_ty);
+        let sigil = ty::ty_closure_sigil(fn_ty);
         let freevars = freevars::get_freevars(self.tcx, fn_expr_id);
-        if proto == ProtoBorrowed {
+        if sigil == BorrowedSigil {
             // &fn() captures everything by ref
             at_vec::from_fn(freevars.len(), |i| {
                 let fvar = &freevars[i];
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 867cc7c686f..68e41b329e3 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -657,7 +657,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
             }
         }
 
-        ast::ty_fn(f) => {
+        ast::ty_closure(ref f) => {
             debug!("referenced fn type: %s",
                    pprust::ty_to_str(ty, cx.sess.intr()));
             match f.region {
@@ -668,7 +668,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
                     }
                 }
                 None => {
-                    if f.proto == ast::ProtoBorrowed && cx.anon_implies_rp {
+                    if f.sigil == ast::BorrowedSigil && cx.anon_implies_rp {
                         cx.add_rp(cx.item_id,
                                   cx.add_variance(rv_contravariant));
                     }
@@ -732,18 +732,18 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
         }
       }
 
-      ast::ty_fn(f) => {
+      ast::ty_closure(@ast::TyClosure {decl: ref decl, _}) |
+      ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => {
         // 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 f.decl.inputs.each |a| {
+                for decl.inputs.each |a| {
                     (visitor.visit_ty)(a.ty, cx, visitor);
                 }
             }
-            visit::visit_ty_param_bounds(f.bounds, cx, visitor);
-            (visitor.visit_ty)(f.decl.output, cx, visitor);
+            (visitor.visit_ty)(decl.output, cx, visitor);
         }
       }
 
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 99b5641ac6a..ebd6d9f9056 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -1652,7 +1652,7 @@ pub fn trans_match_inner(scope_cx: block,
         // insert bindings into the lllocals map and add cleanups
         bcx = insert_lllocals(bcx, *arm_data, true);
 
-        bcx = controlflow::trans_block(bcx, arm_data.arm.body, dest);
+        bcx = controlflow::trans_block(bcx, &arm_data.arm.body, dest);
         bcx = trans_block_cleanups(bcx, block_cleanups(arm_data.bodycx));
         arm_cxs.push(bcx);
     }
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index a1f863332bd..588e2916e47 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -613,7 +613,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t,
         let ccx = cx.ccx();
         let mut cx = cx;
         match ty::get(fn_ty).sty {
-          ty::ty_fn(ref fn_ty) => {
+          ty::ty_bare_fn(ref fn_ty) => {
             let mut j = 0u;
             let v_id = variant.id;
             for vec::each(fn_ty.sig.inputs) |a| {
@@ -777,10 +777,10 @@ pub fn trans_external_path(ccx: @crate_ctxt, did: ast::def_id, t: ty::t)
     -> ValueRef {
     let name = csearch::get_symbol(ccx.sess.cstore, did).to_managed(); // Sad
     match ty::get(t).sty {
-      ty::ty_fn(_) => {
+      ty::ty_bare_fn(_) | ty::ty_closure(_) => {
         let llty = type_of_fn_from_ty(ccx, t);
         return get_extern_fn(ccx.externs, ccx.llmod, name,
-                          lib::llvm::CCallConv, llty);
+                             lib::llvm::CCallConv, llty);
       }
       _ => {
         let llty = type_of(ccx, t);
@@ -1363,7 +1363,7 @@ pub fn with_scope_datumblock(bcx: block, opt_node_info: Option<node_info>,
     DatumBlock {bcx: leave_block(bcx, scope_cx), datum: datum}
 }
 
-pub fn block_locals(b: ast::blk, it: fn(@ast::local)) {
+pub fn block_locals(b: &ast::blk, it: fn(@ast::local)) {
     for vec::each(b.node.stmts) |s| {
         match s.node {
           ast::stmt_decl(d, _) => {
@@ -1727,8 +1727,8 @@ pub enum self_arg { impl_self(ty::t), impl_owned_self(ty::t), no_self, }
 // returned.
 pub fn trans_closure(ccx: @crate_ctxt,
                      +path: path,
-                     decl: ast::fn_decl,
-                     body: ast::blk,
+                     decl: &ast::fn_decl,
+                     body: &ast::blk,
                      llfndecl: ValueRef,
                      ty_self: self_arg,
                      +param_substs: Option<param_substs>,
@@ -1791,8 +1791,8 @@ pub fn trans_closure(ccx: @crate_ctxt,
 // function.
 pub fn trans_fn(ccx: @crate_ctxt,
                 +path: path,
-                decl: ast::fn_decl,
-                body: ast::blk,
+                decl: &ast::fn_decl,
+                body: &ast::blk,
                 llfndecl: ValueRef,
                 ty_self: self_arg,
                 +param_substs: Option<param_substs>,
@@ -1935,7 +1935,7 @@ pub fn trans_tuple_struct(ccx: @crate_ctxt,
 
 pub fn trans_struct_dtor(ccx: @crate_ctxt,
                          +path: path,
-                         body: ast::blk,
+                         body: &ast::blk,
                          dtor_id: ast::node_id,
                          +psubsts: Option<param_substs>,
                          hash_id: Option<mono_id>,
@@ -1966,8 +1966,9 @@ pub fn trans_struct_dtor(ccx: @crate_ctxt,
     ccx.monomorphized.insert(*h_id, lldecl);
   }
   /* Translate the dtor body */
-  trans_fn(ccx, path, ast_util::dtor_dec(),
-           body, lldecl, impl_self(class_ty), psubsts, dtor_id, None);
+  let decl = ast_util::dtor_dec();
+  trans_fn(ccx, path, &decl, body, lldecl,
+           impl_self(class_ty), psubsts, dtor_id, None);
   lldecl
 }
 
@@ -2013,20 +2014,19 @@ pub fn trans_item(ccx: @crate_ctxt, item: ast::item) {
         _ => die!(~"trans_item"),
     };
     match /*bad*/copy item.node {
-      // XXX: Bad copies.
-      ast::item_fn(copy decl, purity, copy tps, ref body) => {
+      ast::item_fn(ref decl, purity, ref tps, ref body) => {
         if purity == ast::extern_fn  {
             let llfndecl = get_item_val(ccx, item.id);
             foreign::trans_foreign_fn(ccx,
                                      vec::append(
                                          /*bad*/copy *path,
                                          ~[path_name(item.ident)]),
-                                     decl, (*body), llfndecl, item.id);
+                                      decl, body, llfndecl, item.id);
         } else if tps.is_empty() {
             let llfndecl = get_item_val(ccx, item.id);
             trans_fn(ccx,
                      vec::append(/*bad*/copy *path, ~[path_name(item.ident)]),
-                     decl, (*body), llfndecl, no_self, None, item.id, None);
+                     decl, body, llfndecl, no_self, None, item.id, None);
         } else {
             for vec::each((*body).node.stmts) |stmt| {
                 match stmt.node {
@@ -2078,7 +2078,7 @@ pub fn trans_struct_def(ccx: @crate_ctxt, struct_def: @ast::struct_def,
                         id: ast::node_id) {
     // Translate the destructor.
     do option::iter(&struct_def.dtor) |dtor| {
-        trans_struct_dtor(ccx, /*bad*/copy *path, dtor.node.body,
+        trans_struct_dtor(ccx, /*bad*/copy *path, &dtor.node.body,
                          dtor.node.id, None, None, local_def(id));
     };
 
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index 4bd5ae969f2..4af74b3623f 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -627,18 +627,17 @@ pub fn trans_arg_expr(bcx: block,
         Some(_) => {
             match arg_expr.node {
                 ast::expr_loop_body(
-                    // XXX: Bad copy.
-                    blk@@ast::expr {
-                        node: ast::expr_fn_block(copy decl, ref body),
+                    blk @ @ast::expr {
+                        node: ast::expr_fn_block(ref decl, ref body),
                         _
                     }) =>
                 {
                     let scratch_ty = expr_ty(bcx, arg_expr);
                     let scratch = alloc_ty(bcx, scratch_ty);
                     let arg_ty = expr_ty(bcx, arg_expr);
-                    let proto = ty::ty_fn_proto(arg_ty);
+                    let sigil = ty::ty_closure_sigil(arg_ty);
                     let bcx = closure::trans_expr_fn(
-                        bcx, proto, decl, /*bad*/copy *body, arg_expr.id,
+                        bcx, sigil, decl, body, arg_expr.id,
                         blk.id, Some(ret_flag), expr::SaveIn(scratch));
                     DatumBlock {bcx: bcx,
                                 datum: Datum {val: scratch,
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index 62e00100d6c..c70425da9fa 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -160,7 +160,7 @@ pub fn mk_closure_tys(tcx: ty::ctxt,
     return cdata_ty;
 }
 
-pub fn allocate_cbox(bcx: block, proto: ast::Proto, cdata_ty: ty::t)
+pub fn allocate_cbox(bcx: block, sigil: ast::Sigil, cdata_ty: ty::t)
                   -> Result {
     let _icx = bcx.insn_ctxt("closure::allocate_cbox");
     let ccx = bcx.ccx(), tcx = ccx.tcx;
@@ -176,23 +176,19 @@ pub fn allocate_cbox(bcx: block, proto: ast::Proto, cdata_ty: ty::t)
     }
 
     // Allocate and initialize the box:
-    match proto {
-        ast::ProtoBox => {
+    match sigil {
+        ast::ManagedSigil => {
             malloc_raw(bcx, cdata_ty, heap_shared)
         }
-        ast::ProtoUniq => {
+        ast::OwnedSigil => {
             malloc_raw(bcx, cdata_ty, heap_exchange)
         }
-        ast::ProtoBorrowed => {
+        ast::BorrowedSigil => {
             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))
-        }
     }
 }
 
@@ -208,7 +204,7 @@ pub type closure_result = {
 // Otherwise, it is stack allocated and copies pointers to the upvars.
 pub fn store_environment(bcx: block,
                          bound_values: ~[EnvValue],
-                         proto: ast::Proto) -> closure_result {
+                         sigil: ast::Sigil) -> closure_result {
     let _icx = bcx.insn_ctxt("closure::store_environment");
     let ccx = bcx.ccx(), tcx = ccx.tcx;
 
@@ -217,7 +213,7 @@ pub fn store_environment(bcx: block,
     let cdata_ty = mk_closure_tys(tcx, copy bound_values);
 
     // allocate closure in the heap
-    let Result {bcx: bcx, val: llbox} = allocate_cbox(bcx, proto, cdata_ty);
+    let Result {bcx: bcx, val: llbox} = allocate_cbox(bcx, sigil, cdata_ty);
     let mut temp_cleanups = ~[];
 
     // cbox_ty has the form of a tuple: (a, b, c) we want a ptr to a
@@ -265,7 +261,7 @@ pub fn store_environment(bcx: block,
 // collects the upvars and packages them up for store_environment.
 pub fn build_closure(bcx0: block,
                      cap_vars: &[moves::CaptureVar],
-                     proto: ast::Proto,
+                     sigil: ast::Sigil,
                      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
@@ -279,7 +275,7 @@ pub fn build_closure(bcx0: block,
         let datum = expr::trans_local_var(bcx, cap_var.def);
         match cap_var.mode {
             moves::CapRef => {
-                assert proto == ast::ProtoBorrowed;
+                assert sigil == ast::BorrowedSigil;
                 env_vals.push(EnvValue {action: EnvRef,
                                         datum: datum});
             }
@@ -316,7 +312,7 @@ pub fn build_closure(bcx0: block,
                                 datum: ret_datum});
     }
 
-    return store_environment(bcx, env_vals, proto);
+    return store_environment(bcx, env_vals, sigil);
 }
 
 // Given an enclosing block context, a new function context, a closure type,
@@ -326,7 +322,7 @@ pub fn load_environment(fcx: fn_ctxt,
                         cdata_ty: ty::t,
                         cap_vars: &[moves::CaptureVar],
                         load_ret_handle: bool,
-                        proto: ast::Proto) {
+                        sigil: ast::Sigil) {
     let _icx = fcx.insn_ctxt("closure::load_environment");
 
     let llloadenv = match fcx.llloadenv {
@@ -352,9 +348,9 @@ pub fn load_environment(fcx: fn_ctxt,
     let mut i = 0u;
     for cap_vars.each |cap_var| {
         let mut upvarptr = GEPi(bcx, llcdata, [0u, i]);
-        match proto {
-            ast::ProtoBorrowed => { upvarptr = Load(bcx, upvarptr); }
-            ast::ProtoBox | ast::ProtoUniq | ast::ProtoBare => {}
+        match sigil {
+            ast::BorrowedSigil => { upvarptr = Load(bcx, upvarptr); }
+            ast::ManagedSigil | ast::OwnedSigil => {}
         }
         let def_id = ast_util::def_id_of_def(cap_var.def);
         fcx.llupvars.insert(def_id.node, upvarptr);
@@ -369,9 +365,9 @@ pub fn load_environment(fcx: fn_ctxt,
 }
 
 pub fn trans_expr_fn(bcx: block,
-                     proto: ast::Proto,
-                     +decl: ast::fn_decl,
-                     +body: ast::blk,
+                     sigil: ast::Sigil,
+                     decl: &ast::fn_decl,
+                     body: &ast::blk,
                      outer_id: ast::node_id,
                      user_id: ast::node_id,
                      is_loop_body: Option<Option<ValueRef>>,
@@ -381,7 +377,7 @@ pub fn trans_expr_fn(bcx: block,
      *
      * Translates the body of a closure expression.
      *
-     * - `proto`
+     * - `sigil`
      * - `decl`
      * - `body`
      * - `outer_id`: The id of the closure expression with the correct
@@ -417,18 +413,18 @@ pub fn trans_expr_fn(bcx: block,
                                                  ~"expr_fn");
     let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
 
-    let Result {bcx: bcx, val: closure} = match proto {
-        ast::ProtoBorrowed | ast::ProtoBox | ast::ProtoUniq => {
+    let Result {bcx: bcx, val: closure} = match sigil {
+        ast::BorrowedSigil | ast::ManagedSigil | ast::OwnedSigil => {
             let cap_vars = ccx.maps.capture_map.get(&user_id);
             let ret_handle = match is_loop_body {Some(x) => x,
                                                  None => None};
-            let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, proto,
+            let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, sigil,
                                                        ret_handle);
             trans_closure(ccx, sub_path, decl,
                           body, llfn, no_self,
                           /*bad*/ copy bcx.fcx.param_substs, user_id, None,
                           |fcx| load_environment(fcx, cdata_ty, cap_vars,
-                                                 ret_handle.is_some(), proto),
+                                                 ret_handle.is_some(), sigil),
                           |bcx| {
                               if is_loop_body.is_some() {
                                   Store(bcx, C_bool(true), bcx.fcx.llretptr);
@@ -436,34 +432,30 @@ pub fn trans_expr_fn(bcx: block,
                           });
             rslt(bcx, llbox)
         }
-        ast::ProtoBare => {
-            trans_closure(ccx, sub_path, decl, body, llfn, no_self, None,
-                          user_id, None, |_fcx| { }, |_bcx| { });
-            rslt(bcx, C_null(T_opaque_box_ptr(ccx)))
-        }
     };
     fill_fn_pair(bcx, dest_addr, llfn, closure);
 
     return bcx;
 }
 
-pub fn make_fn_glue(cx: block,
-                    v: ValueRef,
-                    t: ty::t,
-                    glue_fn: fn@(block, v: ValueRef, t: ty::t) -> block)
-                 -> block {
-    let _icx = cx.insn_ctxt("closure::make_fn_glue");
+pub fn make_closure_glue(
+    cx: block,
+    v: ValueRef,
+    t: ty::t,
+    glue_fn: fn@(block, v: ValueRef, t: ty::t) -> block) -> block
+{
+    let _icx = cx.insn_ctxt("closure::make_closure_glue");
     let bcx = cx;
     let tcx = cx.tcx();
 
-    let proto = ty::ty_fn_proto(t);
-    match proto {
-        ast::ProtoBare | ast::ProtoBorrowed => bcx,
-        ast::ProtoUniq | ast::ProtoBox => {
+    let sigil = ty::ty_closure_sigil(t);
+    match sigil {
+        ast::BorrowedSigil => bcx,
+        ast::OwnedSigil | ast::ManagedSigil => {
             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);
+                let closure_ty = ty::mk_opaque_closure_ptr(tcx, sigil);
                 glue_fn(bcx, box_cell_v, closure_ty)
             }
         }
@@ -472,20 +464,20 @@ pub fn make_fn_glue(cx: block,
 
 pub fn make_opaque_cbox_take_glue(
     bcx: block,
-    proto: ast::Proto,
+    sigil: ast::Sigil,
     cboxptr: ValueRef)     // ptr to ptr to the opaque closure
     -> block {
     // Easy cases:
     let _icx = bcx.insn_ctxt("closure::make_opaque_cbox_take_glue");
-    match proto {
-        ast::ProtoBare | ast::ProtoBorrowed => {
+    match sigil {
+        ast::BorrowedSigil => {
             return bcx;
         }
-        ast::ProtoBox => {
+        ast::ManagedSigil => {
             glue::incr_refcnt_of_boxed(bcx, Load(bcx, cboxptr));
             return bcx;
         }
-        ast::ProtoUniq => {
+        ast::OwnedSigil => {
             /* hard case: fallthrough to code below */
         }
     }
@@ -531,36 +523,36 @@ pub fn make_opaque_cbox_take_glue(
 
 pub fn make_opaque_cbox_drop_glue(
     bcx: block,
-    proto: ast::Proto,
+    sigil: ast::Sigil,
     cboxptr: ValueRef)     // ptr to the opaque closure
     -> block {
     let _icx = bcx.insn_ctxt("closure::make_opaque_cbox_drop_glue");
-    match proto {
-        ast::ProtoBare | ast::ProtoBorrowed => bcx,
-        ast::ProtoBox => {
+    match sigil {
+        ast::BorrowedSigil => bcx,
+        ast::ManagedSigil => {
             glue::decr_refcnt_maybe_free(
                 bcx, Load(bcx, cboxptr),
-                ty::mk_opaque_closure_ptr(bcx.tcx(), proto))
+                ty::mk_opaque_closure_ptr(bcx.tcx(), sigil))
         }
-        ast::ProtoUniq => {
+        ast::OwnedSigil => {
             glue::free_ty(
                 bcx, cboxptr,
-                ty::mk_opaque_closure_ptr(bcx.tcx(), proto))
+                ty::mk_opaque_closure_ptr(bcx.tcx(), sigil))
         }
     }
 }
 
 pub fn make_opaque_cbox_free_glue(
     bcx: block,
-    proto: ast::Proto,
+    sigil: ast::Sigil,
     cbox: ValueRef)     // ptr to ptr to the opaque closure
     -> block {
     let _icx = bcx.insn_ctxt("closure::make_opaque_cbox_free_glue");
-    match proto {
-        ast::ProtoBare | ast::ProtoBorrowed => {
+    match sigil {
+        ast::BorrowedSigil => {
             return bcx;
         }
-        ast::ProtoBox | ast::ProtoUniq => {
+        ast::ManagedSigil | ast::OwnedSigil => {
             /* hard cases: fallthrough to code below */
         }
     }
@@ -580,10 +572,10 @@ pub fn make_opaque_cbox_free_glue(
                                     abi::tydesc_field_drop_glue, None);
 
         // Free the ty descr (if necc) and the box itself
-        match proto {
-            ast::ProtoBox => glue::trans_free(bcx, cbox),
-            ast::ProtoUniq => glue::trans_unique_free(bcx, cbox),
-            ast::ProtoBare | ast::ProtoBorrowed => {
+        match sigil {
+            ast::ManagedSigil => glue::trans_free(bcx, cbox),
+            ast::OwnedSigil => glue::trans_unique_free(bcx, cbox),
+            ast::BorrowedSigil => {
                 bcx.sess().bug(~"impossible")
             }
         }
diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs
index a1505dd2f11..0933eedd5e4 100644
--- a/src/librustc/middle/trans/controlflow.rs
+++ b/src/librustc/middle/trans/controlflow.rs
@@ -23,7 +23,7 @@ pub fn macros() {
     include!("macros.rs");
 }
 
-pub fn trans_block(bcx: block, b: ast::blk, dest: expr::Dest) -> block {
+pub fn trans_block(bcx: block, b: &ast::blk, dest: expr::Dest) -> block {
     let _icx = bcx.insn_ctxt("trans_block");
     let mut bcx = bcx;
     do block_locals(b) |local| {
@@ -47,7 +47,7 @@ pub fn trans_block(bcx: block, b: ast::blk, dest: expr::Dest) -> block {
 
 pub fn trans_if(bcx: block,
             cond: @ast::expr,
-            thn: ast::blk,
+            thn: &ast::blk,
             els: Option<@ast::expr>,
             dest: expr::Dest)
          -> block {
@@ -82,10 +82,10 @@ pub fn trans_if(bcx: block,
         match elexpr.node {
           ast::expr_if(_, _, _) => {
             let elseif_blk = ast_util::block_from_expr(elexpr);
-            trans_block(else_bcx_in, elseif_blk, dest)
+            trans_block(else_bcx_in, &elseif_blk, dest)
           }
           ast::expr_block(ref blk) => {
-            trans_block(else_bcx_in, (*blk), dest)
+            trans_block(else_bcx_in, blk, dest)
           }
           // would be nice to have a constraint on ifs
           _ => bcx.tcx().sess.bug(~"strange alternative in if")
@@ -114,7 +114,7 @@ pub fn join_blocks(parent_bcx: block, in_cxs: ~[block]) -> block {
     return out;
 }
 
-pub fn trans_while(bcx: block, cond: @ast::expr, body: ast::blk) -> block {
+pub fn trans_while(bcx: block, cond: @ast::expr, body: &ast::blk) -> block {
     let _icx = bcx.insn_ctxt("trans_while");
     let next_bcx = sub_block(bcx, ~"while next");
 
@@ -154,7 +154,7 @@ pub fn trans_while(bcx: block, cond: @ast::expr, body: ast::blk) -> block {
 }
 
 pub fn trans_loop(bcx:block,
-                  body: ast::blk,
+                  body: &ast::blk,
                   opt_label: Option<ident>)
                -> block {
     let _icx = bcx.insn_ctxt("trans_loop");
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 56833d373c5..f2da47eb0ec 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -475,10 +475,10 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
             return controlflow::trans_check_expr(bcx, expr, a, ~"Assertion");
         }
         ast::expr_while(cond, ref body) => {
-            return controlflow::trans_while(bcx, cond, (*body));
+            return controlflow::trans_while(bcx, cond, body);
         }
         ast::expr_loop(ref body, opt_label) => {
-            return controlflow::trans_loop(bcx, (*body), opt_label);
+            return controlflow::trans_loop(bcx, body, opt_label);
         }
         ast::expr_assign(dst, src) => {
             let src_datum = unpack_datum!(
@@ -530,7 +530,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
                                             bcx.def(expr.id), dest);
         }
         ast::expr_if(cond, ref thn, els) => {
-            return controlflow::trans_if(bcx, cond, *thn, els, dest);
+            return controlflow::trans_if(bcx, cond, thn, els, dest);
         }
         ast::expr_match(discr, ref arms) => {
             return _match::trans_match(bcx, expr, discr, /*bad*/copy *arms,
@@ -539,7 +539,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
         ast::expr_block(ref blk) => {
             return do base::with_scope(bcx, blk.info(),
                                        ~"block-expr body") |bcx| {
-                controlflow::trans_block(bcx, (*blk), dest)
+                controlflow::trans_block(bcx, blk, dest)
             };
         }
         ast::expr_rec(ref fields, base) |
@@ -562,58 +562,31 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
         ast::expr_vec(*) | ast::expr_repeat(*) => {
             return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
         }
-        // XXX: Bad copy.
-        ast::expr_fn(proto, copy decl, ref body, _) => {
-            // Don't use this function for anything real. Use the one in
-            // astconv instead.
-            return closure::trans_expr_fn(bcx, proto, decl,
-                                          /*bad*/copy *body,
-                                          expr.id, expr.id,
-                                          None, dest);
-        }
+        ast::expr_fn(_, ref decl, ref body, _) |
         ast::expr_fn_block(ref decl, ref body) => {
             let expr_ty = expr_ty(bcx, expr);
-            match ty::get(expr_ty).sty {
-                ty::ty_fn(ref fn_ty) => {
-                    debug!("translating fn_block %s with type %s",
-                           expr_to_str(expr, tcx.sess.intr()),
-                           ty_to_str(tcx, expr_ty));
-                    return closure::trans_expr_fn(
-                        bcx, fn_ty.meta.proto, /*bad*/copy *decl,
-                        /*bad*/copy *body, expr.id, expr.id,
-                        None, dest);
-                }
-                _ => {
-                    bcx.sess().impossible_case(
-                        expr.span, "fn_block has body with a non-fn type");
-                }
-            }
+            let sigil = ty::ty_closure_sigil(expr_ty);
+            debug!("translating fn_block %s with type %s",
+                   expr_to_str(expr, tcx.sess.intr()),
+                   ty_to_str(tcx, expr_ty));
+            return closure::trans_expr_fn(bcx, sigil, decl, body,
+                                          expr.id, expr.id,
+                                          None, dest);
         }
         ast::expr_loop_body(blk) => {
-            match ty::get(expr_ty(bcx, expr)).sty {
-                ty::ty_fn(ref fn_ty) => {
-                    match blk.node {
-                        ast::expr_fn_block(copy decl, ref body) => {
-                            return closure::trans_expr_fn(
-                                bcx,
-                                fn_ty.meta.proto,
-                                decl,
-                                /*bad*/copy *body,
-                                expr.id,
-                                blk.id,
-                                Some(None),
-                                dest);
-                        }
-                        _ => {
-                            bcx.sess().impossible_case(
-                                expr.span,
-                                "loop_body has the wrong kind of contents")
-                        }
-                    }
+            let expr_ty = expr_ty(bcx, expr);
+            let sigil = ty::ty_closure_sigil(expr_ty);
+            match blk.node {
+                ast::expr_fn_block(ref decl, ref body) => {
+                    return closure::trans_expr_fn(bcx, sigil,
+                                                  decl, body,
+                                                  expr.id, blk.id,
+                                                  Some(None), dest);
                 }
                 _ => {
                     bcx.sess().impossible_case(
-                        expr.span, "loop_body has body with a non-fn type")
+                        expr.span,
+                        "loop_body has the wrong kind of contents")
                 }
             }
         }
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index ae05ceb1ec5..bb14fce8053 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -31,7 +31,7 @@ use middle::trans::machine;
 use middle::trans::shape;
 use middle::trans::type_of::*;
 use middle::trans::type_of;
-use middle::ty::{FnTyBase, FnMeta, FnSig, arg};
+use middle::ty::{FnSig, arg};
 use util::ppaux::ty_to_str;
 
 use core::libc::c_uint;
@@ -66,10 +66,8 @@ type c_stack_tys = {
 fn c_arg_and_ret_lltys(ccx: @crate_ctxt,
                        id: ast::node_id) -> (~[TypeRef], TypeRef, ty::t) {
     match ty::get(ty::node_id_to_type(ccx.tcx, id)).sty {
-        ty::ty_fn(ref fn_ty) => {
-            let llargtys = type_of_explicit_args(
-                ccx,
-                fn_ty.sig.inputs);
+        ty::ty_bare_fn(ref fn_ty) => {
+            let llargtys = type_of_explicit_args(ccx, fn_ty.sig.inputs);
             let llretty = type_of::type_of(ccx, fn_ty.sig.output);
             (llargtys, llretty, fn_ty.sig.output)
         }
@@ -541,12 +539,11 @@ pub fn trans_intrinsic(ccx: @crate_ctxt,
             let star_u8 = ty::mk_imm_ptr(
                 bcx.tcx(),
                 ty::mk_mach_uint(bcx.tcx(), ast::ty_u8));
-            let fty = ty::mk_fn(bcx.tcx(), FnTyBase {
-                meta: FnMeta {purity: ast::impure_fn,
-                              proto: ast::ProtoBorrowed,
-                              onceness: ast::Many,
-                              region: ty::re_bound(ty::br_anon(0)),
-                              bounds: @~[]},
+            let fty = ty::mk_closure(bcx.tcx(), ty::ClosureTy {
+                purity: ast::impure_fn,
+                sigil: ast::BorrowedSigil,
+                onceness: ast::Many,
+                region: ty::re_bound(ty::br_anon(0)),
                 sig: FnSig {inputs: ~[arg {mode: ast::expl(ast::by_copy),
                                            ty: star_u8}],
                             output: ty::mk_nil(bcx.tcx())}
@@ -843,14 +840,14 @@ pub fn trans_intrinsic(ccx: @crate_ctxt,
 
 pub fn trans_foreign_fn(ccx: @crate_ctxt,
                         +path: ast_map::path,
-                        decl: ast::fn_decl,
-                        body: ast::blk,
+                        decl: &ast::fn_decl,
+                        body: &ast::blk,
                         llwrapfn: ValueRef,
                         id: ast::node_id) {
     let _icx = ccx.insn_ctxt("foreign::build_foreign_fn");
 
     fn build_rust_fn(ccx: @crate_ctxt, +path: ast_map::path,
-                     decl: ast::fn_decl, body: ast::blk,
+                     decl: &ast::fn_decl, body: &ast::blk,
                      id: ast::node_id) -> ValueRef {
         let _icx = ccx.insn_ctxt("foreign::foreign::build_rust_fn");
         let t = ty::node_id_to_type(ccx.tcx, id);
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index 9909980fb7e..564460fd88e 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -172,7 +172,8 @@ pub fn simplified_glue_type(tcx: ty::ctxt, field: uint, t: ty::t) -> ty::t {
 
     if field == abi::tydesc_field_free_glue {
         match ty::get(t).sty {
-          ty::ty_fn(*) |
+          ty::ty_bare_fn(*) |
+          ty::ty_closure(*) |
           ty::ty_box(*) |
           ty::ty_opaque_box |
           ty::ty_uniq(*) |
@@ -419,8 +420,8 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
                        tvec::expand_boxed_vec_ty(bcx.tcx(), t));
         return;
       }
-      ty::ty_fn(_) => {
-        closure::make_fn_glue(bcx, v, t, free_ty)
+      ty::ty_closure(_) => {
+        closure::make_closure_glue(bcx, v, t, free_ty)
       }
       ty::ty_opaque_closure_ptr(ck) => {
         closure::make_opaque_cbox_free_glue(bcx, ck, v)
@@ -528,8 +529,8 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
           }
         }
       }
-      ty::ty_fn(_) => {
-        closure::make_fn_glue(bcx, v0, t, drop_ty)
+      ty::ty_closure(_) => {
+        closure::make_closure_glue(bcx, v0, t, drop_ty)
       }
       ty::ty_trait(_, _, ty::vstore_box) => {
         let llbox = Load(bcx, GEPi(bcx, v0, [0u, 1u]));
@@ -594,8 +595,8 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
       | ty::ty_estr(ty::vstore_slice(_)) => {
         bcx
       }
-      ty::ty_fn(_) => {
-        closure::make_fn_glue(bcx, v, t, take_ty)
+      ty::ty_closure(_) => {
+        closure::make_closure_glue(bcx, v, t, take_ty)
       }
       ty::ty_trait(_, _, ty::vstore_box) => {
         let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u]));
diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs
index 4466e4e1b28..c094db4ecca 100644
--- a/src/librustc/middle/trans/inline.rs
+++ b/src/librustc/middle/trans/inline.rs
@@ -108,8 +108,8 @@ pub fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id,
                 };
                 trans_fn(ccx,
                          path,
-                         mth.decl,
-                         mth.body,
+                         &mth.decl,
+                         &mth.body,
                          llfn,
                          self_kind,
                          None,
diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs
index e76176218b7..828b5619390 100644
--- a/src/librustc/middle/trans/machine.rs
+++ b/src/librustc/middle/trans/machine.rs
@@ -34,8 +34,11 @@ pub fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t {
           ty::ty_box(_) | ty::ty_opaque_box | ty::ty_uniq(_) |
           ty::ty_evec(_, ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_box) |
           ty::ty_estr(ty::vstore_uniq) | ty::ty_estr(ty::vstore_box) |
-          ty::ty_ptr(_) | ty::ty_rptr(_,_) => nilptr(tcx),
-          ty::ty_fn(_) => ty::mk_tup(tcx, ~[nilptr(tcx), nilptr(tcx)]),
+          ty::ty_ptr(_) | ty::ty_rptr(*) => nilptr(tcx),
+
+          ty::ty_bare_fn(*) | // FIXME(#4804) Bare fn repr
+          ty::ty_closure(*) => ty::mk_tup(tcx, ~[nilptr(tcx), nilptr(tcx)]),
+
           ty::ty_evec(_, ty::vstore_slice(_)) |
           ty::ty_estr(ty::vstore_slice(_)) => {
             ty::mk_tup(tcx, ~[nilptr(tcx), ty::mk_int(tcx)])
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index d751b8f9208..1d48d2dde6b 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -142,8 +142,8 @@ pub fn trans_method(ccx: @crate_ctxt,
     // generate the actual code
     trans_fn(ccx,
              path,
-             method.decl,
-             method.body,
+             &method.decl,
+             &method.body,
              llfn,
              self_arg,
              param_substs,
@@ -822,7 +822,7 @@ pub fn make_impl_vtable(ccx: @crate_ctxt,
     let has_tps = (*ty::lookup_item_type(ccx.tcx, impl_id).bounds).len() > 0u;
     make_vtable(ccx, vec::map(*ty::trait_methods(tcx, trt_id), |im| {
         let fty = ty::subst_tps(tcx, substs, None,
-                                ty::mk_fn(tcx, copy im.fty));
+                                ty::mk_bare_fn(tcx, copy im.fty));
         if (*im.tps).len() > 0u || ty::type_has_self(fty) {
             debug!("(making impl vtable) method has self or type params: %s",
                    tcx.sess.str_of(im.ident));
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index 5873d0a76d9..b09a41f2b7f 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -26,7 +26,7 @@ use middle::trans::shape;
 use middle::trans::type_of::type_of_fn_from_ty;
 use middle::trans::type_of;
 use middle::trans::type_use;
-use middle::ty::{FnTyBase, FnMeta, FnSig};
+use middle::ty::{FnSig};
 use middle::typeck;
 
 use core::option;
@@ -166,12 +166,12 @@ pub fn monomorphic_fn(ccx: @crate_ctxt,
     let lldecl = match map_node {
       ast_map::node_item(i@@ast::item {
                 // XXX: Bad copy.
-                node: ast::item_fn(copy decl, _, _, ref body),
+                node: ast::item_fn(ref decl, _, _, ref body),
                 _
             }, _) => {
         let d = mk_lldecl();
         set_inline_hint_if_appr(/*bad*/copy i.attrs, d);
-        trans_fn(ccx, pt, decl, *body, d, no_self, psubsts, fn_id.node, None);
+        trans_fn(ccx, pt, decl, body, d, no_self, psubsts, fn_id.node, None);
         d
       }
       ast_map::node_item(*) => {
@@ -224,7 +224,7 @@ pub fn monomorphic_fn(ccx: @crate_ctxt,
                 None      => ccx.sess.span_bug(dtor.span, ~"Bad self ty in \
                                                             dtor")
         };
-        trans_struct_dtor(ccx, /*bad*/copy *pt, dtor.node.body,
+        trans_struct_dtor(ccx, /*bad*/copy *pt, &dtor.node.body,
           dtor.node.id, psubsts, Some(hash_id), parent_id)
       }
       ast_map::node_trait_method(@ast::provided(mth), _, pt) => {
@@ -267,31 +267,34 @@ pub fn monomorphic_fn(ccx: @crate_ctxt,
 pub fn normalize_for_monomorphization(tcx: ty::ctxt,
                                       ty: ty::t) -> Option<ty::t> {
     // FIXME[mono] could do this recursively. is that worthwhile? (#2529)
-    match ty::get(ty).sty {
+    return match ty::get(ty).sty {
         ty::ty_box(*) => {
             Some(ty::mk_opaque_box(tcx))
         }
-        ty::ty_fn(ref fty) => {
-            Some(ty::mk_fn(
+        ty::ty_bare_fn(_) => {
+            Some(ty::mk_bare_fn(
                 tcx,
-                FnTyBase {meta: FnMeta {purity: ast::impure_fn,
-                                        proto: fty.meta.proto,
-                                        onceness: ast::Many,
-                                        region: ty::re_static,
-                                        bounds: @~[]},
-                          sig: FnSig {inputs: ~[],
-                                      output: ty::mk_nil(tcx)}}))
+                ty::BareFnTy {
+                    purity: ast::impure_fn,
+                    abi: ast::RustAbi,
+                    sig: FnSig {inputs: ~[],
+                                output: ty::mk_nil(tcx)}}))
         }
-        ty::ty_trait(_, _, _) => {
-            Some(ty::mk_fn(
-                tcx,
-                FnTyBase {meta: FnMeta {purity: ast::impure_fn,
-                                        proto: ast::ProtoBox,
-                                        onceness: ast::Many,
-                                        region: ty::re_static,
-                                        bounds: @~[]},
-                          sig: FnSig {inputs: ~[],
-                                      output: ty::mk_nil(tcx)}}))
+        ty::ty_closure(ref fty) => {
+            Some(normalized_closure_ty(tcx, fty.sigil))
+        }
+        ty::ty_trait(_, _, ref vstore) => {
+            let sigil = match *vstore {
+                ty::vstore_uniq => ast::OwnedSigil,
+                ty::vstore_box => ast::ManagedSigil,
+                ty::vstore_slice(_) => ast::BorrowedSigil,
+                ty::vstore_fixed(*) => {
+                    tcx.sess.bug(fmt!("ty_trait with vstore_fixed"));
+                }
+            };
+
+            // Traits have the same runtime representation as closures.
+            Some(normalized_closure_ty(tcx, sigil))
         }
         ty::ty_ptr(_) => {
             Some(ty::mk_uint(tcx))
@@ -299,6 +302,20 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt,
         _ => {
             None
         }
+    };
+
+    fn normalized_closure_ty(tcx: ty::ctxt,
+                             sigil: ast::Sigil) -> ty::t
+    {
+        ty::mk_closure(
+            tcx,
+            ty::ClosureTy {
+                purity: ast::impure_fn,
+                sigil: sigil,
+                onceness: ast::Many,
+                region: ty::re_static,
+                sig: ty::FnSig {inputs: ~[],
+                                output: ty::mk_nil(tcx)}})
     }
 }
 
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index 7380fa2e562..9466099904c 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -86,9 +86,8 @@ pub impl reflector {
             tcx.sess.ident_of(~"visit_" + ty_name),
             *self.visitor_methods).expect(fmt!("Couldn't find visit method \
                                                 for %s", ty_name));
-        let mth_ty = ty::mk_fn(
-            tcx,
-            /*bad*/copy self.visitor_methods[mth_idx].fty);
+        let mth_ty =
+            ty::mk_bare_fn(tcx, copy self.visitor_methods[mth_idx].fty);
         let v = self.visitor_val;
         debug!("passing %u args:", vec::len(args));
         let bcx = self.bcx;
@@ -211,39 +210,33 @@ pub impl reflector {
             }
           }
 
+          // FIXME (#2594): fetch constants out of intrinsic
+          // FIXME (#4809): visitor should break out bare fns from other fns
+          ty::ty_closure(ref fty) => {
+            let pureval = ast_purity_constant(fty.purity);
+            let sigilval = ast_sigil_constant(fty.sigil);
+            let retval = if ty::type_is_bot(fty.sig.output) {0u} else {1u};
+            let extra = ~[self.c_uint(pureval),
+                          self.c_uint(sigilval),
+                          self.c_uint(vec::len(fty.sig.inputs)),
+                          self.c_uint(retval)];
+            self.visit(~"enter_fn", copy extra);    // XXX: Bad copy.
+            self.visit_sig(retval, &fty.sig);
+            self.visit(~"leave_fn", extra);
+          }
+
           // FIXME (#2594): fetch constants out of intrinsic:: for the
           // numbers.
-          ty::ty_fn(ref fty) => {
-            let pureval = match fty.meta.purity {
-              ast::pure_fn => 0u,
-              ast::unsafe_fn => 1u,
-              ast::impure_fn => 2u,
-              ast::extern_fn => 3u
-            };
-            let protoval = ast_proto_constant(fty.meta.proto);
+          ty::ty_bare_fn(ref fty) => {
+            let pureval = ast_purity_constant(fty.purity);
+            let sigilval = 0u;
             let retval = if ty::type_is_bot(fty.sig.output) {0u} else {1u};
             let extra = ~[self.c_uint(pureval),
-                          self.c_uint(protoval),
+                          self.c_uint(sigilval),
                           self.c_uint(vec::len(fty.sig.inputs)),
                           self.c_uint(retval)];
             self.visit(~"enter_fn", copy extra);    // XXX: Bad copy.
-            for fty.sig.inputs.eachi |i, arg| {
-                let modeval = match arg.mode {
-                  ast::infer(_) => 0u,
-                  ast::expl(e) => match e {
-                    ast::by_ref => 1u,
-                    ast::by_val => 2u,
-                    ast::by_copy => 5u
-                  }
-                };
-                self.visit(~"fn_input",
-                           ~[self.c_uint(i),
-                             self.c_uint(modeval),
-                             self.c_tydesc(arg.ty)]);
-            }
-            self.visit(~"fn_output",
-                       ~[self.c_uint(retval),
-                         self.c_tydesc(fty.sig.output)]);
+            self.visit_sig(retval, &fty.sig);
             self.visit(~"leave_fn", extra);
           }
 
@@ -302,11 +295,31 @@ pub impl reflector {
           ty::ty_type => self.leaf(~"type"),
           ty::ty_opaque_box => self.leaf(~"opaque_box"),
           ty::ty_opaque_closure_ptr(ck) => {
-            let ckval = ast_proto_constant(ck);
+            let ckval = ast_sigil_constant(ck);
             self.visit(~"closure_ptr", ~[self.c_uint(ckval)])
           }
         }
     }
+
+    fn visit_sig(&self, retval: uint, sig: &ty::FnSig) {
+        for sig.inputs.eachi |i, arg| {
+            let modeval = match arg.mode {
+                ast::infer(_) => 0u,
+                ast::expl(e) => match e {
+                    ast::by_ref => 1u,
+                    ast::by_val => 2u,
+                    ast::by_copy => 5u
+                }
+            };
+            self.visit(~"fn_input",
+                       ~[self.c_uint(i),
+                         self.c_uint(modeval),
+                         self.c_tydesc(arg.ty)]);
+        }
+        self.visit(~"fn_output",
+                   ~[self.c_uint(retval),
+                     self.c_tydesc(sig.output)]);
+    }
 }
 
 // Emit a sequence of calls to visit_ty::visit_foo
@@ -332,12 +345,20 @@ pub fn emit_calls_to_trait_visit_ty(bcx: block,
     return final;
 }
 
-pub fn ast_proto_constant(proto: ast::Proto) -> uint {
-    match proto {
-        ast::ProtoBare => 0u,
-        ast::ProtoUniq => 2u,
-        ast::ProtoBox => 3u,
-        ast::ProtoBorrowed => 4u,
+pub fn ast_sigil_constant(sigil: ast::Sigil) -> uint {
+    match sigil {
+        ast::OwnedSigil => 2u,
+        ast::ManagedSigil => 3u,
+        ast::BorrowedSigil => 4u,
+    }
+}
+
+pub fn ast_purity_constant(purity: ast::purity) -> uint {
+    match purity {
+        ast::pure_fn => 0u,
+        ast::unsafe_fn => 1u,
+        ast::impure_fn => 2u,
+        ast::extern_fn => 3u
     }
 }
 
diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs
index 99c47997df0..f727b5a2de0 100644
--- a/src/librustc/middle/trans/type_of.rs
+++ b/src/librustc/middle/trans/type_of.rs
@@ -59,7 +59,13 @@ pub fn type_of_fn(cx: @crate_ctxt, inputs: &[ty::arg],
 
 // Given a function type and a count of ty params, construct an llvm type
 pub fn type_of_fn_from_ty(cx: @crate_ctxt, fty: ty::t) -> TypeRef {
-    type_of_fn(cx, ty::ty_fn_args(fty), ty::ty_fn_ret(fty))
+    match ty::get(fty).sty {
+        ty::ty_closure(ref f) => type_of_fn(cx, f.sig.inputs, f.sig.output),
+        ty::ty_bare_fn(ref f) => type_of_fn(cx, f.sig.inputs, f.sig.output),
+        _ => {
+            cx.sess.bug(~"type_of_fn_from_ty given non-closure, non-bare-fn")
+        }
+    }
 }
 
 pub fn type_of_non_gc_box(cx: @crate_ctxt, t: ty::t) -> TypeRef {
@@ -170,7 +176,11 @@ pub fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
         // structs
         T_struct(~[T_struct(tys)])
       }
-      ty::ty_fn(_) => T_fn_pair(cx, type_of_fn_from_ty(cx, t)),
+
+      // FIXME(#4804) Bare fn repr
+      // ty::ty_bare_fn(_) => T_ptr(type_of_fn_from_ty(cx, t)),
+      ty::ty_bare_fn(_) => T_fn_pair(cx, type_of_fn_from_ty(cx, t)),
+      ty::ty_closure(_) => T_fn_pair(cx, type_of_fn_from_ty(cx, t)),
       ty::ty_trait(_, _, vstore) => T_opaque_trait(cx, vstore),
       ty::ty_type => T_ptr(cx.tydesc_type),
       ty::ty_tup(elts) => {
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
index 6b0d4e17c74..3fd334c2d15 100644
--- a/src/librustc/middle/trans/type_use.rs
+++ b/src/librustc/middle/trans/type_use.rs
@@ -69,8 +69,9 @@ pub fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
 
     let cx = {ccx: ccx, uses: vec::cast_to_mut(vec::from_elem(n_tps, 0u))};
     match ty::get(ty::lookup_item_type(cx.ccx.tcx, fn_id).ty).sty {
-        ty::ty_fn(ref fn_ty) => {
-            for vec::each(fn_ty.sig.inputs) |arg| {
+        ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) |
+        ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => {
+            for vec::each(sig.inputs) |arg| {
                 match ty::resolved_mode(ccx.tcx, arg.mode) {
                     by_val | by_copy => {
                         type_needs(cx, use_repr, arg.ty);
@@ -197,8 +198,12 @@ pub fn type_needs_inner(cx: ctx,
                  it, we depend on the drop glue for T (we have to write the
                  right tydesc into the result)
                  */
-              ty::ty_fn(_) | ty::ty_ptr(_) | ty::ty_rptr(_, _)
-               | ty::ty_trait(_, _, _) => false,
+                ty::ty_closure(*) |
+                ty::ty_bare_fn(*) |
+                ty::ty_ptr(_) |
+                ty::ty_rptr(_, _) |
+                ty::ty_trait(_, _, _) => false,
+
               ty::ty_enum(did, ref substs) => {
                 if option::is_none(&list::find(enums_seen, |id| *id == did)) {
                     let seen = @Cons(did, enums_seen);
@@ -287,15 +292,15 @@ pub 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)) {
-          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);
-            }
+          match ty::ty_closure_sigil(ty::expr_ty(cx.ccx.tcx, e)) {
+              ast::OwnedSigil => {}
+              ast::BorrowedSigil | ast::ManagedSigil => {
+                  for freevars::get_freevars(cx.ccx.tcx, e.id).each |fv| {
+                      let node_id = ast_util::def_id_of_def(fv.def).node;
+                      node_type_needs(cx, use_repr, node_id);
+                  }
+              }
           }
-        }
       }
       expr_assign(val, _) | expr_swap(val, _) | expr_assign_op(_, val, _) |
       expr_ret(Some(val)) => {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 9905701e058..ef62fb3caf1 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[warn(deprecated_pattern)];
-
 use core::prelude::*;
 
 use driver::session;
@@ -27,7 +25,7 @@ use middle;
 use session::Session;
 use util::ppaux::{note_and_explain_region, bound_region_to_str};
 use util::ppaux::{region_to_str, explain_region, vstore_to_str};
-use util::ppaux::{ty_to_str, proto_ty_to_str, tys_to_str};
+use util::ppaux::{ty_to_str, tys_to_str};
 
 use core::cast;
 use core::cmp;
@@ -73,7 +71,7 @@ pub type param_bounds = @~[param_bound];
 pub type method = {
     ident: ast::ident,
     tps: @~[param_bounds],
-    fty: FnTy,
+    fty: BareFnTy,
     self_ty: ast::self_ty_,
     vis: ast::visibility,
     def_id: ast::def_id
@@ -344,22 +342,20 @@ pub pure fn type_contains_err(t: t) -> bool {
 pub pure fn type_def_id(t: t) -> Option<ast::def_id> { get(t).o_def_id }
 pub pure fn type_id(t: t) -> uint { get(t).id }
 
-/**
- * Meta information about a closure.
- *
- * - `purity` is the function's effect (pure, impure, unsafe).
- * - `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. */
 #[deriving_eq]
-pub struct FnMeta {
+pub struct BareFnTy {
+    purity: ast::purity,
+    abi: Abi,
+    sig: FnSig
+}
+
+#[deriving_eq]
+pub struct ClosureTy {
     purity: ast::purity,
-    proto: ast::Proto,
+    sigil: ast::Sigil,
     onceness: ast::Onceness,
     region: Region,
-    bounds: @~[param_bound]
+    sig: FnSig
 }
 
 /**
@@ -374,25 +370,19 @@ pub struct FnSig {
     output: t
 }
 
-/**
- * Function type: combines the meta information and the
- * type signature.  This particular type is parameterized
- * by the meta information because, in some cases, the
- * meta information is inferred. */
-#[deriving_eq]
-pub struct FnTyBase<M> {
-    meta: M,        // Either FnMeta or FnVid
-    sig: FnSig      // Types of arguments/return type
+impl BareFnTy : to_bytes::IterBytes {
+    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
+        to_bytes::iter_bytes_3(&self.purity, &self.abi, &self.sig, lsb0, f)
+    }
 }
 
-impl<M: to_bytes::IterBytes> FnTyBase<M> : to_bytes::IterBytes {
+impl ClosureTy : to_bytes::IterBytes {
     pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
-        to_bytes::iter_bytes_2(&self.meta, &self.sig, lsb0, f)
+        to_bytes::iter_bytes_5(&self.purity, &self.sigil, &self.onceness,
+                               &self.region, &self.sig, lsb0, f)
     }
 }
 
-pub type FnTy = FnTyBase<FnMeta>;
-
 #[deriving_eq]
 pub struct param_ty {
     idx: uint,
@@ -491,6 +481,7 @@ pub struct substs {
 
 // NB: If you change this, you'll probably want to change the corresponding
 // AST structure in libsyntax/ast.rs as well.
+#[deriving_eq]
 pub enum sty {
     ty_nil,
     ty_bot,
@@ -506,7 +497,8 @@ pub enum sty {
     ty_ptr(mt),
     ty_rptr(Region, mt),
     ty_rec(~[field]),
-    ty_fn(FnTy),
+    ty_bare_fn(BareFnTy),
+    ty_closure(ClosureTy),
     ty_trait(def_id, substs, vstore),
     ty_struct(def_id, substs),
     ty_tup(~[t]),
@@ -522,7 +514,7 @@ pub 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(ast::Proto), // ptr to env for fn, fn@, fn~
+    ty_opaque_closure_ptr(Sigil), // ptr to env for fn, fn@, fn~
     ty_unboxed_vec(mt),
 }
 
@@ -546,8 +538,9 @@ pub enum type_err {
     terr_mismatch,
     terr_purity_mismatch(expected_found<purity>),
     terr_onceness_mismatch(expected_found<Onceness>),
+    terr_abi_mismatch(expected_found<ast::Abi>),
     terr_mutability,
-    terr_proto_mismatch(expected_found<ast::Proto>),
+    terr_sigil_mismatch(expected_found<ast::Sigil>),
     terr_box_mutability,
     terr_ptr_mutability,
     terr_ref_mutability,
@@ -744,6 +737,15 @@ pub impl RegionVid : to_bytes::IterBytes {
     }
 }
 
+pub fn kind_to_param_bounds(kind: Kind) -> param_bounds {
+    let mut bounds = ~[];
+    if kind_can_be_copied(kind) { bounds.push(bound_copy); }
+    if kind_can_be_sent(kind) { bounds.push(bound_owned); }
+    else if kind_is_durable(kind) { bounds.push(bound_durable); }
+    if kind_is_const(kind) { bounds.push(bound_const); }
+    return @bounds;
+}
+
 pub fn param_bounds_to_kind(bounds: param_bounds) -> Kind {
     let mut kind = kind_noncopyable();
     for vec::each(*bounds) |bound| {
@@ -925,8 +927,12 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option<ast::def_id>) -> t {
       }
       &ty_rec(ref flds) => for flds.each |f| { flags |= get(f.mt.ty).flags; },
       &ty_tup(ref ts) => for ts.each |tt| { flags |= get(*tt).flags; },
-      &ty_fn(ref f) => {
-        flags |= rflags(f.meta.region);
+      &ty_bare_fn(ref f) => {
+        for f.sig.inputs.each |a| { flags |= get(a.ty).flags; }
+        flags |= get(f.sig.output).flags;
+      }
+      &ty_closure(ref f) => {
+        flags |= rflags(f.region);
         for f.sig.inputs.each |a| { flags |= get(a.ty).flags; }
         flags |= get(f.sig.output).flags;
       }
@@ -1044,8 +1050,25 @@ pub fn mk_rec(cx: ctxt, +fs: ~[field]) -> t { mk_t(cx, ty_rec(fs)) }
 
 pub fn mk_tup(cx: ctxt, +ts: ~[t]) -> t { mk_t(cx, ty_tup(ts)) }
 
-// take a copy because we want to own the various vectors inside
-pub fn mk_fn(cx: ctxt, +fty: FnTy) -> t { mk_t(cx, ty_fn(fty)) }
+pub fn mk_closure(cx: ctxt, +fty: ClosureTy) -> t {
+    mk_t(cx, ty_closure(fty))
+}
+
+pub fn mk_bare_fn(cx: ctxt, +fty: BareFnTy) -> t {
+    mk_t(cx, ty_bare_fn(fty))
+}
+
+pub fn mk_ctor_fn(cx: ctxt, input_tys: &[ty::t], output: ty::t) -> t {
+    let input_args = input_tys.map(|t| arg {mode: ast::expl(ast::by_copy),
+                                            ty: *t});
+    mk_bare_fn(cx,
+               BareFnTy {
+                   purity: ast::pure_fn,
+                   abi: ast::RustAbi,
+                   sig: FnSig {inputs: input_args,
+                               output: output}})
+}
+
 
 pub fn mk_trait(cx: ctxt, did: ast::def_id, +substs: substs, vstore: vstore)
          -> t {
@@ -1074,8 +1097,8 @@ pub fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
 
 pub fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) }
 
-pub fn mk_opaque_closure_ptr(cx: ctxt, proto: ast::Proto) -> t {
-    mk_t(cx, ty_opaque_closure_ptr(proto))
+pub fn mk_opaque_closure_ptr(cx: ctxt, sigil: ast::Sigil) -> t {
+    mk_t(cx, ty_opaque_closure_ptr(sigil))
 }
 
 pub fn mk_opaque_box(cx: ctxt) -> t { mk_t(cx, ty_opaque_box) }
@@ -1097,13 +1120,11 @@ pub pure fn mach_sty(cfg: @session::config, t: t) -> sty {
 pub fn default_arg_mode_for_ty(tcx: ctxt, ty: ty::t) -> ast::rmode {
         // FIXME(#2202) --- We retain by-ref for fn& things to workaround a
         // memory leak that otherwise results when @fn is upcast to &fn.
-    if type_is_fn(ty) {
-        match ty_fn_proto(ty) {
-            ast::ProtoBorrowed => {
-                return ast::by_ref;
-            }
-            _ => {}
+    match ty::get(ty).sty {
+        ty::ty_closure(ClosureTy {sigil: ast::BorrowedSigil, _}) => {
+            return ast::by_ref;
         }
+        _ => {}
     }
     return if tcx.legacy_modes {
         if type_is_borrowed(ty) {
@@ -1119,13 +1140,6 @@ pub fn default_arg_mode_for_ty(tcx: ctxt, ty: ty::t) -> ast::rmode {
         ast::by_copy
     };
 
-    fn type_is_fn(ty: t) -> bool {
-        match get(ty).sty {
-            ty_fn(*) => true,
-            _ => false
-        }
-    }
-
     fn type_is_borrowed(ty: t) -> bool {
         match ty::get(ty).sty {
             ty::ty_rptr(*) => true,
@@ -1171,7 +1185,11 @@ pub fn maybe_walk_ty(ty: t, f: fn(t) -> bool) {
         for fields.each |fl| { maybe_walk_ty(fl.mt.ty, f); }
       }
       ty_tup(ts) => { for ts.each |tt| { maybe_walk_ty(*tt, f); } }
-      ty_fn(ref ft) => {
+      ty_bare_fn(ref ft) => {
+        for ft.sig.inputs.each |a| { maybe_walk_ty(a.ty, f); }
+        maybe_walk_ty(ft.sig.output, f);
+      }
+      ty_closure(ref ft) => {
         for ft.sig.inputs.each |a| { maybe_walk_ty(a.ty, f); }
         maybe_walk_ty(ft.sig.output, f);
       }
@@ -1235,9 +1253,13 @@ fn fold_sty(sty: &sty, fldop: fn(t) -> t) -> sty {
             let new_ts = vec::map(ts, |tt| fldop(*tt));
             ty_tup(new_ts)
         }
-        ty_fn(ref f) => {
+        ty_bare_fn(ref f) => {
+            let sig = fold_sig(&f.sig, fldop);
+            ty_bare_fn(BareFnTy {sig: sig, abi: f.abi, purity: f.purity})
+        }
+        ty_closure(ref f) => {
             let sig = fold_sig(&f.sig, fldop);
-            ty_fn(FnTyBase {meta: f.meta, sig: sig})
+            ty_closure(ClosureTy {sig: sig, ..copy *f})
         }
         ty_rptr(r, tm) => {
             ty_rptr(r, mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
@@ -1318,10 +1340,14 @@ pub fn fold_regions_and_ty(
       ty_trait(def_id, ref substs, vst) => {
         ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), vst)
       }
-      ty_fn(ref f) => {
-          ty::mk_fn(cx, FnTyBase {meta: FnMeta {region: fldr(f.meta.region),
-                                                ..f.meta},
-                                  sig: fold_sig(&f.sig, fldfnt)})
+      ty_bare_fn(ref f) => {
+          ty::mk_bare_fn(cx, BareFnTy {sig: fold_sig(&f.sig, fldfnt),
+                                       ..copy *f})
+      }
+      ty_closure(ref f) => {
+          ty::mk_closure(cx, ClosureTy {region: fldr(f.region),
+                                        sig: fold_sig(&f.sig, fldfnt),
+                                        ..copy *f})
       }
       ref sty => {
         fold_sty_to_ty(cx, sty, |t| fldt(t))
@@ -1329,30 +1355,6 @@ pub fn fold_regions_and_ty(
     }
 }
 
-/* A little utility: it often happens that I have a `fn_ty`,
- * but I want to use some function like `fold_regions_and_ty()`
- * that is defined over all types.  This utility converts to
- * a full type and back.  It's not the best way to do this (somewhat
- * inefficient to do the conversion), it would be better to refactor
- * all this folding business.  However, I've been waiting on that
- * until trait support is improved. */
-pub fn apply_op_on_t_to_ty_fn(
-    cx: ctxt,
-    f: &FnTy,
-    t_op: fn(t) -> t) -> FnTy
-{
-    let t0 = ty::mk_fn(cx, /*bad*/copy *f);
-    let t1 = t_op(t0);
-    match ty::get(t1).sty {
-        ty::ty_fn(copy f) => {
-            move f
-        }
-        _ => {
-            cx.sess.bug(~"`t_op` did not return a function type");
-        }
-    }
-}
-
 // n.b. this function is intended to eventually replace fold_region() below,
 // that is why its name is so similar.
 pub fn fold_regions(
@@ -1372,41 +1374,6 @@ pub fn fold_regions(
     do_fold(cx, ty, false, fldr)
 }
 
-pub fn fold_region(cx: ctxt, t0: t, fldop: fn(Region, bool) -> Region) -> t {
-    fn do_fold(cx: ctxt, t0: t, under_r: bool,
-               fldop: fn(Region, bool) -> Region) -> t {
-        let tb = get(t0);
-        if !tbox_has_flag(tb, has_regions) { return t0; }
-        match tb.sty {
-          ty_rptr(r, mt {ty: t1, mutbl: m}) => {
-            let m_r = fldop(r, under_r);
-            let m_t1 = do_fold(cx, t1, true, fldop);
-            ty::mk_rptr(cx, m_r, mt {ty: m_t1, mutbl: m})
-          }
-          ty_estr(vstore_slice(r)) => {
-            let m_r = fldop(r, under_r);
-            ty::mk_estr(cx, vstore_slice(m_r))
-          }
-          ty_evec(mt {ty: t1, mutbl: m}, vstore_slice(r)) => {
-            let m_r = fldop(r, under_r);
-            let m_t1 = do_fold(cx, t1, true, fldop);
-            ty::mk_evec(cx, mt {ty: m_t1, mutbl: m}, vstore_slice(m_r))
-          }
-          ty_fn(_) => {
-            // do not recurse into functions, which introduce fresh bindings
-            t0
-          }
-          ref sty => {
-            do fold_sty_to_ty(cx, sty) |t| {
-                do_fold(cx, t, under_r, fldop)
-            }
-          }
-      }
-    }
-
-    do_fold(cx, t0, false, fldop)
-}
-
 // Substitute *only* type parameters.  Used in trans where regions are erased.
 pub fn subst_tps(cx: ctxt, tps: &[t], self_ty_opt: Option<t>, typ: t) -> t {
     if tps.len() == 0u && self_ty_opt.is_none() { return typ; }
@@ -1529,7 +1496,9 @@ pub fn type_is_bool(ty: t) -> bool { get(ty).sty == ty_bool }
 
 pub fn type_is_structural(ty: t) -> bool {
     match get(ty).sty {
-      ty_rec(_) | ty_struct(*) | ty_tup(_) | ty_enum(*) | ty_fn(_) |
+      ty_rec(_) | ty_struct(*) | ty_tup(_) | ty_enum(*) |
+      ty_closure(_) |
+      ty_bare_fn(_) | // FIXME(#4804) Bare fn repr
       ty_trait(*) |
       ty_evec(_, vstore_fixed(_)) | ty_estr(vstore_fixed(_)) |
       ty_evec(_, vstore_slice(_)) | ty_estr(vstore_slice(_))
@@ -1715,10 +1684,11 @@ pub fn type_needs_drop(cx: ctxt, ty: t) -> bool {
         }
         accum
       }
-      ty_fn(ref fty) => {
-        match fty.meta.proto {
-          ast::ProtoBare | ast::ProtoBorrowed => false,
-          ast::ProtoBox | ast::ProtoUniq => true,
+      ty_bare_fn(*) => false,
+      ty_closure(ref fty) => {
+        match fty.sigil {
+          ast::BorrowedSigil => false,
+          ast::ManagedSigil | ast::OwnedSigil => true,
         }
       }
     };
@@ -1813,7 +1783,7 @@ pub enum Kind { kind_(u32) }
 const KIND_MASK_COPY         : u32 = 0b000000000000000000000000001_u32;
 
 /// no shared box, borrowed ptr (must imply DURABLE)
-const KIND_MASK_OWNED         : u32 = 0b000000000000000000000000010_u32;
+const KIND_MASK_OWNED        : u32 = 0b000000000000000000000000010_u32;
 
 /// is durable (no borrowed ptrs)
 const KIND_MASK_DURABLE      : u32 = 0b000000000000000000000000100_u32;
@@ -1942,20 +1912,25 @@ pub pure fn kind_is_durable(k: Kind) -> bool {
     *k & KIND_MASK_DURABLE == KIND_MASK_DURABLE
 }
 
-pub fn meta_kind(p: FnMeta) -> Kind {
-    match p.proto { // XXX consider the kind bounds!
-        ast::ProtoBare => {
-            kind_safe_for_default_mode_send() | kind_const() | kind_durable()
-        }
-        ast::ProtoBorrowed => {
-            kind_noncopyable() | kind_(KIND_MASK_DEFAULT_MODE)
-        }
-        ast::ProtoBox => {
-            kind_safe_for_default_mode() | kind_durable()
-        }
-        ast::ProtoUniq => {
-            kind_owned_copy() | kind_durable()
-        }
+pure fn kind_is_const(k: Kind) -> bool {
+    *k & KIND_MASK_CONST == KIND_MASK_CONST
+}
+
+fn closure_kind(cty: &ClosureTy) -> Kind {
+    let kind = match cty.sigil {
+        ast::BorrowedSigil => kind_implicitly_copyable(),
+        ast::ManagedSigil => kind_implicitly_copyable(),
+        ast::OwnedSigil => kind_owned_only() | kind_durable(),
+    };
+
+    let kind = match cty.region {
+        re_static => kind | kind_durable(),
+        _ => kind - kind_owned_only() - kind_durable()
+    };
+
+    match cty.onceness {
+        ast::Once => kind - kind_implicitly_copyable(),
+        ast::Many => kind
     }
 }
 
@@ -2022,7 +1997,7 @@ pub fn type_kind_ext(cx: ctxt, ty: t, allow_ty_var: bool) -> Kind {
     let mut result = match /*bad*/copy get(ty).sty {
       // Scalar and unique types are sendable, constant, and owned
       ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
-      ty_ptr(_) => {
+      ty_bare_fn(_) | ty_ptr(_) => {
         kind_safe_for_default_mode_send() | kind_const() | kind_durable()
       }
 
@@ -2035,8 +2010,9 @@ pub fn type_kind_ext(cx: ctxt, ty: t, allow_ty_var: bool) -> Kind {
         }
       }
 
-      // functions depend on the protocol
-      ty_fn(ref f) => meta_kind(f.meta),
+      ty_closure(ref c) => {
+          closure_kind(c)
+      }
 
       // Those with refcounts raise noncopyable to copyable,
       // lower sendable to copyable. Therefore just set result to copyable.
@@ -2215,7 +2191,8 @@ fn type_size(cx: ctxt, ty: t) -> uint {
 
       ty_evec(_, vstore_slice(_)) |
       ty_estr(vstore_slice(_)) |
-      ty_fn(_) => {
+      ty_bare_fn(*) |
+      ty_closure(*) => {
         2
       }
 
@@ -2297,7 +2274,8 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
           ty_uint(_) |
           ty_float(_) |
           ty_estr(_) |
-          ty_fn(_) |
+          ty_bare_fn(_) |
+          ty_closure(_) |
           ty_infer(_) |
           ty_err |
           ty_param(_) |
@@ -2472,9 +2450,9 @@ pub fn type_is_pod(cx: ctxt, ty: t) -> bool {
     match /*bad*/copy get(ty).sty {
       // Scalar types
       ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
-      ty_type | ty_ptr(_) => result = true,
+      ty_type | ty_ptr(_) | ty_bare_fn(_) => result = true,
       // Boxed types
-      ty_box(_) | ty_uniq(_) | ty_fn(_) |
+      ty_box(_) | ty_uniq(_) | ty_closure(_) |
       ty_estr(vstore_uniq) | ty_estr(vstore_box) |
       ty_evec(_, vstore_uniq) | ty_evec(_, vstore_box) |
       ty_trait(_, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false,
@@ -2700,14 +2678,9 @@ impl arg : to_bytes::IterBytes {
     }
 }
 
-impl FnMeta : to_bytes::IterBytes {
+impl Kind : to_bytes::IterBytes {
     pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
-        to_bytes::iter_bytes_5(&self.purity,
-                               &self.proto,
-                               &self.onceness,
-                               &self.region,
-                               &self.bounds,
-                               lsb0, f);
+        (**self).iter_bytes(lsb0, f)
     }
 }
 
@@ -2755,7 +2728,7 @@ impl sty : to_bytes::IterBytes {
           ty_rec(ref fs) =>
           to_bytes::iter_bytes_2(&11u8, fs, lsb0, f),
 
-          ty_fn(ref ft) =>
+          ty_bare_fn(ref ft) =>
           to_bytes::iter_bytes_2(&12u8, ft, lsb0, f),
 
           ty_self => 13u8.iter_bytes(lsb0, f),
@@ -2789,7 +2762,10 @@ impl sty : to_bytes::IterBytes {
           ty_rptr(ref r, ref mt) =>
           to_bytes::iter_bytes_3(&24u8, r, mt, lsb0, f),
 
-          ty_err => 25u8.iter_bytes(lsb0, f)
+          ty_err => 25u8.iter_bytes(lsb0, f),
+
+          ty_closure(ref ct) =>
+          to_bytes::iter_bytes_2(&26u8, ct, lsb0, f),
         }
     }
 }
@@ -2823,36 +2799,48 @@ fn node_id_has_type_params(cx: ctxt, id: ast::node_id) -> bool {
 // Type accessors for substructures of types
 pub fn ty_fn_args(fty: t) -> ~[arg] {
     match get(fty).sty {
-      ty_fn(ref f) => /*bad*/copy f.sig.inputs,
-      _ => die!(~"ty_fn_args() called on non-fn type")
+        ty_bare_fn(ref f) => copy f.sig.inputs,
+        ty_closure(ref f) => copy f.sig.inputs,
+        ref s => {
+            die!(fmt!("ty_fn_args() called on non-fn type: %?", s))
+        }
     }
 }
 
-pub fn ty_fn_proto(fty: t) -> Proto {
+pub fn ty_closure_sigil(fty: t) -> Sigil {
     match get(fty).sty {
-      ty_fn(ref f) => f.meta.proto,
-      _ => die!(~"ty_fn_proto() called on non-fn type")
+        ty_closure(ref f) => f.sigil,
+        ref s => {
+            die!(fmt!("ty_closure_sigil() called on non-closure type: %?", s))
+        }
     }
 }
 
 pub fn ty_fn_purity(fty: t) -> ast::purity {
     match get(fty).sty {
-      ty_fn(ref f) => f.meta.purity,
-      _ => die!(~"ty_fn_purity() called on non-fn type")
+        ty_bare_fn(ref f) => f.purity,
+        ty_closure(ref f) => f.purity,
+        ref s => {
+            die!(fmt!("ty_fn_purity() called on non-fn type: %?", s))
+        }
     }
 }
 
 pub pure fn ty_fn_ret(fty: t) -> t {
     match get(fty).sty {
-        ty_fn(ref f) => f.sig.output,
-        _ => die!(~"ty_fn_ret() called on non-fn type")
+        ty_bare_fn(ref f) => f.sig.output,
+        ty_closure(ref f) => f.sig.output,
+        ref s => {
+            die!(fmt!("ty_fn_ret() called on non-fn type: %?", s))
+        }
     }
 }
 
 fn is_fn_ty(fty: t) -> bool {
     match get(fty).sty {
-      ty_fn(_) => true,
-      _ => false
+        ty_bare_fn(_) => true,
+        ty_closure(_) => true,
+        _ => false
     }
 }
 
@@ -2874,17 +2862,17 @@ pub fn ty_region(ty: t) -> Region {
     }
 }
 
-pub fn replace_fn_return_type(tcx: ctxt, fn_type: t, ret_type: t) -> t {
+pub fn replace_closure_return_type(tcx: ctxt, fn_type: t, ret_type: t) -> t {
     /*!
      *
      * Returns a new function type based on `fn_type` but returning a value of
      * type `ret_type` instead. */
 
     match ty::get(fn_type).sty {
-        ty::ty_fn(ref fty) => {
-            ty::mk_fn(tcx, FnTyBase {
-                meta: fty.meta,
-                sig: FnSig {output: ret_type, ..copy fty.sig}
+        ty::ty_closure(ref fty) => {
+            ty::mk_closure(tcx, ClosureTy {
+                sig: FnSig {output: ret_type, ..copy fty.sig},
+                ..copy *fty
             })
         }
         _ => {
@@ -2900,12 +2888,6 @@ pub fn tys_in_fn_sig(sig: &FnSig) -> ~[t] {
     vec::append_one(sig.inputs.map(|a| a.ty), sig.output)
 }
 
-// Just checks whether it's a fn that returns bool,
-// not its purity.
-pub fn is_pred_ty(fty: t) -> bool {
-    is_fn_ty(fty) && type_is_bool(ty_fn_ret(fty))
-}
-
 // Type accessors for AST nodes
 pub fn block_ty(cx: ctxt, b: &ast::blk) -> t {
     return node_id_to_type(cx, b.node.id);
@@ -3023,11 +3005,12 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t {
     fn borrow_fn(cx: ctxt, expr: @ast::expr,
                  autoref: &AutoRef, ty: ty::t) -> ty::t {
         match get(ty).sty {
-            ty_fn(ref fty) => {
-                ty::mk_fn(cx, FnTyBase {meta: FnMeta {proto: ProtoBorrowed,
-                                                      region: autoref.region,
-                                                      ..copy fty.meta},
-                                        sig: copy fty.sig})
+            ty_closure(ref fty) => {
+                ty::mk_closure(cx, ClosureTy {
+                    sigil: BorrowedSigil,
+                    region: autoref.region,
+                    ..copy *fty
+                })
             }
 
             ref s => {
@@ -3417,7 +3400,8 @@ pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
       ty_ptr(_) => ~"*-ptr",
       ty_rptr(_, _) => ~"&-ptr",
       ty_rec(_) => ~"record",
-      ty_fn(_) => ~"fn",
+      ty_bare_fn(_) => ~"extern fn",
+      ty_closure(_) => ~"fn",
       ty_trait(id, _, _) => fmt!("trait %s", item_path_str(cx, id)),
       ty_struct(id, _) => fmt!("struct %s", item_path_str(cx, id)),
       ty_tup(_) => ~"tuple",
@@ -3455,14 +3439,18 @@ pub fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
             fmt!("expected %s fn but found %s fn",
                  values.expected.to_str(), values.found.to_str())
         }
+        terr_abi_mismatch(values) => {
+            fmt!("expected %s fn but found %s fn",
+                 values.expected.to_str(), values.found.to_str())
+        }
         terr_onceness_mismatch(values) => {
             fmt!("expected %s fn but found %s fn",
                  values.expected.to_str(), values.found.to_str())
         }
-        terr_proto_mismatch(values) => {
+        terr_sigil_mismatch(values) => {
             fmt!("expected %s closure, found %s closure",
-                 proto_ty_to_str(cx, values.expected, false),
-                 proto_ty_to_str(cx, values.found, false))
+                 values.expected.to_str(),
+                 values.found.to_str())
         }
         terr_mutability => ~"values differ in mutability",
         terr_box_mutability => ~"boxed values differ in mutability",
@@ -4232,13 +4220,10 @@ pub fn normalize_ty(cx: ctxt, t: t) -> t {
             // This type has a region. Get rid of it
             mk_rptr(cx, re_static, normalize_mt(cx, mt)),
 
-        ty_fn(ref fn_ty) => {
-            mk_fn(cx, FnTyBase {
-                meta: FnMeta {
-                    region: ty::re_static,
-                    ..fn_ty.meta
-                },
-                sig: /*bad*/copy fn_ty.sig
+        ty_closure(ref closure_ty) => {
+            mk_closure(cx, ClosureTy {
+                region: ty::re_static,
+                ..copy *closure_ty
             })
         }
 
@@ -4310,13 +4295,13 @@ pub fn eval_repeat_count(tcx: ctxt,
 // Determine what purity to check a nested function under
 pub pure fn determine_inherited_purity(parent_purity: ast::purity,
                                        child_purity: ast::purity,
-                                       child_proto: ast::Proto)
+                                       child_sigil: ast::Sigil)
                                     -> 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
-    match child_proto {
-        ast::ProtoBorrowed if child_purity == ast::impure_fn => parent_purity,
+    match child_sigil {
+        ast::BorrowedSigil if child_purity == ast::impure_fn => parent_purity,
         _ => child_purity
     }
 }
@@ -4526,171 +4511,6 @@ impl bound_region : cmp::Eq {
     pure fn ne(&self, other: &bound_region) -> bool { !(*self).eq(other) }
 }
 
-impl sty : cmp::Eq {
-    pure fn eq(&self, other: &sty) -> bool {
-        match (/*bad*/copy *self) {
-            ty_nil => {
-                match (*other) {
-                    ty_nil => true,
-                    _ => false
-                }
-            }
-            ty_bot => {
-                match (*other) {
-                    ty_bot => true,
-                    _ => false
-                }
-            }
-            ty_bool => {
-                match (*other) {
-                    ty_bool => true,
-                    _ => false
-                }
-            }
-            ty_int(e0a) => {
-                match (*other) {
-                    ty_int(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_uint(e0a) => {
-                match (*other) {
-                    ty_uint(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_float(e0a) => {
-                match (*other) {
-                    ty_float(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_estr(e0a) => {
-                match (*other) {
-                    ty_estr(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_enum(e0a, ref e1a) => {
-                match (*other) {
-                    ty_enum(e0b, ref e1b) => e0a == e0b && (*e1a) == (*e1b),
-                    _ => false
-                }
-            }
-            ty_box(e0a) => {
-                match (*other) {
-                    ty_box(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_uniq(e0a) => {
-                match (*other) {
-                    ty_uniq(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_evec(e0a, e1a) => {
-                match (*other) {
-                    ty_evec(e0b, e1b) => e0a == e0b && e1a == e1b,
-                    _ => false
-                }
-            }
-            ty_ptr(e0a) => {
-                match (*other) {
-                    ty_ptr(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_rptr(e0a, e1a) => {
-                match (*other) {
-                    ty_rptr(e0b, e1b) => e0a == e0b && e1a == e1b,
-                    _ => false
-                }
-            }
-            ty_rec(e0a) => {
-                match (/*bad*/copy *other) {
-                    ty_rec(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_fn(ref e0a) => {
-                match (*other) {
-                    ty_fn(ref e0b) => (*e0a) == (*e0b),
-                    _ => false
-                }
-            }
-            ty_trait(e0a, ref e1a, e2a) => {
-                match (*other) {
-                    ty_trait(e0b, ref e1b, e2b) =>
-                        e0a == e0b && (*e1a) == (*e1b) && e2a == e2b,
-                    _ => false
-                }
-            }
-            ty_struct(e0a, ref e1a) => {
-                match (*other) {
-                    ty_struct(e0b, ref e1b) => e0a == e0b && (*e1a) == (*e1b),
-                    _ => false
-                }
-            }
-            ty_tup(e0a) => {
-                match (/*bad*/copy *other) {
-                    ty_tup(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_infer(ref e0a) => {
-                match (*other) {
-                    ty_infer(ref e0b) => *e0a == *e0b,
-                    _ => false
-                }
-            }
-            ty_err => {
-                match (*other) {
-                    ty_err => true,
-                    _ => false
-                }
-            }
-            ty_param(e0a) => {
-                match (*other) {
-                    ty_param(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_self => {
-                match (*other) {
-                    ty_self => true,
-                    _ => false
-                }
-            }
-            ty_type => {
-                match (*other) {
-                    ty_type => true,
-                    _ => false
-                }
-            }
-            ty_opaque_box => {
-                match (*other) {
-                    ty_opaque_box => true,
-                    _ => false
-                }
-            }
-            ty_opaque_closure_ptr(e0a) => {
-                match (*other) {
-                    ty_opaque_closure_ptr(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            ty_unboxed_vec(e0a) => {
-                match (*other) {
-                    ty_unboxed_vec(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-        }
-    }
-    pure fn ne(&self, other: &sty) -> bool { !(*self).eq(other) }
-}
-
 impl param_bound : cmp::Eq {
     pure fn eq(&self, other: &param_bound) -> bool {
         match (*self) {
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 070360ce32f..0aafeac265a 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -55,7 +55,7 @@
 use core::prelude::*;
 
 use middle::pat_util::pat_id_map;
-use middle::ty::{FnTyBase, FnMeta, FnSig, arg, field, substs};
+use middle::ty::{arg, field, substs};
 use middle::ty::{ty_param_substs_and_ty};
 use middle::ty;
 use middle::typeck::check::fn_ctxt;
@@ -70,7 +70,7 @@ use core::vec;
 use syntax::ast;
 use syntax::codemap::span;
 use syntax::print::pprust::path_to_str;
-use util::common::indent;
+use util::common::indenter;
 
 pub trait ast_conv {
     fn tcx() -> ty::ctxt;
@@ -321,13 +321,16 @@ pub fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Durable>(
         };
         ty::mk_rec(tcx, flds)
       }
-      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)
+      ast::ty_bare_fn(bf) => {
+          ty::mk_bare_fn(tcx, ty_of_bare_fn(self, rscope, bf.purity,
+                                            bf.abi, bf.decl))
+      }
+      ast::ty_closure(f) => {
+          let fn_decl = ty_of_closure(self, rscope, f.sigil,
+                                      f.purity, f.onceness,
+                                      f.region, f.decl, None,
+                                      ast_ty.span);
+          ty::mk_closure(tcx, fn_decl)
       }
       ast::ty_path(path, id) => {
         let a_def = match tcx.def_map.find(&id) {
@@ -452,71 +455,92 @@ pub fn ty_of_arg<AC: ast_conv, RS: region_scope Copy Durable>(
     arg {mode: mode, ty: ty}
 }
 
-pub type expected_tys = Option<{inputs: ~[ty::arg],
-                                output: ty::t}>;
+pub fn ty_of_bare_fn<AC: ast_conv, RS: region_scope Copy Durable>(
+    self: AC, rscope: RS,
+    purity: ast::purity,
+    abi: ast::Abi,
+    decl: ast::fn_decl) -> ty::BareFnTy
+{
+    debug!("ty_of_fn_decl");
+
+    // new region names that appear inside of the fn decl are bound to
+    // that function type
+    let rb = in_binding_rscope(rscope);
+
+    let input_tys = decl.inputs.map(|a| ty_of_arg(self, rb, *a, None));
+    let output_ty = match decl.output.node {
+        ast::ty_infer => self.ty_infer(decl.output.span),
+        _ => ast_ty_to_ty(self, rb, decl.output)
+    };
+
+    ty::BareFnTy {
+        purity: purity,
+        abi: abi,
+        sig: ty::FnSig {inputs: input_tys, output: output_ty}
+    }
+}
 
-pub fn ty_of_fn_decl<AC: ast_conv, RS: region_scope Copy Durable>(
+pub fn ty_of_closure<AC: ast_conv, RS: region_scope Copy Durable>(
     self: AC, rscope: RS,
-    ast_proto: ast::Proto,
+    sigil: ast::Sigil,
     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 {
+    expected_tys: Option<ty::FnSig>,
+    span: span) -> ty::ClosureTy
+{
     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)
-                    }
+    let _i = indenter();
+
+    // 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 sigil {
+                ast::OwnedSigil | ast::ManagedSigil => {
+                    // @fn(), ~fn() default to static as the bound
+                    // on their upvars:
+                    ty::re_static
+                }
+                ast::BorrowedSigil => {
+                    // &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);
-
-        let input_tys = do decl.inputs.mapi |i, a| {
-            let expected_arg_ty = do expected_tys.chain_ref |e| {
-                // no guarantee that the correct number of expected args
-                // were supplied
-                if i < e.inputs.len() {Some(e.inputs[i])} else {None}
-            };
-            ty_of_arg(self, rb, *a, expected_arg_ty)
-        };
+    // new region names that appear inside of the fn decl are bound to
+    // that function type
+    let rb = in_binding_rscope(rscope);
 
-        let expected_ret_ty = expected_tys.map(|e| e.output);
-        let output_ty = match decl.output.node {
-          ast::ty_infer if expected_ret_ty.is_some() => expected_ret_ty.get(),
-          ast::ty_infer => self.ty_infer(decl.output.span),
-          _ => ast_ty_to_ty(self, rb, decl.output)
+    let input_tys = do decl.inputs.mapi |i, a| {
+        let expected_arg_ty = do expected_tys.chain_ref |e| {
+            // no guarantee that the correct number of expected args
+            // were supplied
+            if i < e.inputs.len() {Some(e.inputs[i])} else {None}
         };
+        ty_of_arg(self, rb, *a, expected_arg_ty)
+    };
 
-        FnTyBase {
-            meta: FnMeta {purity: purity,
-                          proto: ast_proto,
-                          onceness: onceness,
-                          region: bound_region,
-                          bounds: bounds},
-            sig: FnSig {inputs: input_tys,
+    let expected_ret_ty = expected_tys.map(|e| e.output);
+    let output_ty = match decl.output.node {
+        ast::ty_infer if expected_ret_ty.is_some() => expected_ret_ty.get(),
+        ast::ty_infer => self.ty_infer(decl.output.span),
+        _ => ast_ty_to_ty(self, rb, decl.output)
+    };
+
+    ty::ClosureTy {
+        purity: purity,
+        sigil: sigil,
+        onceness: onceness,
+        region: bound_region,
+        sig: ty::FnSig {inputs: input_tys,
                         output: output_ty}
-        }
     }
 }
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index b86f8f26c25..f5faa968791 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -883,7 +883,7 @@ pub impl LookupContext {
                     })
             }
 
-            ty_trait(*) | ty_fn(*) => {
+            ty_trait(*) | ty_closure(*) => {
                 // NDM---eventually these should be some variant of autoref
                 None
             }
@@ -906,14 +906,14 @@ pub impl LookupContext {
 
         let tcx = self.tcx();
         match ty::get(self_ty).sty {
-            ty_box(*) | ty_uniq(*) | ty_rptr(*) |
+            ty_bare_fn(*) | ty_box(*) | ty_uniq(*) | ty_rptr(*) |
             ty_infer(IntVar(_)) |
             ty_infer(FloatVar(_)) |
             ty_self | ty_param(*) | ty_nil | ty_bot | ty_bool |
             ty_int(*) | ty_uint(*) |
             ty_float(*) | ty_enum(*) | ty_ptr(*) | ty_rec(*) |
             ty_struct(*) | ty_tup(*) | ty_estr(*) | ty_evec(*) |
-            ty_trait(*) | ty_fn(*) => {
+            ty_trait(*) | ty_closure(*) => {
                 self.search_for_some_kind_of_autorefd_method(
                     AutoPtr, autoderefs, [m_const, m_imm, m_mutbl],
                     |m,r| ty::mk_rptr(tcx, r, ty::mt {ty:self_ty, mutbl:m}))
@@ -1212,7 +1212,7 @@ pub impl LookupContext {
                                 trait_did: def_id,
                                 method_num: uint) -> ty::t {
             let trait_methods = ty::trait_methods(tcx, trait_did);
-            ty::mk_fn(tcx, /*bad*/copy trait_methods[method_num].fty)
+            ty::mk_bare_fn(tcx, copy trait_methods[method_num].fty)
         }
     }
 
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 1c0881b6ed5..074a0a565ae 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -81,7 +81,7 @@ use core::prelude::*;
 use middle::const_eval;
 use middle::pat_util::pat_id_map;
 use middle::pat_util;
-use middle::ty::{TyVid, Vid, FnTyBase, FnMeta, FnSig, VariantInfo_, field};
+use middle::ty::{TyVid, Vid, FnSig, VariantInfo_, field};
 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
 use middle::ty::{re_bound, br_cap_avoid, substs, arg, param_ty};
 use middle::ty;
@@ -90,7 +90,6 @@ use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
 use middle::typeck::astconv;
 use middle::typeck::check::_match::pat_ctxt;
 use middle::typeck::check::method::TransformTypeNormally;
-use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_ty;
 use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
 use middle::typeck::check::vtable::{LocationInfo, VtableContext};
 use middle::typeck::crate_ctxt;
@@ -248,8 +247,9 @@ pub fn check_bare_fn(ccx: @crate_ctxt,
                      self_info: Option<self_info>) {
     let fty = ty::node_id_to_type(ccx.tcx, id);
     match ty::get(fty).sty {
-        ty::ty_fn(ref fn_ty) => {
-            check_fn(ccx, self_info, fn_ty, decl, body, Vanilla, None)
+        ty::ty_bare_fn(ref fn_ty) => {
+            check_fn(ccx, self_info, fn_ty.purity, None,
+                     &fn_ty.sig, decl, body, Vanilla, None)
         }
         _ => ccx.tcx.sess.impossible_case(body.span,
                                  "check_bare_fn: function type expected")
@@ -258,12 +258,14 @@ pub fn check_bare_fn(ccx: @crate_ctxt,
 
 pub fn check_fn(ccx: @crate_ctxt,
                 self_info: Option<self_info>,
-                fn_ty: &ty::FnTy,
+                purity: ast::purity,
+                sigil: Option<ast::Sigil>,
+                fn_sig: &ty::FnSig,
                 decl: &ast::fn_decl,
                 body: ast::blk,
                 fn_kind: FnKind,
-                old_fcx: Option<@fn_ctxt>) {
-
+                old_fcx: Option<@fn_ctxt>)
+{
     let tcx = ccx.tcx;
     let indirect_ret = match fn_kind {
         ForLoop => true, _ => false
@@ -277,7 +279,7 @@ pub fn check_fn(ccx: @crate_ctxt,
     let {isr, self_info, fn_sig} = {
         let old_isr = option::map_default(&old_fcx, @Nil,
                                           |fcx| fcx.in_scope_regions);
-        replace_bound_regions_in_fn_sig(tcx, old_isr, self_info, &fn_ty.sig,
+        replace_bound_regions_in_fn_sig(tcx, old_isr, self_info, fn_sig,
                                         |br| ty::re_free(body.node.id, br))
     };
 
@@ -294,13 +296,10 @@ pub fn check_fn(ccx: @crate_ctxt,
     // in the case of function expressions, based on the outer context.
     let fcx: @fn_ctxt = {
         let (purity, inherited) = match old_fcx {
-            None => {
-                (fn_ty.meta.purity,
-                 blank_inherited(ccx))
-            }
+            None => (purity, blank_inherited(ccx)),
             Some(fcx) => {
-                (ty::determine_inherited_purity(fcx.purity, fn_ty.meta.purity,
-                                                fn_ty.meta.proto),
+                (ty::determine_inherited_purity(fcx.purity, purity,
+                                                sigil.get()),
                  fcx.inh)
             }
         };
@@ -1092,8 +1091,9 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
         in_fty: ty::t,
         callee_expr: @ast::expr,
         args: ~[@ast::expr],
-        deref_args: DerefArgs) -> {fty: ty::t, bot: bool} {
-
+        sugar: ast::CallSugar,
+        deref_args: DerefArgs) -> (ty::t, bool)
+    {
         let tcx = fcx.ccx.tcx;
         let mut bot = false;
 
@@ -1103,62 +1103,72 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
         debug!("check_call_inner: before universal quant., in_fty=%s",
                fcx.infcx().ty_to_str(in_fty));
 
-        let mut formal_tys;
+        let formal_tys;
 
         // This is subtle: we expect `fty` to be a function type, which
         // normally introduce a level of binding.  In this case, we want to
         // process the types bound by the function but not by any nested
         // functions.  Therefore, we match one level of structure.
-        let fty =
-            match structure_of(fcx, sp, in_fty) {
-              ty::ty_fn(ref fn_ty) => {
-                  let fn_ty =
-                    /*bad*/copy replace_bound_regions_in_fn_ty(tcx, @Nil,
-                      None, fn_ty, |_br| fcx.infcx().next_region_var(sp,
-                                                      call_expr_id)).fn_ty;
-
-                  let supplied_arg_count = args.len();
-
-                  bot |= ty::type_is_bot(fn_ty.sig.output);
-
-                  // Grab the argument types, supplying fresh type variables
-                  // if the wrong number of arguments were supplied
-                  let expected_arg_count = fn_ty.sig.inputs.len();
-                  formal_tys = if expected_arg_count == supplied_arg_count {
-                      fn_ty.sig.inputs.map(|a| a.ty)
-                  } else {
-                      tcx.sess.span_err(
-                          sp, fmt!("this function takes %u parameter%s but \
-                                    %u parameter%s supplied",
+        let ret_ty = match structure_of(fcx, sp, in_fty) {
+            ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) |
+            ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => {
+                let {fn_sig: sig, _} =
+                    replace_bound_regions_in_fn_sig(
+                        tcx, @Nil, None, sig,
+                        |_br| fcx.infcx().next_region_var(
+                            sp, call_expr_id));
+
+                let supplied_arg_count = args.len();
+
+                bot |= ty::type_is_bot(sig.output);
+
+                // Grab the argument types, supplying fresh type variables
+                // if the wrong number of arguments were supplied
+                let expected_arg_count = sig.inputs.len();
+                formal_tys = if expected_arg_count == supplied_arg_count {
+                    sig.inputs.map(|a| a.ty)
+                } else {
+                    let suffix = match sugar {
+                        ast::NoSugar => "",
+                        ast::DoSugar => " (including the closure passed by \
+                                         the `do` keyword)",
+                        ast::ForSugar => " (including the closure passed by \
+                                          the `for` keyword)"
+                    };
+                    let msg = fmt!("this function takes %u parameter%s but \
+                                    %u parameter%s supplied%s",
                                    expected_arg_count,
-                                   if expected_arg_count == 1 {
-                                       ~""
-                                   } else {
-                                       ~"s"
-                                   },
+                                   if expected_arg_count == 1 {""}
+                                   else {"s"},
                                    supplied_arg_count,
-                                   if supplied_arg_count == 1 {
-                                       ~" was"
-                                   } else {
-                                       ~"s were"
-                                   }));
-                      fcx.infcx().next_ty_vars(supplied_arg_count)
-                  };
-                  ty::mk_fn(tcx, fn_ty)
-              }
-              _ => {
-                  fcx.type_error_message(sp, |actual| {
-                      fmt!("expected function or foreign function but \
-                            found `%s`", actual) }, in_fty, None);
-                  // check each arg against "error", in order to set up
-                  // all the node type bindings
-                  formal_tys = args.map(|_x| ty::mk_err(tcx));
-                  ty::mk_err(tcx)
-              }
-            };
+                                   if supplied_arg_count == 1 {" was"}
+                                   else {"s were"},
+                                   suffix);
 
-        debug!("check_call_inner: after universal quant., fty=%s",
-               fcx.infcx().ty_to_str(fty));
+                    tcx.sess.span_err(sp, msg);
+
+                    vec::from_fn(expected_arg_count, |_| ty::mk_err(tcx))
+                };
+
+                sig.output
+            }
+
+            _ => {
+                fcx.type_error_message(sp, |actual| {
+                    fmt!("expected function or foreign function but \
+                          found `%s`", actual) }, in_fty, None);
+
+                // check each arg against "error", in order to set up
+                // all the node type bindings
+                formal_tys = args.map(|_x| ty::mk_err(tcx));
+                ty::mk_err(tcx)
+            }
+        };
+
+        debug!("check_call_inner: after universal quant., \
+                formal_tys=%? ret_ty=%s",
+               formal_tys.map(|t| fcx.infcx().ty_to_str(*t)),
+               fcx.infcx().ty_to_str(ret_ty));
 
         // Check the arguments.
         // We do this in a pretty awful way: first we typecheck any arguments
@@ -1209,7 +1219,7 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
             }
         }
 
-        {fty: fty, bot: bot}
+        (ret_ty, bot)
     }
 
     // A generic function for checking assignment expressions
@@ -1233,36 +1243,26 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
                             fn_ty: ty::t,
                             expr: @ast::expr,
                             +args: ~[@ast::expr],
-                            bot: bool)
-                         -> bool {
+                            bot: bool,
+                            sugar: ast::CallSugar) -> bool
+    {
         let mut bot = bot;
 
         // Call the generic checker.
-        let fty = {
-            let r = check_call_inner(fcx, sp, call_expr_id,
-                                     fn_ty, expr, args, DontDerefArgs);
-            bot |= r.bot;
-            r.fty
-        };
+        let (ret_ty, b) = check_call_inner(fcx, sp, call_expr_id,
+                                           fn_ty, expr, args, sugar,
+                                           DontDerefArgs);
+        bot |= b;
 
         // Pull the return type out of the type of the function.
-        match structure_of(fcx, sp, fty) {
-          ty::ty_fn(ref f) => {
-              fcx.write_ty(call_expr_id, f.sig.output);
-              return bot;
-          }
-          _ => {
-              fcx.write_ty(call_expr_id, ty::mk_err(fcx.ccx.tcx));
-              fcx.type_error_message(sp, |_actual| {
-                  ~"expected function"}, fty, None);
-              return bot;
-          }
-        }
+        fcx.write_ty(call_expr_id, ret_ty);
+        return bot;
     }
 
     // A generic function for doing all of the checking for call expressions
     fn check_call(fcx: @fn_ctxt, sp: span, call_expr_id: ast::node_id,
-                  f: @ast::expr, +args: ~[@ast::expr]) -> bool {
+                  f: @ast::expr, +args: ~[@ast::expr],
+                  sugar: ast::CallSugar) -> bool {
         // Index expressions need to be handled separately, to inform them
         // that they appear in call position.
         let mut bot = match /*bad*/copy f.node {
@@ -1278,7 +1278,8 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
                              fcx.expr_ty(f),
                              f,
                              args,
-                             bot)
+                             bot,
+                             sugar)
     }
 
     // Checks a method call.
@@ -1287,7 +1288,8 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
                          rcvr: @ast::expr,
                          method_name: ast::ident,
                          +args: ~[@ast::expr],
-                         tps: ~[@ast::Ty])
+                         tps: ~[@ast::Ty],
+                         sugar: ast::CallSugar)
                       -> bool {
         let bot = check_expr(fcx, rcvr);
         let expr_t = structurally_resolved_type(fcx,
@@ -1329,7 +1331,8 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
                              fcx.node_ty(expr.callee_id),
                              expr,
                              args,
-                             bot)
+                             bot,
+                             sugar)
     }
 
     // A generic function for checking for or for-each loops
@@ -1378,13 +1381,11 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
                              op_ex.callee_id, opname, self_t, ~[],
                              deref_args) {
           Some(ref origin) => {
-            let {fty: method_ty, bot: bot} = {
-                let method_ty = fcx.node_ty(op_ex.callee_id);
-                check_call_inner(fcx, op_ex.span, op_ex.id,
-                                 method_ty, op_ex, args, deref_args)
-            };
-            fcx.ccx.method_map.insert(op_ex.id, (*origin));
-            Some((ty::ty_fn_ret(method_ty), bot))
+              let method_ty = fcx.node_ty(op_ex.callee_id);
+              fcx.ccx.method_map.insert(op_ex.id, *origin);
+              Some(check_call_inner(fcx, op_ex.span, op_ex.id,
+                                    method_ty, op_ex, args,
+                                    ast::NoSugar, deref_args))
           }
           _ => None
         }
@@ -1472,13 +1473,14 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
         // If the or operator is used it might be that the user forgot to
         // supply the do keyword.  Let's be more helpful in that situation.
         if op == ast::or {
-          match ty::get(lhs_resolved_t).sty {
-            ty::ty_fn(_) => {
-              tcx.sess.span_note(
-                  ex.span, ~"did you forget the `do` keyword for the call?");
+            match ty::get(lhs_resolved_t).sty {
+                ty::ty_bare_fn(_) | ty::ty_closure(_) => {
+                    tcx.sess.span_note(
+                        ex.span, ~"did you forget the `do` keyword \
+                                   for the call?");
+                }
+                _ => ()
             }
-            _ => ()
-          }
         }
 
         (lhs_resolved_t, false)
@@ -1523,7 +1525,7 @@ pub 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_sigil_opt: Option<ast::Sigil>,
                      decl: &ast::fn_decl,
                      body: ast::blk,
                      fn_kind: FnKind,
@@ -1534,50 +1536,44 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
         // avoid capture of bound regions in the expected type.  See
         // def'n of br_cap_avoid() for a more lengthy explanation of
         // what's going on here.
-        // Also try to pick up inferred purity and proto, defaulting
+        // Also try to pick up inferred purity and sigil, defaulting
         // to impure and block. Note that we only will use those for
         // block syntax lambdas; that is, lambdas without explicit
-        // protos.
+        // sigils.
         let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
         let (expected_tys,
              expected_purity,
-             expected_proto,
+             expected_sigil,
              expected_onceness) = {
             match expected_sty {
-                Some(ty::ty_fn(ref fn_ty)) => {
+                Some(ty::ty_closure(ref cenv)) => {
                     let id = expr.id;
-                    let {fn_ty: fn_ty, _} =
-                        replace_bound_regions_in_fn_ty(
-                            tcx, @Nil, None, fn_ty,
+                    let {fn_sig: sig, _} =
+                        replace_bound_regions_in_fn_sig(
+                            tcx, @Nil, None, &cenv.sig,
                             |br| ty::re_bound(ty::br_cap_avoid(id, @br)));
-                    (Some({inputs: /*bad*/copy fn_ty.sig.inputs,
-                           output: fn_ty.sig.output}),
-                     fn_ty.meta.purity,
-                     fn_ty.meta.proto,
-                     fn_ty.meta.onceness)
+                    (Some(sig), cenv.purity, cenv.sigil, cenv.onceness)
                 }
                 _ => {
-                    (None, ast::impure_fn, ast::ProtoBorrowed, ast::Many)
+                    (None, ast::impure_fn, ast::BorrowedSigil, ast::Many)
                 }
             }
         };
 
         // If the proto is specified, use that, otherwise select a
         // proto based on inference.
-        let (proto, purity) = match ast_proto_opt {
+        let (sigil, purity) = match ast_sigil_opt {
             Some(p) => (p, ast::impure_fn),
-            None => (expected_proto, expected_purity)
+            None => (expected_sigil, expected_purity)
         };
 
         // construct the function type
-        let mut fn_ty = astconv::ty_of_fn_decl(
+        let mut fn_ty = astconv::ty_of_closure(
             fcx, fcx,
-            proto, purity, expected_onceness,
-            /*bounds:*/ @~[], /*opt_region:*/ None,
-            *decl, expected_tys, expr.span);
+            sigil, purity, expected_onceness,
+            None, *decl, expected_tys, expr.span);
 
-        // XXX: Bad copy.
-        let fty = ty::mk_fn(tcx, copy fn_ty);
+        let fty = ty::mk_closure(tcx, copy fn_ty);
 
         debug!("check_expr_fn_with_unifier %s fty=%s",
                fcx.expr_to_str(expr),
@@ -1587,8 +1583,8 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
 
         // We inherit the same self info as the enclosing scope,
         // since the function we're checking might capture `self`
-        check_fn(fcx.ccx, fcx.self_info, &fn_ty, decl, body,
-                 fn_kind, Some(fcx));
+        check_fn(fcx.ccx, fcx.self_info, fn_ty.purity, Some(fn_ty.sigil),
+                 &fn_ty.sig, decl, body, fn_kind, Some(fcx));
     }
 
 
@@ -1913,6 +1909,119 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
         return bot;
     }
 
+    fn check_loop_body(fcx: @fn_ctxt,
+                       expr: @ast::expr,
+                       expected: Option<ty::t>,
+                       loop_body: @ast::expr)
+    {
+        // a loop body is the special argument to a `for` loop.  We know that
+        // there will be an expected type in this context because it can only
+        // appear in the context of a call, so we get the expected type of the
+        // parameter. The catch here is that we need to validate two things:
+        // 1. a closure that returns a bool is expected
+        // 2. the closure that was given returns unit
+        let tcx = fcx.tcx();
+        let mut err_happened = false;
+        let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
+        let inner_ty = match expected_sty {
+            Some(ty::ty_closure(ref fty)) => {
+                match fcx.mk_subty(false, expr.span,
+                                   fty.sig.output, ty::mk_bool(tcx)) {
+                    result::Ok(_) => {
+                        ty::mk_closure(tcx, ty::ClosureTy {
+                            sig: FnSig {output: ty::mk_nil(tcx),
+                                        ..copy fty.sig},
+                            ..copy *fty
+                        })
+                    }
+                    result::Err(_) => {
+                        fcx.type_error_message(
+                            expr.span,
+                            |actual| {
+                                let did_you_mean = {
+                                    if ty::type_is_nil(fty.sig.output) {
+                                        "\nDid you mean to use \
+                                             `do` instead of `for`?"
+                                     } else {
+                                         ""
+                                     }
+                                };
+                                fmt!("A `for` loop iterator should expect a \
+                                      closure that returns `bool`. This \
+                                      iterator expects a closure that \
+                                      returns `%s`.%s",
+                                     actual, did_you_mean)
+                            },
+                            fty.sig.output,
+                            None);
+                        err_happened = true;
+
+                        // Kind of a hack: create a function type with
+                        // the result replaced with ty_err, to
+                        // suppress derived errors.
+                        let t = ty::replace_closure_return_type(
+                            tcx, ty::mk_closure(tcx, copy *fty),
+                            ty::mk_err(tcx));
+                        fcx.write_ty(expr.id, ty::mk_err(tcx));
+                        t
+                    }
+                }
+            }
+            _ => {
+                match expected {
+                    Some(expected_t) => {
+                        fcx.type_error_message(
+                            expr.span,
+                            |actual| {
+                                fmt!("last argument in `for` call \
+                                      has non-closure type: %s",
+                                     actual)
+                            },
+                            expected_t, None);
+                        let err_ty = ty::mk_err(tcx);
+                        fcx.write_ty(expr.id, err_ty);
+                        err_happened = true;
+                        err_ty
+                    }
+                    None => fcx.tcx().sess.impossible_case(
+                        expr.span,
+                        ~"loop body must have an expected type")
+                }
+            }
+        };
+
+        match loop_body.node {
+            ast::expr_fn_block(ref decl, ref body) => {
+                // If an error occurred, we pretend this isn't a for
+                // loop, so as to assign types to all nodes while also
+                // propagating ty_err throughout so as to suppress
+                // derived errors. If we passed in ForLoop in the
+                // error case, we'd potentially emit a spurious error
+                // message because of the indirect_ret_ty.
+                let fn_kind = if err_happened {Vanilla} else {ForLoop};
+                check_expr_fn(fcx, loop_body, None,
+                              decl, *body, fn_kind, Some(inner_ty));
+                demand::suptype(fcx, loop_body.span,
+                                inner_ty, fcx.expr_ty(loop_body));
+            }
+            ref n => {
+                die!(fmt!(
+                    "check_loop_body expected expr_fn_block, not %?", n))
+            }
+        }
+
+        let block_ty = structurally_resolved_type(
+            fcx, expr.span, fcx.node_ty(loop_body.id));
+        if err_happened {
+            fcx.write_ty(expr.id, ty::mk_err(fcx.tcx()));
+        } else {
+            let loop_body_ty =
+                ty::replace_closure_return_type(
+                    tcx, block_ty, ty::mk_bool(tcx));
+            fcx.write_ty(expr.id, loop_body_ty);
+        }
+    }
+
     let tcx = fcx.ccx.tcx;
     let id = expr.id;
     let mut bot = false;
@@ -2153,121 +2262,38 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
       ast::expr_match(discrim, ref arms) => {
         bot = _match::check_match(fcx, expr, discrim, (/*bad*/copy *arms));
       }
-      ast::expr_fn(proto, ref decl, ref body, _) => {
-        check_expr_fn(fcx, expr, Some(proto),
+      ast::expr_fn(sigil, ref decl, ref body, _) => {
+        check_expr_fn(fcx, expr, Some(sigil),
                       decl, (*body), Vanilla, expected);
       }
       ast::expr_fn_block(ref decl, ref body) => {
         check_expr_fn(fcx, expr, None,
                       decl, (*body), Vanilla, expected);
       }
-      ast::expr_loop_body(b) => {
-        // a loop body is the special argument to a `for` loop.  We know that
-        // there will be an expected type in this context because it can only
-        // appear in the context of a call, so we get the expected type of the
-        // parameter. The catch here is that we need to validate two things:
-        // 1. a closure that returns a bool is expected
-        // 2. the closure that was given returns unit
-        let mut err_happened = false;
-        let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
-        let inner_ty = match expected_sty {
-          Some(ty::ty_fn(ref fty)) => {
-            match fcx.mk_subty(false, expr.span,
-                               (*fty).sig.output, ty::mk_bool(tcx)) {
-              result::Ok(_) =>
-                  ty::mk_fn(tcx, FnTyBase {
-                      meta: (*fty).meta,
-                      sig: FnSig {output: ty::mk_nil(tcx),
-                                  ../*bad*/copy (*fty).sig}
-                  }),
-              result::Err(_) => {
-                   fcx.type_error_message(expr.span,
-                      |actual| {
-                          fmt!("A `for` loop iterator should expect a \
-                                closure that returns `bool`. This iterator \
-                                expects a closure that returns `%s`. %s",
-                               actual, if ty::type_is_nil((*fty).sig.output) {
-                                   "\nDid you mean to use `do` instead of \
-                                        `for`?" } else { "" } )
-                      },
-                      (*fty).sig.output, None);
-                err_happened = true;
-                // Kind of a hack: create a function type with the result
-                // replaced with ty_err, to suppress derived errors.
-                let t = ty::replace_fn_return_type(tcx, ty::mk_fn(tcx,
-                                                                  copy *fty),
-                                                   ty::mk_err(tcx));
-                fcx.write_ty(id, ty::mk_err(tcx));
-                t
-              }
-            }
-          }
-          _ =>
-              match expected {
-                  Some(expected_t) => {
-                      fcx.type_error_message(expr.span, |actual| {
-                          fmt!("a `loop` function's last \
-                                argument should be of function \
-                                type, not `%s`",
-                               actual)
-                      },
-                                             expected_t, None);
-                      let err_ty = ty::mk_err(tcx);
-                      fcx.write_ty(id, err_ty);
-                      err_happened = true;
-                      err_ty
-                  }
-                  None => fcx.tcx().sess.impossible_case(expr.span,
-                            ~"loop body must have an expected type")
-              }
-        };
-        match b.node {
-                ast::expr_fn_block(ref decl, ref body) => {
-                    // If an error occurred, we pretend this isn't a for
-                    // loop, so as to assign types to all nodes while also
-                    // propagating ty_err throughout so as to suppress
-                    // derived errors. If we passed in ForLoop in the
-                    // error case, we'd potentially emit a spurious error
-                    // message because of the indirect_ret_ty.
-                    let fn_kind = if err_happened { Vanilla }
-                                  else { ForLoop };
-                    check_expr_fn(fcx, b, None,
-                                  decl, *body, fn_kind, Some(inner_ty));
-                    demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
-                }
-                // argh
-                _ => die!(~"expr_fn_block")
-        }
-        let block_ty = structurally_resolved_type(
-            fcx, expr.span, fcx.node_ty(b.id));
-        if err_happened {
-            fcx.write_ty(expr.id, ty::mk_err(fcx.tcx()));
-        } else {
-            let loop_body_ty = ty::replace_fn_return_type(tcx, block_ty,
-                                                          ty::mk_bool(tcx));
-            fcx.write_ty(expr.id, loop_body_ty);
-        }
+      ast::expr_loop_body(loop_body) => {
+          check_loop_body(fcx, expr, expected, loop_body);
       }
       ast::expr_do_body(b) => {
         let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
         let inner_ty = match expected_sty {
-          Some(ty::ty_fn(ref fty)) => {
-              ty::mk_fn(tcx, (/*bad*/copy *fty))
-          }
-          _ => match expected {
-                  Some(expected_t) => {
-                      fcx.type_error_message(expr.span, |_actual| {
-                          ~"Non-function passed to a `do` \
-                            function as its last argument, or wrong number \
-                            of arguments passed to a `do` function"
-                      }, expected_t, None);
-                      let err_ty = ty::mk_err(tcx);
-                      fcx.write_ty(id, err_ty);
-                      err_ty
-                  }
-                  None => fcx.tcx().sess.impossible_case(expr.span,
-                              ~"do body must have expected type")
-              }
+            Some(ty::ty_closure(_)) => expected.get(),
+            _ => match expected {
+                Some(expected_t) => {
+                    fcx.type_error_message(expr.span, |actual| {
+                        fmt!("last argument in `do` call \
+                              has non-closure type: %s",
+                             actual)
+                    }, expected_t, None);
+                    let err_ty = ty::mk_err(tcx);
+                    fcx.write_ty(id, err_ty);
+                    err_ty
+                }
+                None => {
+                    fcx.tcx().sess.impossible_case(
+                        expr.span,
+                        ~"do body must have expected type")
+                }
+            }
         };
         match b.node {
           ast::expr_fn_block(ref decl, ref body) => {
@@ -2290,11 +2316,11 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
             };
         fcx.write_ty(id, typ);
       }
-      ast::expr_call(f, args, _) => {
-        bot = check_call(fcx, expr.span, expr.id, f, args);
+      ast::expr_call(f, args, sugar) => {
+        bot = check_call(fcx, expr.span, expr.id, f, args, sugar);
       }
-      ast::expr_method_call(rcvr, ident, tps, args, _) => {
-        bot = check_method_call(fcx, expr, rcvr, ident, args, tps);
+      ast::expr_method_call(rcvr, ident, tps, args, sugar) => {
+        bot = check_method_call(fcx, expr, rcvr, ident, args, tps, sugar);
       }
       ast::expr_cast(e, t) => {
         bot = check_expr(fcx, e);
@@ -3088,20 +3114,18 @@ pub fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
                  arg(ast::by_ref, visitor_trait)], ty::mk_nil(tcx))
       }
       ~"frame_address" => {
-        let fty = ty::mk_fn(ccx.tcx, FnTyBase {
-            meta: FnMeta {purity: ast::impure_fn,
-                          proto: ast::ProtoBorrowed,
-                          onceness: ast::Once,
-                          region: ty::re_bound(ty::br_anon(0)),
-                          bounds: @~[]},
-            sig: FnSig {
-                inputs: ~[arg {
-                    mode: ast::expl(ast::by_val),
-                    ty: ty::mk_imm_ptr(
-                        ccx.tcx,
-                        ty::mk_mach_uint(ccx.tcx, ast::ty_u8))
-                }],
-                output: ty::mk_nil(ccx.tcx)}
+        let fty = ty::mk_closure(ccx.tcx, ty::ClosureTy {
+            purity: ast::impure_fn,
+            sigil: ast::BorrowedSigil,
+            onceness: ast::Once,
+            region: ty::re_bound(ty::br_anon(0)),
+            sig: ty::FnSig {
+                inputs: ~[arg {mode: ast::expl(ast::by_val),
+                               ty: ty::mk_imm_ptr(
+                                   ccx.tcx,
+                                   ty::mk_mach_uint(ccx.tcx, ast::ty_u8))}],
+                output: ty::mk_nil(ccx.tcx)
+            }
         });
         (0u, ~[arg(ast::by_ref, fty)], ty::mk_nil(tcx))
       }
@@ -3324,12 +3348,9 @@ pub fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
         return;
       }
     };
-    let fty = ty::mk_fn(tcx, FnTyBase {
-        meta: FnMeta {purity: ast::unsafe_fn,
-                      proto: ast::ProtoBare,
-                      onceness: ast::Many,
-                      region: ty::re_static,
-                      bounds: @~[]},
+    let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
+        purity: ast::unsafe_fn,
+        abi: ast::RustAbi,
         sig: FnSig {inputs: inputs,
                     output: output}
     });
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 952c1a9fcd8..9dfaaeebc8f 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -32,7 +32,7 @@ use core::prelude::*;
 use middle::freevars::get_freevars;
 use middle::pat_util::{pat_bindings, pat_is_binding};
 use middle::ty::{encl_region, re_scope};
-use middle::ty::{ty_fn_proto, vstore_box, vstore_fixed, vstore_slice};
+use middle::ty::{vstore_box, vstore_fixed, vstore_slice};
 use middle::ty::{vstore_uniq};
 use middle::ty;
 use middle::typeck::check::fn_ctxt;
@@ -42,7 +42,7 @@ use middle::typeck::infer::{resolve_type};
 use util::ppaux::{note_and_explain_region, ty_to_str};
 
 use core::result;
-use syntax::ast::{ProtoBare, ProtoBox, ProtoUniq, ProtoBorrowed};
+use syntax::ast::{ManagedSigil, OwnedSigil, BorrowedSigil};
 use syntax::ast::{def_arg, def_binding, def_local, def_self, def_upvar};
 use syntax::ast;
 use syntax::codemap::span;
@@ -59,10 +59,9 @@ pub fn encl_region_of_def(fcx: @fn_ctxt, def: ast::def) -> ty::Region {
         def_self(node_id, _) | def_binding(node_id, _) =>
             return encl_region(tcx, node_id),
         def_upvar(_, subdef, closure_id, body_id) => {
-            match ty_fn_proto(fcx.node_ty(closure_id)) {
-                ProtoBare => tcx.sess.bug(~"ProtoBare with upvars?!"),
-                ProtoBorrowed => encl_region_of_def(fcx, *subdef),
-                ProtoBox | ProtoUniq => re_scope(body_id)
+            match ty::ty_closure_sigil(fcx.node_ty(closure_id)) {
+                BorrowedSigil => encl_region_of_def(fcx, *subdef),
+                ManagedSigil | OwnedSigil => re_scope(body_id)
             }
         }
         _ => {
@@ -278,11 +277,9 @@ pub fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) {
         ast::expr_fn(*) | ast::expr_fn_block(*) => {
             let function_type = rcx.resolve_node_type(expr.id);
             match ty::get(function_type).sty {
-                ty::ty_fn(ref fn_ty) => {
-                    if fn_ty.meta.proto == ast::ProtoBorrowed {
-                        constrain_free_variables(
-                            rcx, fn_ty.meta.region, expr);
-                    }
+                ty::ty_closure(ty::ClosureTy {sigil: ast::BorrowedSigil,
+                                              region: region, _}) => {
+                    constrain_free_variables(rcx, region, expr);
                 }
                 _ => ()
             }
diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs
index 8ea35824e32..f0956df545c 100644
--- a/src/librustc/middle/typeck/check/regionmanip.rs
+++ b/src/librustc/middle/typeck/check/regionmanip.rs
@@ -12,7 +12,6 @@
 
 use core::prelude::*;
 
-use middle::ty::{FnTyBase};
 use middle::ty;
 use middle::typeck::check::self_info;
 use middle::typeck::isr_alist;
@@ -27,22 +26,6 @@ use syntax::print::pprust::{expr_to_str};
 
 // Helper functions related to manipulating region types.
 
-pub fn replace_bound_regions_in_fn_ty(
-    tcx: ty::ctxt,
-    isr: isr_alist,
-    self_info: Option<self_info>,
-    fn_ty: &ty::FnTy,
-    mapf: fn(ty::bound_region) -> ty::Region) ->
-    {isr: isr_alist, self_info: Option<self_info>, fn_ty: ty::FnTy} {
-    let {isr, self_info, fn_sig} =
-        replace_bound_regions_in_fn_sig(
-            tcx, isr, self_info, &fn_ty.sig, mapf);
-    {isr: isr,
-     self_info: self_info,
-     fn_ty: FnTyBase {meta: fn_ty.meta,
-                      sig: fn_sig}}
-}
-
 pub fn replace_bound_regions_in_fn_sig(
     tcx: ty::ctxt,
     isr: isr_alist,
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 9f2af3ec003..abd4697eb31 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -233,7 +233,7 @@ pub fn lookup_vtable(vcx: &VtableContext,
             relate_trait_tys(vcx, location_info, trait_ty, ty);
             if !allow_unsafe && !is_early {
                 for vec::each(*ty::trait_methods(tcx, did)) |m| {
-                    if ty::type_has_self(ty::mk_fn(tcx, /*bad*/copy m.fty)) {
+                    if ty::type_has_self(ty::mk_bare_fn(tcx, copy m.fty)) {
                         tcx.sess.span_err(
                             location_info.span,
                             ~"a boxed trait with self types may not be \
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index 324cdcc261f..8fc8c4f6cbb 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -26,10 +26,10 @@ use middle::resolve::{Impl, MethodInfo};
 use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, bound_copy, get};
 use middle::ty::{kind_can_be_copied, lookup_item_type, param_bounds, subst};
 use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err};
-use middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_infer, ty_int, ty_nil};
+use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil};
 use middle::ty::{ty_opaque_box, ty_param, ty_param_bounds_and_ty, ty_ptr};
 use middle::ty::{ty_rec, ty_rptr, ty_self, ty_struct, ty_trait, ty_tup};
-use middle::ty::{ty_type, ty_uint, ty_uniq};
+use middle::ty::{ty_type, ty_uint, ty_uniq, ty_bare_fn, ty_closure};
 use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_kind_ext};
 use middle::ty::{type_is_ty_var};
 use middle::ty;
@@ -108,7 +108,7 @@ pub fn get_base_type(inference_context: @InferCtxt,
 
         ty_nil | ty_bot | ty_bool | ty_int(*) | ty_uint(*) | ty_float(*) |
         ty_estr(*) | ty_evec(*) | ty_rec(*) |
-        ty_fn(*) | ty_tup(*) | ty_infer(*) |
+        ty_bare_fn(*) | ty_closure(*) | ty_tup(*) | ty_infer(*) |
         ty_param(*) | ty_self | ty_type | ty_opaque_box |
         ty_opaque_closure_ptr(*) | ty_unboxed_vec(*) | ty_err => {
             debug!("(getting base type) no base type; found %?",
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index b7b7899883b..120fd89e5eb 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -33,10 +33,10 @@ are represented as `ty_param()` instances.
 use core::prelude::*;
 
 use metadata::csearch;
-use middle::ty::{FnMeta, FnSig, FnTyBase, InstantiatedTraitRef, arg};
+use middle::ty::{InstantiatedTraitRef, arg};
 use middle::ty::{substs, ty_param_substs_and_ty};
 use middle::ty;
-use middle::typeck::astconv::{ast_conv, ty_of_fn_decl, ty_of_arg};
+use middle::typeck::astconv::{ast_conv, ty_of_arg};
 use middle::typeck::astconv::{ast_ty_to_ty};
 use middle::typeck::astconv;
 use middle::typeck::infer;
@@ -153,9 +153,10 @@ pub impl @crate_ctxt: ast_conv {
 
 pub fn get_enum_variant_types(ccx: @crate_ctxt,
                               enum_ty: ty::t,
-                              variants: ~[ast::variant],
-                              ty_params: ~[ast::ty_param],
-                              rp: Option<ty::region_variance>) {
+                              variants: &[ast::variant],
+                              ty_params: &[ast::ty_param],
+                              rp: Option<ty::region_variance>)
+{
     let tcx = ccx.tcx;
 
     // Create a set of parameter types shared among all the variants.
@@ -166,58 +167,35 @@ pub fn get_enum_variant_types(ccx: @crate_ctxt,
         match variant.node.kind {
             ast::tuple_variant_kind(ref args) if args.len() > 0 => {
                 let rs = type_rscope(rp);
-                let args = args.map(|va| {
-                    let arg_ty = ccx.to_ty(rs, va.ty);
-                    arg { mode: ast::expl(ast::by_copy), ty: arg_ty }
-                });
-                result_ty = Some(ty::mk_fn(tcx, FnTyBase {
-                    meta: FnMeta {purity: ast::pure_fn,
-                                  proto: ast::ProtoBare,
-                                  onceness: ast::Many,
-                                  bounds: @~[],
-                                  region: ty::re_static},
-                    sig: FnSig {inputs: args,
-                                output: enum_ty}
-                }));
+                let input_tys = args.map(|va| ccx.to_ty(rs, va.ty));
+                result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty));
             }
+
             ast::tuple_variant_kind(_) => {
                 result_ty = Some(enum_ty);
             }
+
             ast::struct_variant_kind(struct_def) => {
-                // XXX: Merge with computation of the the same value below?
-                let tpt = {
-                    bounds: ty_param_bounds(ccx, /*bad*/copy ty_params),
-                    region_param: rp,
-                    ty: enum_ty
-                };
-                convert_struct(
-                    ccx,
-                    rp,
-                    struct_def,
-                    /*bad*/copy ty_params,
-                    tpt,
-                    variant.node.id);
-                // Compute the ctor arg types from the struct fields
-                let struct_fields = do struct_def.fields.map |struct_field| {
-                    arg {
-                        mode: ast::expl(ast::by_val),
-                        ty: ty::node_id_to_type(ccx.tcx, struct_field.node.id)
-                    }
-                };
-                result_ty = Some(ty::mk_fn(tcx, FnTyBase {
-                    meta: FnMeta {purity: ast::pure_fn,
-                                  proto: ast::ProtoBare,
-                                  onceness: ast::Many,
-                                  bounds: @~[],
-                                  region: ty::re_static},
-                    sig: FnSig {inputs: struct_fields, output: enum_ty }}));
+                let tpt = {bounds: ty_param_bounds(ccx, ty_params),
+                           region_param: rp,
+                           ty: enum_ty};
+
+                convert_struct(ccx,
+                               rp,
+                               struct_def,
+                               ty_params.to_vec(),
+                               tpt,
+                               variant.node.id);
+
+                let input_tys = struct_def.fields.map(
+                    |f| ty::node_id_to_type(ccx.tcx, f.node.id));
+                result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty));
             }
+
             ast::enum_variant_kind(ref enum_definition) => {
-                get_enum_variant_types(ccx,
-                                       enum_ty,
-                                       /*bad*/copy enum_definition.variants,
-                                       /*bad*/copy ty_params,
-                                       rp);
+                get_enum_variant_types(ccx, enum_ty,
+                                       enum_definition.variants,
+                                       ty_params, rp);
                 result_ty = None;
             }
         };
@@ -225,11 +203,9 @@ pub fn get_enum_variant_types(ccx: @crate_ctxt,
         match result_ty {
             None => {}
             Some(result_ty) => {
-                let tpt = {
-                    bounds: ty_param_bounds(ccx, /*bad*/copy ty_params),
-                    region_param: rp,
-                    ty: result_ty
-                };
+                let tpt = {bounds: ty_param_bounds(ccx, ty_params),
+                           region_param: rp,
+                           ty: result_ty};
                 tcx.tcache.insert(local_def(variant.node.id), tpt);
                 write_ty_to_tcx(tcx, variant.node.id, result_ty);
             }
@@ -279,7 +255,7 @@ pub fn ensure_trait_methods(ccx: @crate_ctxt,
         };
         let ty = ty::subst(ccx.tcx,
                            &substs,
-                           ty::mk_fn(ccx.tcx, /*bad*/copy m.fty));
+                           ty::mk_bare_fn(ccx.tcx, copy m.fty));
         let bounds = @(*trait_bounds + ~[@~[ty::bound_trait(trait_ty)]]
                        + *m.tps);
         ccx.tcx.tcache.insert(local_def(am.id),
@@ -305,7 +281,7 @@ pub fn ensure_trait_methods(ccx: @crate_ctxt,
                 ast::provided(method) => def_id = local_def(method.id)
             }
 
-            let trait_bounds = ty_param_bounds(ccx, copy *params);
+            let trait_bounds = ty_param_bounds(ccx, *params);
             let ty_m = trait_method_to_ty_method(*m);
             let method_ty = ty_of_ty_method(ccx, ty_m, region_paramd, def_id);
             if ty_m.self_ty.node == ast::sty_static {
@@ -458,7 +434,7 @@ pub fn compare_impl_method(tcx: ty::ctxt,
     //   that correspond to the parameters we will find on the impl
     // - replace self region with a fresh, dummy region
     let impl_fty = {
-        let impl_fty = ty::mk_fn(tcx, /*bad*/copy impl_m.fty);
+        let impl_fty = ty::mk_bare_fn(tcx, copy impl_m.fty);
         debug!("impl_fty (pre-subst): %s", ppaux::ty_to_str(tcx, impl_fty));
         replace_bound_self(tcx, impl_fty, dummy_self_r)
     };
@@ -476,7 +452,7 @@ pub fn compare_impl_method(tcx: ty::ctxt,
             self_ty: Some(self_ty),
             tps: vec::append(trait_tps, dummy_tps)
         };
-        let trait_fty = ty::mk_fn(tcx, /*bad*/copy trait_m.fty);
+        let trait_fty = ty::mk_bare_fn(tcx, copy trait_m.fty);
         debug!("trait_fty (pre-subst): %s", ppaux::ty_to_str(tcx, trait_fty));
         ty::subst(tcx, &substs, trait_fty)
     };
@@ -583,9 +559,9 @@ pub fn convert_methods(ccx: @crate_ctxt,
 
     let tcx = ccx.tcx;
     do vec::map(ms) |m| {
-        let bounds = ty_param_bounds(ccx, /*bad*/copy m.tps);
+        let bounds = ty_param_bounds(ccx, m.tps);
         let mty = ty_of_method(ccx, *m, rp);
-        let fty = ty::mk_fn(tcx, /*bad*/copy mty.fty);
+        let fty = ty::mk_bare_fn(tcx, copy mty.fty);
         tcx.tcache.insert(
             local_def(m.id),
 
@@ -626,13 +602,11 @@ pub fn convert(ccx: @crate_ctxt, it: @ast::item) {
         ensure_no_ty_param_bounds(ccx, it.span, *ty_params, "enumeration");
         let tpt = ty_of_item(ccx, it);
         write_ty_to_tcx(tcx, it.id, tpt.ty);
-        get_enum_variant_types(ccx,
-                               tpt.ty,
-                               /*bad*/copy (*enum_definition).variants,
-                               /*bad*/copy *ty_params, rp);
+        get_enum_variant_types(ccx, tpt.ty, enum_definition.variants,
+                               *ty_params, rp);
       }
       ast::item_impl(ref tps, trait_ref, selfty, ref ms) => {
-        let i_bounds = ty_param_bounds(ccx, /*bad*/copy *tps);
+        let i_bounds = ty_param_bounds(ccx, *tps);
         let selfty = ccx.to_ty(type_rscope(rp), selfty);
         write_ty_to_tcx(tcx, it.id, selfty);
         tcx.tcache.insert(local_def(it.id),
@@ -695,13 +669,12 @@ pub fn convert_struct(ccx: @crate_ctxt,
 
     do option::iter(&struct_def.dtor) |dtor| {
         // Write the dtor type
-        let t_dtor = ty::mk_fn(
+        let t_dtor = ty::mk_bare_fn(
             tcx,
-            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));
+            astconv::ty_of_bare_fn(
+                ccx, type_rscope(rp),
+                ast::impure_fn, ast::RustAbi,
+                ast_util::dtor_dec()));
         write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
         tcx.tcache.insert(local_def(dtor.node.id),
                           {bounds: tpt.bounds,
@@ -727,25 +700,11 @@ pub fn convert_struct(ccx: @crate_ctxt,
                 tcx.tcache.insert(local_def(ctor_id), tpt);
             } else if struct_def.fields[0].node.kind == ast::unnamed_field {
                 // Tuple-like.
-                let ctor_fn_ty = ty::mk_fn(tcx, FnTyBase {
-                    meta: FnMeta {
-                        purity: ast::pure_fn,
-                        proto: ast::ProtoBare,
-                        onceness: ast::Many,
-                        bounds: @~[],
-                        region: ty::re_static
-                    },
-                    sig: FnSig {
-                        inputs: do struct_def.fields.map |field| {
-                            arg {
-                                mode: ast::expl(ast::by_copy),
-                                ty: ccx.tcx.tcache.get
-                                        (&local_def(field.node.id)).ty
-                            }
-                        },
-                        output: selfty
-                    }
-                });
+                let inputs =
+                    struct_def.fields.map(
+                        |field| ccx.tcx.tcache.get(
+                            &local_def(field.node.id)).ty);
+                let ctor_fn_ty = ty::mk_ctor_fn(tcx, inputs, selfty);
                 write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty);
                 tcx.tcache.insert(local_def(ctor_id), {
                     bounds: tpt.bounds,
@@ -770,11 +729,9 @@ pub fn ty_of_method(ccx: @crate_ctxt,
                     m: @ast::method,
                     rp: Option<ty::region_variance>) -> ty::method {
     {ident: m.ident,
-     tps: ty_param_bounds(ccx, /*bad*/copy m.tps),
-     fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::ProtoBare,
-                        m.purity, ast::Many,
-                        /*bounds:*/ @~[], /*opt_region:*/ None,
-                        m.decl, None, m.span),
+     tps: ty_param_bounds(ccx, m.tps),
+     fty: astconv::ty_of_bare_fn(ccx, type_rscope(rp), m.purity,
+                                 ast::RustAbi, m.decl),
      self_ty: m.self_ty.node,
      vis: m.vis,
      def_id: local_def(m.id)}
@@ -785,11 +742,9 @@ pub fn ty_of_ty_method(self: @crate_ctxt,
                        rp: Option<ty::region_variance>,
                        id: ast::def_id) -> ty::method {
     {ident: m.ident,
-     tps: ty_param_bounds(self, /*bad*/copy m.tps),
-     fty: ty_of_fn_decl(self, type_rscope(rp), ast::ProtoBare,
-                        m.purity, ast::Many,
-                        /*bounds:*/ @~[], /*opt_region:*/ None,
-                        m.decl, None, m.span),
+     tps: ty_param_bounds(self, m.tps),
+     fty: astconv::ty_of_bare_fn(self, type_rscope(rp), m.purity,
+                                 ast::RustAbi, m.decl),
      // assume public, because this is only invoked on trait methods
      self_ty: m.self_ty.node,
      vis: ast::public,
@@ -844,13 +799,11 @@ pub 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::ProtoBare, purity, ast::Many,
-                                 /*bounds:*/ @~[], /*opt_region:*/ None,
-                                 decl, None, it.span);
+        let tofd = astconv::ty_of_bare_fn(ccx, empty_rscope, purity,
+                                          ast::RustAbi, decl);
         let tpt = {bounds: bounds,
                    region_param: None,
-                   ty: ty::mk_fn(ccx.tcx, tofd)};
+                   ty: ty::mk_bare_fn(ccx.tcx, tofd)};
         debug!("type of %s (id %d) is %s",
                tcx.sess.str_of(it.ident),
                it.id,
@@ -976,7 +929,7 @@ pub fn compute_bounds(ccx: @crate_ctxt,
 }
 
 pub fn ty_param_bounds(ccx: @crate_ctxt,
-                       params: ~[ast::ty_param]) -> @~[ty::param_bounds] {
+                       params: &[ast::ty_param]) -> @~[ty::param_bounds] {
     @do params.map |param| {
         match ccx.tcx.ty_param_bounds.find(&param.id) {
           Some(bs) => bs,
@@ -999,15 +952,13 @@ pub fn ty_of_foreign_fn_decl(ccx: @crate_ctxt,
     let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, rb, *a, None) );
     let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
 
-    let t_fn = ty::mk_fn(ccx.tcx, FnTyBase {
-        meta: FnMeta {purity: ast::unsafe_fn,
-                      onceness: ast::Many,
-                      proto: ast::ProtoBare,
-                      bounds: @~[],
-                      region: ty::re_static},
-        sig: FnSig {inputs: input_tys,
-                    output: output_ty}
-    });
+    let t_fn = ty::mk_bare_fn(
+        ccx.tcx,
+        ty::BareFnTy {
+            abi: ast::RustAbi,
+            purity: ast::unsafe_fn,
+            sig: ty::FnSig {inputs: input_tys, output: output_ty}
+        });
     let tpt = {bounds: bounds, region_param: None, ty: t_fn};
     ccx.tcx.tcache.insert(def_id, tpt);
     return tpt;
@@ -1017,8 +968,7 @@ pub fn mk_ty_params(ccx: @crate_ctxt, atps: ~[ast::ty_param])
     -> {bounds: @~[ty::param_bounds], params: ~[ty::t]} {
 
     let mut i = 0u;
-    // XXX: Bad copy.
-    let bounds = ty_param_bounds(ccx, copy atps);
+    let bounds = ty_param_bounds(ccx, atps);
     {bounds: bounds,
      params: vec::map(atps, |atp| {
          let t = ty::mk_param(ccx.tcx, i, local_def(atp.id));
diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs
index f0fe2deffdf..5d291fdde77 100644
--- a/src/librustc/middle/typeck/infer/coercion.rs
+++ b/src/librustc/middle/typeck/infer/coercion.rs
@@ -69,7 +69,7 @@ use core::prelude::*;
 use middle::ty::{TyVar, AutoPtr, AutoBorrowVec, AutoBorrowFn};
 use middle::ty::{AutoAdjustment, AutoRef};
 use middle::ty::{vstore_slice, vstore_box, vstore_uniq, vstore_fixed};
-use middle::ty::{FnMeta, FnTyBase, mt};
+use middle::ty::{mt};
 use middle::ty;
 use middle::typeck::infer::{CoerceResult, resolve_type};
 use middle::typeck::infer::combine::CombineFields;
@@ -117,7 +117,7 @@ impl Coerce {
                 };
             }
 
-            ty::ty_fn(ref b_f) if b_f.meta.proto == ast::ProtoBorrowed => {
+            ty::ty_closure(ty::ClosureTy {sigil: ast::BorrowedSigil, _}) => {
                 return do self.unpack_actual_value(a) |sty_a| {
                     self.coerce_borrowed_fn(a, sty_a, b)
                 };
@@ -134,7 +134,7 @@ impl Coerce {
 
         do self.unpack_actual_value(a) |sty_a| {
             match *sty_a {
-                ty::ty_fn(ref a_f) if a_f.meta.proto == ast::ProtoBare => {
+                ty::ty_bare_fn(ref a_f) => {
                     // Bare functions are coercable to any closure type.
                     //
                     // FIXME(#3320) this should go away and be
@@ -289,9 +289,9 @@ impl Coerce {
                b.inf_str(self.infcx));
 
         let fn_ty = match *sty_a {
-            ty::ty_fn(ref f) if f.meta.proto == ast::ProtoBox => {f}
-            ty::ty_fn(ref f) if f.meta.proto == ast::ProtoUniq => {f}
-            ty::ty_fn(ref f) if f.meta.proto == ast::ProtoBare => {
+            ty::ty_closure(ref f) if f.sigil == ast::ManagedSigil => copy *f,
+            ty::ty_closure(ref f) if f.sigil == ast::OwnedSigil => copy *f,
+            ty::ty_bare_fn(ref f) => {
                 return self.coerce_from_bare_fn(a, f, b);
             }
             _ => {
@@ -300,12 +300,13 @@ impl Coerce {
         };
 
         let r_borrow = self.infcx.next_region_var_nb(self.span);
-        let meta = FnMeta {proto: ast::ProtoBorrowed,
-                           region: r_borrow,
-                           ..fn_ty.meta};
-        let a_borrowed = ty::mk_fn(self.infcx.tcx,
-                                   FnTyBase {meta: meta,
-                                             sig: copy fn_ty.sig});
+        let a_borrowed = ty::mk_closure(
+            self.infcx.tcx,
+            ty::ClosureTy {
+                sigil: ast::BorrowedSigil,
+                region: r_borrow,
+                ..fn_ty
+            });
 
         if_ok!(self.subtype(a_borrowed, b));
         Ok(Some(@AutoAdjustment {
@@ -320,7 +321,7 @@ impl Coerce {
 
     fn coerce_from_bare_fn(&self,
                            a: ty::t,
-                           fn_ty_a: &ty::FnTy,
+                           fn_ty_a: &ty::BareFnTy,
                            b: ty::t) -> CoerceResult
     {
         do self.unpack_actual_value(b) |sty_b| {
@@ -330,7 +331,7 @@ impl Coerce {
 
     fn coerce_from_bare_fn_post_unpack(&self,
                                        a: ty::t,
-                                       fn_ty_a: &ty::FnTy,
+                                       fn_ty_a: &ty::BareFnTy,
                                        b: ty::t,
                                        sty_b: &ty::sty) -> CoerceResult
     {
@@ -338,18 +339,18 @@ impl Coerce {
                a.inf_str(self.infcx), b.inf_str(self.infcx));
 
         let fn_ty_b = match *sty_b {
-            ty::ty_fn(ref f) if f.meta.proto != ast::ProtoBare => {f}
+            ty::ty_closure(ref f) => {copy *f}
             _ => {
                 return self.subtype(a, b);
             }
         };
 
-            // for now, bare fn and closures have the same
-            // representation
-        let a_adapted = ty::mk_fn(self.infcx.tcx,
-                                  FnTyBase {meta: copy fn_ty_b.meta,
-                                            sig: copy fn_ty_a.sig});
-        self.subtype(a_adapted, b)
+        // for now, bare fn and closures have the same
+        // representation
+        let a_closure = ty::mk_closure(
+            self.infcx.tcx,
+            ty::ClosureTy {sig: copy fn_ty_a.sig, ..fn_ty_b});
+        self.subtype(a_closure, b)
     }
 
     fn coerce_unsafe_ptr(&self,
diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs
index 819348e744e..7737327bc0c 100644
--- a/src/librustc/middle/typeck/infer/combine.rs
+++ b/src/librustc/middle/typeck/infer/combine.rs
@@ -56,7 +56,7 @@
 
 use core::prelude::*;
 
-use middle::ty::{FloatVar, FnTyBase, FnMeta, FnSig, IntVar, TyVar};
+use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
 use middle::ty::{IntType, UintType, arg, substs};
 use middle::ty;
 use middle::typeck::infer::glb::Glb;
@@ -94,14 +94,17 @@ pub trait Combine {
     fn self_tys(a: Option<ty::t>, b: Option<ty::t>) -> cres<Option<ty::t>>;
     fn substs(did: ast::def_id, as_: &ty::substs,
               bs: &ty::substs) -> cres<ty::substs>;
-    fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy>;
+    fn bare_fn_tys(a: &ty::BareFnTy,
+                   b: &ty::BareFnTy) -> cres<ty::BareFnTy>;
+    fn closure_tys(a: &ty::ClosureTy,
+                   b: &ty::ClosureTy) -> cres<ty::ClosureTy>;
     fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig>;
-    fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta>;
     fn flds(a: ty::field, b: ty::field) -> cres<ty::field>;
     fn modes(a: ast::mode, b: ast::mode) -> cres<ast::mode>;
     fn args(a: ty::arg, b: ty::arg) -> cres<ty::arg>;
-    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto>;
+    fn sigils(p1: ast::Sigil, p2: ast::Sigil) -> cres<ast::Sigil>;
     fn purities(a: purity, b: purity) -> cres<purity>;
+    fn abis(a: ast::Abi, b: ast::Abi) -> cres<ast::Abi>;
     fn oncenesses(a: Onceness, b: Onceness) -> cres<Onceness>;
     fn contraregions(a: ty::Region, b: ty::Region) -> cres<ty::Region>;
     fn regions(a: ty::Region, b: ty::Region) -> cres<ty::Region>;
@@ -287,12 +290,12 @@ pub fn super_self_tys<C:Combine>(
     }
 }
 
-pub fn super_protos<C: Combine>(
-    self: &C, p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
+pub fn super_sigils<C: Combine>(
+    self: &C, p1: ast::Sigil, p2: ast::Sigil) -> cres<ast::Sigil> {
     if p1 == p2 {
         Ok(p1)
     } else {
-        Err(ty::terr_proto_mismatch(expected_found(self, p1, p2)))
+        Err(ty::terr_sigil_mismatch(expected_found(self, p1, p2)))
     }
 }
 
@@ -350,21 +353,45 @@ pub fn super_vstores<C:Combine>(
     }
 }
 
-pub fn super_fn_metas<C:Combine>(
-    self: &C, a_f: &ty::FnMeta, b_f: &ty::FnMeta) -> cres<ty::FnMeta> {
-    let p = if_ok!(self.protos(a_f.proto, b_f.proto));
+pub fn super_closure_tys<C:Combine>(
+    self: &C, a_f: &ty::ClosureTy, b_f: &ty::ClosureTy) -> cres<ty::ClosureTy>
+{
+    let p = if_ok!(self.sigils(a_f.sigil, b_f.sigil));
     let r = if_ok!(self.contraregions(a_f.region, b_f.region));
     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,
-               onceness: onceness,
-               region: r,
-               bounds: a_f.bounds}) // XXX: This is wrong!
+    let sig = if_ok!(self.fn_sigs(&a_f.sig, &b_f.sig));
+    Ok(ty::ClosureTy {purity: purity,
+                      sigil: p,
+                      onceness: onceness,
+                      region: r,
+                      sig: sig})
+}
+
+pub fn super_abis<C:Combine>(
+    self: &C, a: ast::Abi, b: ast::Abi) -> cres<ast::Abi>
+{
+    if a == b {
+        Ok(a)
+    } else {
+        Err(ty::terr_abi_mismatch(expected_found(self, a, b)))
+    }
+}
+
+pub fn super_bare_fn_tys<C:Combine>(
+    self: &C, a_f: &ty::BareFnTy, b_f: &ty::BareFnTy) -> cres<ty::BareFnTy>
+{
+    let purity = if_ok!(self.purities(a_f.purity, b_f.purity));
+    let abi = if_ok!(self.abis(a_f.abi, b_f.abi));
+    let sig = if_ok!(self.fn_sigs(&a_f.sig, &b_f.sig));
+    Ok(ty::BareFnTy {purity: purity,
+                     abi: abi,
+                     sig: sig})
 }
 
 pub fn super_fn_sigs<C:Combine>(
-    self: &C, a_f: &ty::FnSig, b_f: &ty::FnSig) -> cres<ty::FnSig> {
+    self: &C, a_f: &ty::FnSig, b_f: &ty::FnSig) -> cres<ty::FnSig>
+{
     fn argvecs<C:Combine>(self: &C,
                           +a_args: ~[ty::arg],
                           +b_args: ~[ty::arg]) -> cres<~[ty::arg]>
@@ -384,13 +411,6 @@ pub fn super_fn_sigs<C:Combine>(
     }
 }
 
-pub fn super_fns<C:Combine>(
-    self: &C, a_f: &ty::FnTy, b_f: &ty::FnTy) -> cres<ty::FnTy> {
-    let m = if_ok!(self.fn_metas(&a_f.meta, &b_f.meta));
-    let s = if_ok!(self.fn_sigs(&a_f.sig, &b_f.sig));
-    Ok(FnTyBase {meta: m, sig: s})
-}
-
 pub fn super_tys<C:Combine>(
     self: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
     let tcx = self.infcx().tcx;
@@ -551,9 +571,15 @@ pub fn super_tys<C:Combine>(
         }
       }
 
-      (ty::ty_fn(ref a_fty), ty::ty_fn(ref b_fty)) => {
-        do self.fns(a_fty, b_fty).chain |fty| {
-            Ok(ty::mk_fn(tcx, fty))
+      (ty::ty_bare_fn(ref a_fty), ty::ty_bare_fn(ref b_fty)) => {
+        do self.bare_fn_tys(a_fty, b_fty).chain |fty| {
+            Ok(ty::mk_bare_fn(tcx, fty))
+        }
+      }
+
+      (ty::ty_closure(ref a_fty), ty::ty_closure(ref b_fty)) => {
+        do self.closure_tys(a_fty, b_fty).chain |fty| {
+            Ok(ty::mk_closure(tcx, fty))
         }
       }
 
diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs
index 58d9f1019ae..382d5f24cc7 100644
--- a/src/librustc/middle/typeck/infer/glb.rs
+++ b/src/librustc/middle/typeck/infer/glb.rs
@@ -267,16 +267,22 @@ pub impl Glb: Combine {
         }
     }
 
-    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
-        super_protos(&self, p1, p2)
+    fn sigils(p1: ast::Sigil, p2: ast::Sigil) -> cres<ast::Sigil> {
+        super_sigils(&self, p1, p2)
     }
 
-    fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
-        super_fns(&self, a, b)
+    fn abis(p1: ast::Abi, p2: ast::Abi) -> cres<ast::Abi> {
+        super_abis(&self, p1, p2)
     }
 
-    fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
-        super_fn_metas(&self, a, b)
+    fn bare_fn_tys(a: &ty::BareFnTy,
+                   b: &ty::BareFnTy) -> cres<ty::BareFnTy> {
+        super_bare_fn_tys(&self, a, b)
+    }
+
+    fn closure_tys(a: &ty::ClosureTy,
+                   b: &ty::ClosureTy) -> cres<ty::ClosureTy> {
+        super_closure_tys(&self, a, b)
     }
 
     fn substs(did: ast::def_id,
diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs
index 4f7bedd8149..4bf8a0bae86 100644
--- a/src/librustc/middle/typeck/infer/lattice.rs
+++ b/src/librustc/middle/typeck/infer/lattice.rs
@@ -71,23 +71,6 @@ pub impl ty::t: LatticeValue {
     }
 }
 
-pub impl FnMeta: LatticeValue {
-    static fn sub(cf: &CombineFields,
-                  a: &FnMeta, b: &FnMeta) -> ures {
-        Sub(*cf).fn_metas(a, b).to_ures()
-    }
-
-    static fn lub(cf: &CombineFields,
-                  a: &FnMeta, b: &FnMeta) -> cres<FnMeta> {
-        Lub(*cf).fn_metas(a, b)
-    }
-
-    static fn glb(cf: &CombineFields,
-                  a: &FnMeta, b: &FnMeta) -> cres<FnMeta> {
-        Glb(*cf).fn_metas(a, b)
-    }
-}
-
 pub impl CombineFields {
     fn var_sub_var<T:Copy InferStr LatticeValue,
                    V:Copy Eq ToStr Vid UnifyVid<Bounds<T>>>(
diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs
index f24d245db58..44ad367c9dc 100644
--- a/src/librustc/middle/typeck/infer/lub.rs
+++ b/src/librustc/middle/typeck/infer/lub.rs
@@ -191,18 +191,24 @@ pub impl Lub: Combine {
         }
     }
 
-    fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
-        super_fns(&self, a, b)
+    fn bare_fn_tys(a: &ty::BareFnTy,
+                   b: &ty::BareFnTy) -> cres<ty::BareFnTy> {
+        super_bare_fn_tys(&self, a, b)
     }
 
-    fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
-        super_fn_metas(&self, a, b)
+    fn closure_tys(a: &ty::ClosureTy,
+                   b: &ty::ClosureTy) -> cres<ty::ClosureTy> {
+        super_closure_tys(&self, a, b)
     }
 
     // Traits please (FIXME: #2794):
 
-    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
-        super_protos(&self, p1, p2)
+    fn sigils(p1: ast::Sigil, p2: ast::Sigil) -> cres<ast::Sigil> {
+        super_sigils(&self, p1, p2)
+    }
+
+    fn abis(p1: ast::Abi, p2: ast::Abi) -> cres<ast::Abi> {
+        super_abis(&self, p1, p2)
     }
 
     fn tys(a: ty::t, b: ty::t) -> cres<ty::t> {
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 6140390a24e..d6ecf11ef26 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -242,9 +242,6 @@ section on "Type Combining" below for details.
 
 */
 
-#[warn(deprecated_mode)];
-#[warn(deprecated_pattern)];
-
 use core::prelude::*;
 
 pub use middle::ty::IntVarValue;
@@ -257,7 +254,6 @@ pub use middle::typeck::infer::resolve::{resolve_nested_tvar};
 pub use middle::typeck::infer::resolve::{resolve_rvar};
 
 use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid};
-use middle::ty::{mk_fn, type_is_bot};
 use middle::ty::{ty_int, ty_uint, get, terr_fn, TyVar, IntVar, FloatVar};
 use middle::ty;
 use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig};
diff --git a/src/librustc/middle/typeck/infer/region_inference.rs b/src/librustc/middle/typeck/infer/region_inference.rs
index 0d4e520122f..afb18888cd9 100644
--- a/src/librustc/middle/typeck/infer/region_inference.rs
+++ b/src/librustc/middle/typeck/infer/region_inference.rs
@@ -536,9 +536,6 @@ more convincing in the future.
 
 */
 
-#[warn(deprecated_mode)];
-#[warn(deprecated_pattern)];
-
 use core::prelude::*;
 
 use middle::region::is_subregion_of;
diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs
index 2e30bdc5888..bc834ef0289 100644
--- a/src/librustc/middle/typeck/infer/sub.rs
+++ b/src/librustc/middle/typeck/infer/sub.rs
@@ -212,20 +212,26 @@ pub impl Sub: Combine {
 
     // Traits please (FIXME: #2794):
 
-    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
-        super_protos(&self, p1, p2)
+    fn sigils(p1: ast::Sigil, p2: ast::Sigil) -> cres<ast::Sigil> {
+        super_sigils(&self, p1, p2)
+    }
+
+    fn abis(p1: ast::Abi, p2: ast::Abi) -> cres<ast::Abi> {
+        super_abis(&self, p1, p2)
     }
 
     fn flds(a: ty::field, b: ty::field) -> cres<ty::field> {
         super_flds(&self, a, b)
     }
 
-    fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
-        super_fns(&self, a, b)
+    fn bare_fn_tys(a: &ty::BareFnTy,
+                   b: &ty::BareFnTy) -> cres<ty::BareFnTy> {
+        super_bare_fn_tys(&self, a, b)
     }
 
-    fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
-        super_fn_metas(&self, a, b)
+    fn closure_tys(a: &ty::ClosureTy,
+                   b: &ty::ClosureTy) -> cres<ty::ClosureTy> {
+        super_closure_tys(&self, a, b)
     }
 
     fn vstores(vk: ty::terr_vstore_kind,
diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs
index 57e05926173..bade7639e4b 100644
--- a/src/librustc/middle/typeck/infer/to_str.rs
+++ b/src/librustc/middle/typeck/infer/to_str.rs
@@ -10,7 +10,7 @@
 
 use core::prelude::*;
 
-use middle::ty::{FnMeta, FnTyBase, FnSig, Vid};
+use middle::ty::{FnSig, Vid};
 use middle::ty::{IntVarValue, IntType, UintType};
 use middle::ty;
 use middle::typeck::infer::{Bound, Bounds};
@@ -34,12 +34,6 @@ pub impl ty::t : InferStr {
     }
 }
 
-pub impl FnMeta : InferStr {
-    fn inf_str(&self, _cx: &InferCtxt) -> ~str {
-        fmt!("%?", *self)
-    }
-}
-
 pub impl FnSig : InferStr {
     fn inf_str(&self, cx: &InferCtxt) -> ~str {
         fmt!("(%s) -> %s",
@@ -48,12 +42,6 @@ pub impl FnSig : InferStr {
     }
 }
 
-pub impl<M:InferStr> FnTyBase<M> : InferStr {
-    fn inf_str(&self, cx: &InferCtxt) -> ~str {
-        fmt!("%s%s", self.meta.inf_str(cx), self.sig.inf_str(cx))
-    }
-}
-
 pub impl ty::mt : InferStr {
     fn inf_str(&self, cx: &InferCtxt) -> ~str {
         mt_to_str(cx.tcx, *self)
diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs
index 742646618bd..3d9e2e7b86a 100644
--- a/src/librustc/middle/typeck/mod.rs
+++ b/src/librustc/middle/typeck/mod.rs
@@ -324,7 +324,7 @@ fn check_main_fn_ty(ccx: @crate_ctxt,
     let tcx = ccx.tcx;
     let main_t = ty::node_id_to_type(tcx, main_id);
     match ty::get(main_t).sty {
-        ty::ty_fn(ref fn_ty) => {
+        ty::ty_bare_fn(ref fn_ty) => {
             match tcx.items.find(&main_id) {
                 Some(ast_map::node_item(it,_)) => {
                     match it.node {
@@ -341,8 +341,8 @@ fn check_main_fn_ty(ccx: @crate_ctxt,
                 }
                 _ => ()
             }
-            let mut ok = ty::type_is_nil((*fn_ty).sig.output);
-            let num_args = vec::len((*fn_ty).sig.inputs);
+            let mut ok = ty::type_is_nil(fn_ty.sig.output);
+            let num_args = vec::len(fn_ty.sig.inputs);
             ok &= num_args == 0u;
             if !ok {
                 tcx.sess.span_err(
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 9e70a6ab130..43d12c95c4d 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -21,7 +21,8 @@ use middle::ty::{mt, t, param_bound, param_ty};
 use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region};
 use middle::ty::{ReSkolemized, ReVar};
 use middle::ty::{ty_bool, ty_bot, ty_box, ty_struct, ty_enum};
-use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_fn, ty_trait, ty_int};
+use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure};
+use middle::ty::{ty_trait, ty_int};
 use middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param};
 use middle::ty::{ty_ptr, ty_rec, ty_rptr, ty_self, ty_tup};
 use middle::ty::{ty_type, ty_uniq, ty_uint, ty_infer};
@@ -30,7 +31,7 @@ use metadata::encoder;
 use syntax::codemap;
 use syntax::codemap::span;
 use syntax::print::pprust;
-use syntax::print::pprust::{path_to_str, proto_to_str, mode_to_str};
+use syntax::print::pprust::{path_to_str, mode_to_str};
 use syntax::{ast, ast_util};
 use syntax::ast_map;
 
@@ -252,17 +253,6 @@ pub fn vstore_ty_to_str(cx: ctxt, ty: ~str, vs: ty::vstore) -> ~str {
     }
 }
 
-pub fn proto_ty_to_str(_cx: ctxt, proto: ast::Proto,
-                       followed_by_word: bool) -> &static/str {
-    match proto {
-        ast::ProtoBare if followed_by_word => "extern ",
-        ast::ProtoBare => "extern",
-        ast::ProtoBox => "@",
-        ast::ProtoBorrowed => "&",
-        ast::ProtoUniq => "~",
-    }
-}
-
 pub fn expr_repr(cx: ctxt, expr: @ast::expr) -> ~str {
     fmt!("expr(%d: %s)",
          expr.id,
@@ -306,69 +296,95 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
         };
         fmt!("%s%s", modestr, ty_to_str(cx, ty))
     }
-    fn fn_to_str(cx: ctxt,
-                 proto: ast::Proto,
-                 region: ty::Region,
-                 purity: ast::purity,
-                 onceness: ast::Onceness,
-                 ident: Option<ast::ident>,
-                 inputs: &[arg],
-                 output: t) -> ~str {
-        let mut s;
-
-        s = match purity {
-            ast::impure_fn => ~"",
-            _ => purity.to_str() + ~" "
-        };
+    fn bare_fn_to_str(cx: ctxt,
+                      purity: ast::purity,
+                      abi: ast::Abi,
+                      ident: Option<ast::ident>,
+                      sig: &ty::FnSig) -> ~str
+    {
+        let mut s = ~"extern ";
 
-        s += match onceness {
-            ast::Many => ~"",
-            ast::Once => onceness.to_str() + ~" "
+        match abi {
+            ast::RustAbi => {}
+        }
+
+        match purity {
+            ast::impure_fn => {}
+            _ => {
+                s.push_str(purity.to_str());
+                s.push_char(' ');
+            }
         };
 
-        s += proto_ty_to_str(cx, proto, true);
+        s.push_str("fn");
 
-        match (proto, region) {
-            (ast::ProtoBox, ty::re_static) |
-            (ast::ProtoUniq, ty::re_static) |
-            (ast::ProtoBare, ty::re_static) => {
-            }
+        match ident {
+          Some(i) => {
+              s.push_char(' ');
+              s.push_str(cx.sess.str_of(i));
+          }
+          _ => { }
+        }
+
+        push_sig_to_str(cx, &mut s, sig);
+
+        return s;
+    }
+    fn closure_to_str(cx: ctxt, cty: &ty::ClosureTy) -> ~str
+    {
+        let mut s = cty.sigil.to_str();
+
+        match (cty.sigil, cty.region) {
+            (ast::ManagedSigil, ty::re_static) |
+            (ast::OwnedSigil, ty::re_static) => {}
 
             (_, region) => {
-                s += region_to_str_adorned(cx, ~"", region, ~"/");
+                s.push_str(region_to_str_adorned(cx, "", region, "/"));
             }
         }
 
-        s += ~"fn";
+        match cty.purity {
+            ast::impure_fn => {}
+            _ => {
+                s.push_str(cty.purity.to_str());
+                s.push_char(' ');
+            }
+        };
 
-        match ident {
-          Some(i) => { s += ~" "; s += cx.sess.str_of(i); }
-          _ => { }
-        }
-        s += ~"(";
-        let strs = inputs.map(|a| fn_input_to_str(cx, *a));
-        s += str::connect(strs, ~", ");
-        s += ~")";
-        if ty::get(output).sty != ty_nil {
-            s += ~" -> ";
-            if ty::type_is_bot(output) {
-                s += ~"!";
+        match cty.onceness {
+            ast::Many => {}
+            ast::Once => {
+                s.push_str(cty.onceness.to_str());
+                s.push_char(' ');
+            }
+        };
+
+        s.push_str("fn");
+
+        push_sig_to_str(cx, &mut s, &cty.sig);
+
+        return s;
+    }
+    fn push_sig_to_str(cx: ctxt, s: &mut ~str, sig: &ty::FnSig) {
+        s.push_char('(');
+        let strs = sig.inputs.map(|a| fn_input_to_str(cx, *a));
+        s.push_str(str::connect(strs, ", "));
+        s.push_char(')');
+        if ty::get(sig.output).sty != ty_nil {
+            s.push_str(" -> ");
+            if ty::type_is_bot(sig.output) {
+                s.push_char('!');
             } else {
-                s += ty_to_str(cx, output);
+                s.push_str(ty_to_str(cx, sig.output));
             }
         }
-        return s;
     }
     fn method_to_str(cx: ctxt, m: method) -> ~str {
-        return fn_to_str(
-            cx,
-            m.fty.meta.proto,
-            m.fty.meta.region,
-            m.fty.meta.purity,
-            m.fty.meta.onceness,
-            Some(m.ident),
-            m.fty.sig.inputs,
-            m.fty.sig.output) + ~";";
+        bare_fn_to_str(cx,
+                       m.fty.purity,
+                       m.fty.abi,
+                       Some(m.ident),
+                       &m.fty.sig) + ~";"
     }
     fn field_to_str(cx: ctxt, f: field) -> ~str {
         return cx.sess.str_of(f.ident) + ~": " + mt_to_str(cx, f.mt);
@@ -409,15 +425,11 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
         let strs = elems.map(|elem| ty_to_str(cx, *elem));
         ~"(" + str::connect(strs, ~",") + ~")"
       }
-      ty_fn(ref f) => {
-        fn_to_str(cx,
-                  f.meta.proto,
-                  f.meta.region,
-                  f.meta.purity,
-                  f.meta.onceness,
-                  None,
-                  f.sig.inputs,
-                  f.sig.output)
+      ty_closure(ref f) => {
+          closure_to_str(cx, f)
+      }
+      ty_bare_fn(ref f) => {
+          bare_fn_to_str(cx, f.purity, f.abi, None, &f.sig)
       }
       ty_infer(infer_ty) => infer_ty.to_str(),
       ty_err => ~"[type error]",
@@ -448,10 +460,9 @@ pub 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(ast::ProtoBorrowed) => ~"closure&",
-      ty_opaque_closure_ptr(ast::ProtoBox) => ~"closure@",
-      ty_opaque_closure_ptr(ast::ProtoUniq) => ~"closure~",
-      ty_opaque_closure_ptr(ast::ProtoBare) => ~"closure"
+      ty_opaque_closure_ptr(ast::BorrowedSigil) => ~"closure&",
+      ty_opaque_closure_ptr(ast::ManagedSigil) => ~"closure@",
+      ty_opaque_closure_ptr(ast::OwnedSigil) => ~"closure~",
     }
 }