From aa5382bb13690ff183f6e94065dadf0524ce1c6e Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Thu, 29 Dec 2011 20:07:55 -0800
Subject: [PATCH] split proto from fn_decl, as not all fn_decls know the proto.
 this will address the (crashing) new test added.

---
 src/comp/front/test.rs                        | 10 +--
 src/comp/middle/alias.rs                      |  6 +-
 src/comp/middle/ast_map.rs                    |  6 +-
 src/comp/middle/debuginfo.rs                  |  2 +-
 src/comp/middle/freevars.rs                   |  9 +--
 src/comp/middle/kind.rs                       |  8 +-
 src/comp/middle/last_use.rs                   | 10 +--
 src/comp/middle/resolve.rs                    | 32 ++++----
 src/comp/middle/trans.rs                      |  8 +-
 src/comp/middle/trans_closure.rs              |  5 +-
 src/comp/middle/tstate/annotate.rs            |  6 +-
 src/comp/middle/tstate/auxiliary.rs           |  4 +-
 src/comp/middle/tstate/bitvectors.rs          |  2 +-
 src/comp/middle/tstate/ck.rs                  | 21 +++--
 src/comp/middle/tstate/collect_locals.rs      | 20 ++---
 src/comp/middle/tstate/pre_post_conditions.rs | 11 ++-
 src/comp/middle/tstate/states.rs              |  2 +-
 src/comp/middle/typeck.rs                     | 67 ++++++++--------
 src/comp/syntax/ast.rs                        |  7 +-
 src/comp/syntax/fold.rs                       | 11 ++-
 src/comp/syntax/parse/parser.rs               | 59 +++++---------
 src/comp/syntax/print/pprust.rs               | 20 ++---
 src/comp/syntax/visit.rs                      | 77 ++++++++++++-------
 src/comp/util/ppaux.rs                        |  4 -
 src/test/run-pass/block-arg-call-as.rs        | 22 ++++++
 25 files changed, 229 insertions(+), 200 deletions(-)
 create mode 100644 src/test/run-pass/block-arg-call-as.rs

diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs
index ee32a31aabb..f8aa8bdac53 100644
--- a/src/comp/front/test.rs
+++ b/src/comp/front/test.rs
@@ -190,8 +190,7 @@ fn mk_tests(cx: test_ctxt) -> @ast::item {
     let ret_ty = mk_test_desc_vec_ty(cx);
 
     let decl: ast::fn_decl =
-        {proto: ast::proto_bare,
-         inputs: [],
+        {inputs: [],
          output: ret_ty,
          purity: ast::impure_fn,
          cf: ast::return_val,
@@ -322,7 +321,6 @@ fn mk_test_wrapper(cx: test_ctxt,
         ast::stmt_expr(@call_expr, cx.sess.next_node_id()));
 
     let wrapper_decl: ast::fn_decl = {
-        proto: ast::proto_bare,
         inputs: [],
         output: @nospan(ast::ty_nil),
         purity: ast::impure_fn,
@@ -345,7 +343,8 @@ fn mk_test_wrapper(cx: test_ctxt,
 
     let wrapper_expr: ast::expr = {
         id: cx.sess.next_node_id(),
-        node: ast::expr_fn(wrapper_decl, wrapper_body, wrapper_capture),
+        node: ast::expr_fn(ast::proto_bare, wrapper_decl,
+                           wrapper_body, wrapper_capture),
         span: span
     };
 
@@ -366,8 +365,7 @@ fn mk_main(cx: test_ctxt) -> @ast::item {
     let ret_ty = nospan(ast::ty_nil);
 
     let decl: ast::fn_decl =
-        {proto: ast::proto_bare,
-         inputs: [args_arg],
+        {inputs: [args_arg],
          output: @ret_ty,
          purity: ast::impure_fn,
          cf: ast::return_val,
diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs
index 959f5e02e17..e3c91b3d52a 100644
--- a/src/comp/middle/alias.rs
+++ b/src/comp/middle/alias.rs
@@ -61,7 +61,7 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_map) {
                copy_map: std::map::new_int_hash(),
                ref_map: std::map::new_int_hash(),
                mutable silent: false};
-    let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _, _),
+    let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _),
               visit_expr: bind visit_expr(cx, _, _, _),
               visit_block: bind visit_block(cx, _, _, _)
               with *visit::default_visitor::<scope>()};
@@ -71,8 +71,8 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_map) {
     ret (cx.copy_map, cx.ref_map);
 }
 
-fn visit_fn(cx: @ctx, decl: ast::fn_decl, _ts: [ast::ty_param],
-            body: ast::blk, sp: span, _name: ast::fn_ident,
+fn visit_fn(cx: @ctx, _fk: visit::fn_kind, decl: ast::fn_decl,
+            body: ast::blk, sp: span,
             id: ast::node_id, sc: scope, v: vt<scope>) {
     visit::visit_fn_decl(decl, sc, v);
     let fty = ty::node_id_to_type(cx.tcx, id);
diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs
index 995c16ddb2c..2d2ef2e4c17 100644
--- a/src/comp/middle/ast_map.rs
+++ b/src/comp/middle/ast_map.rs
@@ -32,7 +32,7 @@ fn map_crate(c: crate) -> map {
         (@{visit_item: bind map_item(cx, _),
            visit_native_item: bind map_native_item(cx, _),
            visit_expr: bind map_expr(cx, _),
-           visit_fn: bind map_fn(cx, _, _, _, _, _, _),
+           visit_fn: bind map_fn(cx, _, _, _, _, _),
            visit_local: bind map_local(cx, _),
            visit_arm: bind map_arm(cx, _)
            with *visit::default_simple_visitor()});
@@ -40,8 +40,8 @@ fn map_crate(c: crate) -> map {
     ret cx.map;
 }
 
-fn map_fn(cx: ctx, decl: fn_decl, _tps: [ty_param], _body: blk,
-          _sp: codemap::span, _n: fn_ident, _id: node_id) {
+fn map_fn(cx: ctx, _fk: visit::fn_kind, decl: fn_decl, _body: blk,
+          _sp: codemap::span, _id: node_id) {
     for a in decl.inputs {
         cx.map.insert(a.id, node_arg(a, cx.local_id));
         cx.local_id += 1u;
diff --git a/src/comp/middle/debuginfo.rs b/src/comp/middle/debuginfo.rs
index b97b9a65510..0cc6cc7b79d 100644
--- a/src/comp/middle/debuginfo.rs
+++ b/src/comp/middle/debuginfo.rs
@@ -736,7 +736,7 @@ fn create_function(fcx: @fn_ctxt) -> @metadata<subprogram_md> {
       }
       ast_map::node_expr(expr) {
         alt expr.node {
-          ast::expr_fn(decl, _, _) {
+          ast::expr_fn(_, decl, _, _) {
             (dbg_cx.names.next("fn"), decl.output, expr.id)
           }
           ast::expr_fn_block(decl, _) {
diff --git a/src/comp/middle/freevars.rs b/src/comp/middle/freevars.rs
index 9e18bae4a2e..7b348a9c8a1 100644
--- a/src/comp/middle/freevars.rs
+++ b/src/comp/middle/freevars.rs
@@ -38,8 +38,8 @@ fn collect_freevars(def_map: resolve::def_map, blk: ast::blk)
     let walk_expr =
         lambda (expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
             alt expr.node {
-              ast::expr_fn(decl, _, captures) {
-                if decl.proto != ast::proto_bare {
+              ast::expr_fn(proto, decl, _, captures) {
+                if proto != ast::proto_bare {
                     visit::visit_expr(expr, depth + 1, v);
                 }
               }
@@ -82,9 +82,8 @@ fn annotate_freevars(def_map: resolve::def_map, crate: @ast::crate) ->
    freevar_map {
     let freevars = new_int_hash();
 
-    let walk_fn = lambda (_decl: ast::fn_decl, _tps: [ast::ty_param],
-                          blk: ast::blk, _sp: span, _nm: ast::fn_ident,
-                          nid: ast::node_id) {
+    let walk_fn = lambda (_fk: visit::fn_kind, _decl: ast::fn_decl,
+                          blk: ast::blk, _sp: span, nid: ast::node_id) {
         let vars = collect_freevars(def_map, blk);
         freevars.insert(nid, vars);
     };
diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs
index e9b15729450..f71112002c4 100644
--- a/src/comp/middle/kind.rs
+++ b/src/comp/middle/kind.rs
@@ -67,8 +67,8 @@ fn with_closure_check_fn(cx: ctx, id: node_id,
 
 // Check that the free variables used in a shared/sendable closure conform
 // to the copy/move kind bounds. Then recursively check the function body.
-fn check_fn(decl: fn_decl, tps: [ty_param], body: blk, sp: span,
-            i: fn_ident, id: node_id, cx: ctx, v: visit::vt<ctx>) {
+fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span,
+            id: node_id, cx: ctx, v: visit::vt<ctx>) {
 
     // n.b.: This could be the body of either a fn decl or a fn expr.  In the
     // former case, the prototype will be proto_bare and no check occurs.  In
@@ -88,7 +88,7 @@ fn check_fn(decl: fn_decl, tps: [ty_param], body: blk, sp: span,
         }
     }
 
-    visit::visit_fn(decl, tps, body, sp, i, id, cx, v);
+    visit::visit_fn(fk, decl, body, sp, id, cx, v);
 }
 
 fn check_fn_cap_clause(cx: ctx,
@@ -181,7 +181,7 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
         }
       }
       expr_ternary(_, a, b) { maybe_copy(cx, a); maybe_copy(cx, b); }
-      expr_fn(_, _, cap_clause) {
+      expr_fn(_, _, _, cap_clause) {
         check_fn_cap_clause(cx, e.id, *cap_clause);
       }
       _ { }
diff --git a/src/comp/middle/last_use.rs b/src/comp/middle/last_use.rs
index 7b1a0b6c0a3..113e9a9c299 100644
--- a/src/comp/middle/last_use.rs
+++ b/src/comp/middle/last_use.rs
@@ -136,7 +136,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
         for arg in args {
             alt arg.node {
               //NDM--register captured as uses
-              expr_fn(_, _, captured) { fns += [arg]; }
+              expr_fn(_, _, _, captured) { fns += [arg]; }
               expr_fn_block(_, _) { fns += [arg]; }
               _ {
                 alt arg_ts[i].mode {
@@ -153,19 +153,19 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
     }
 }
 
-fn visit_fn(decl: fn_decl, tps: [ty_param], body: blk,
-            sp: span, nm: fn_ident, id: node_id,
+fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
+            sp: span, id: node_id,
             cx: ctx, v: visit::vt<ctx>) {
     let fty = ty::node_id_to_type(cx.tcx, id);
     let proto = ty::ty_fn_proto(cx.tcx, fty);
     if proto == proto_block {
         visit_block(func, cx, {||
-            visit::visit_fn(decl, tps, body, sp, nm, id, cx, v);
+            visit::visit_fn(fk, decl, body, sp, id, cx, v);
         });
     } else {
         let old = nil;
         cx.blocks <-> old;
-        visit::visit_fn(decl, tps, body, sp, nm, id, cx, v);
+        visit::visit_fn(fk, decl, body, sp, id, cx, v);
         cx.blocks <-> old;
         leave_fn(cx);
     }
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 9eaaee2cb36..ca9887534cb 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -336,7 +336,7 @@ fn resolve_names(e: @env, c: @ast::crate) {
           visit_expr: bind walk_expr(e, _, _, _),
           visit_ty: bind walk_ty(e, _, _, _),
           visit_constr: bind walk_constr(e, _, _, _, _, _),
-          visit_fn: bind visit_fn_with_scope(e, _, _, _, _, _, _, _, _)
+          visit_fn: bind visit_fn_with_scope(e, _, _, _, _, _, _, _)
           with *visit::default_visitor()};
     visit::visit_crate(*c, cons(scope_crate, @nil), visit::mk_vt(v));
     e.used_imports.track = false;
@@ -350,7 +350,7 @@ fn resolve_names(e: @env, c: @ast::crate) {
                          lookup_path_strict(*e, sc, exp.span, p.node,
                                             ns_value));
           }
-          ast::expr_fn(_, _, cap_clause) {
+          ast::expr_fn(_, _, _, cap_clause) {
             let rci = bind resolve_capture_item(e, sc, _);
             vec::iter(cap_clause.copies, rci);
             vec::iter(cap_clause.moves, rci);
@@ -403,8 +403,9 @@ fn visit_item_with_scope(i: @ast::item, sc: scopes, v: vt<scopes>) {
         alt ifce { some(ty) { v.visit_ty(ty, sc, v); } _ {} }
         v.visit_ty(sty, sc, v);
         for m in methods {
-            v.visit_fn(m.decl, tps + m.tps, m.body, m.span,
-                       some(m.ident), m.id, sc, v);
+            v.visit_fn(visit::fk_method(m.ident, tps + m.tps),
+                       m.decl, m.body, m.span,
+                       m.id, sc, v);
         }
       }
       _ { visit::visit_item(i, sc, v); }
@@ -416,30 +417,35 @@ fn visit_native_item_with_scope(ni: @ast::native_item, sc: scopes,
     visit::visit_native_item(ni, cons(scope_native_item(ni), @sc), v);
 }
 
-fn visit_fn_with_scope(e: @env, decl: ast::fn_decl, tp: [ast::ty_param],
-                       body: ast::blk, sp: span, name: fn_ident,
+fn visit_fn_with_scope(e: @env, fk: visit::fn_kind, decl: ast::fn_decl,
+                       body: ast::blk, sp: span,
                        id: node_id, sc: scopes, v: vt<scopes>) {
     // is this a main fn declaration?
-    alt name {
-      some(nm) {
+    alt fk {
+      visit::fk_item_fn(nm, _) {
         if is_main_name([nm]) && !e.sess.building_library() {
             // This is a main function -- set it in the session
             // as the main ID
             e.sess.set_main_id(id);
         }
       }
-      _ { }
+      _ { /* fallthrough */ }
     }
 
     // here's where we need to set up the mapping
     // for f's constrs in the table.
     for c: @ast::constr in decl.constraints { resolve_constr(e, c, sc, v); }
-    let scope = alt decl.proto {
-      ast::proto_bare. { scope_bare_fn(decl, id, tp) }
-      _ { scope_fn_expr(decl, id, tp) }
+    let scope = alt fk {
+      visit::fk_item_fn(_, tps) | visit::fk_method(_, tps) |
+      visit::fk_res(_, tps) {
+        scope_bare_fn(decl, id, tps)
+      }
+      visit::fk_anon(_) | visit::fk_fn_block. {
+        scope_fn_expr(decl, id, [])
+      }
     };
 
-    visit::visit_fn(decl, tp, body, sp, name, id, cons(scope, @sc), v);
+    visit::visit_fn(fk, decl, body, sp, id, cons(scope, @sc), v);
 }
 
 fn visit_block_with_scope(b: ast::blk, sc: scopes, v: vt<scopes>) {
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index a318f2ec354..26a9a29b685 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -3551,16 +3551,18 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
         assert op != ast::deref; // lvals are handled above
         ret trans_unary(bcx, op, x, e.id, dest);
       }
-      ast::expr_fn(decl, body, cap_clause) {
+      ast::expr_fn(proto, decl, body, cap_clause) {
         ret trans_closure::trans_expr_fn(
-            bcx, decl, body, e.span, e.id, *cap_clause, dest);
+            bcx, proto, decl, body, e.span, e.id, *cap_clause, dest);
       }
       ast::expr_fn_block(decl, body) {
         alt ty::struct(tcx, ty::expr_ty(tcx, e)) {
           ty::ty_fn({proto, _}) {
+            #debug("translating fn_block %s with type %s",
+                   expr_to_str(e), ty_to_str(tcx, ty::expr_ty(tcx, e)));
             let cap_clause = { copies: [], moves: [] };
             ret trans_closure::trans_expr_fn(
-                bcx, decl, body, e.span, e.id, cap_clause, dest);
+                bcx, proto, decl, body, e.span, e.id, cap_clause, dest);
           }
           _ {
             fail "Type of fn block is not a function!";
diff --git a/src/comp/middle/trans_closure.rs b/src/comp/middle/trans_closure.rs
index b60649a2280..7205dd27c1c 100644
--- a/src/comp/middle/trans_closure.rs
+++ b/src/comp/middle/trans_closure.rs
@@ -372,6 +372,7 @@ fn load_environment(enclosing_cx: @block_ctxt,
 }
 
 fn trans_expr_fn(bcx: @block_ctxt,
+                 proto: ast::proto,
                  decl: ast::fn_decl,
                  body: ast::blk,
                  sp: span,
@@ -390,7 +391,7 @@ fn trans_expr_fn(bcx: @block_ctxt,
 
     let trans_closure_env = lambda(ck: ty::closure_kind) -> ValueRef {
         let cap_vars = capture::compute_capture_vars(
-            ccx.tcx, id, decl.proto, cap_clause);
+            ccx.tcx, id, proto, cap_clause);
         let {llbox, box_ty, bcx} = build_closure(bcx, cap_vars, ck);
         trans_closure(sub_cx, sp, decl, body, llfn, no_self, [], id, {|fcx|
             load_environment(bcx, fcx, box_ty, cap_vars, ck);
@@ -398,7 +399,7 @@ fn trans_expr_fn(bcx: @block_ctxt,
         llbox
     };
 
-    let closure = alt decl.proto {
+    let closure = alt proto {
       ast::proto_block. { trans_closure_env(ty::closure_block) }
       ast::proto_shared(_) { trans_closure_env(ty::closure_shared) }
       ast::proto_send. { trans_closure_env(ty::closure_send) }
diff --git a/src/comp/middle/tstate/annotate.rs b/src/comp/middle/tstate/annotate.rs
index cc1360114cd..e5c4cd7192c 100644
--- a/src/comp/middle/tstate/annotate.rs
+++ b/src/comp/middle/tstate/annotate.rs
@@ -56,8 +56,8 @@ fn visit_fn(ccx: crate_ctxt, num_constraints: uint, body: blk) {
     init_vecs(ccx, node_id_vec, num_constraints);
 }
 
-fn annotate_in_fn(ccx: crate_ctxt, _decl: fn_decl, _ts: [ty_param], body: blk,
-                  _sp: span, _n: fn_ident, id: node_id) {
+fn annotate_in_fn(ccx: crate_ctxt, _fk: visit::fn_kind, _decl: fn_decl,
+                  body: blk, _sp: span, id: node_id) {
     let f_info = get_fn_info(ccx, id);
     visit_fn(ccx, num_constraints(f_info), body);
 }
@@ -65,7 +65,7 @@ fn annotate_in_fn(ccx: crate_ctxt, _decl: fn_decl, _ts: [ty_param], body: blk,
 fn annotate_crate(ccx: crate_ctxt, crate: crate) {
     let do_ann =
         visit::mk_simple_visitor(
-            @{visit_fn: bind annotate_in_fn(ccx, _, _, _, _, _, _)
+            @{visit_fn: bind annotate_in_fn(ccx, _, _, _, _, _)
               with *visit::default_simple_visitor()});
     visit::visit_crate(crate, (), do_ann);
 }
diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs
index 340b2264354..5b12477d873 100644
--- a/src/comp/middle/tstate/auxiliary.rs
+++ b/src/comp/middle/tstate/auxiliary.rs
@@ -1008,8 +1008,8 @@ fn op_to_oper_ty(io: init_op) -> oper_type {
 }
 
 // default function visitor
-fn do_nothing<T>(_decl: fn_decl, _ts: [ty_param], _body: blk,
-                 _sp: span, _i: fn_ident, _id: node_id,
+fn do_nothing<T>(_fk: visit::fn_kind, _decl: fn_decl, _body: blk,
+                 _sp: span, _id: node_id,
                  _t: T, _v: visit::vt<T>) {
 }
 
diff --git a/src/comp/middle/tstate/bitvectors.rs b/src/comp/middle/tstate/bitvectors.rs
index 120e33d9254..9f4d5949e01 100644
--- a/src/comp/middle/tstate/bitvectors.rs
+++ b/src/comp/middle/tstate/bitvectors.rs
@@ -151,7 +151,7 @@ fn relax_precond_block(fcx: fn_ctxt, i: node_id, b: blk) {
           visit_stmt: relax_precond_stmt,
           visit_item:
               fn (_i: @item, _cx: relax_ctxt, _vt: visit::vt<relax_ctxt>) { },
-          visit_fn: bind do_nothing(_, _, _, _, _, _, _, _)
+          visit_fn: bind do_nothing(_, _, _, _, _, _, _)
              with *visitor};
     let v1 = visit::mk_vt(visitor);
     v1.visit_block(b, cx, v1);
diff --git a/src/comp/middle/tstate/ck.rs b/src/comp/middle/tstate/ck.rs
index f790334fbc4..0ebf4bd0ccc 100644
--- a/src/comp/middle/tstate/ck.rs
+++ b/src/comp/middle/tstate/ck.rs
@@ -94,21 +94,20 @@ fn check_states_stmt(s: @stmt, fcx: fn_ctxt, v: visit::vt<fn_ctxt>) {
 }
 
 fn check_states_against_conditions(fcx: fn_ctxt,
+                                   fk: visit::fn_kind,
                                    f_decl: ast::fn_decl,
                                    f_body: ast::blk,
                                    sp: span,
-                                   nm: fn_ident,
                                    id: node_id) {
     /* Postorder traversal instead of pre is important
        because we want the smallest possible erroneous statement
        or expression. */
-
     let visitor = visit::mk_vt(
         @{visit_stmt: check_states_stmt,
           visit_expr: check_states_expr,
-          visit_fn: bind do_nothing::<fn_ctxt>(_, _, _, _, _, _, _, _)
+          visit_fn: bind do_nothing::<fn_ctxt>(_, _, _, _, _, _, _)
           with *visit::default_visitor::<fn_ctxt>()});
-    visit::visit_fn(f_decl, [], f_body, sp, nm, id, fcx, visitor);
+    visit::visit_fn(fk, f_decl, f_body, sp, id, fcx, visitor);
 
     /* Check that the return value is initialized */
     let post = aux::block_poststate(fcx.ccx, f_body);
@@ -142,10 +141,10 @@ fn check_states_against_conditions(fcx: fn_ctxt,
 }
 
 fn check_fn_states(fcx: fn_ctxt,
+                   fk: visit::fn_kind,
                    f_decl: ast::fn_decl,
                    f_body: ast::blk,
                    sp: span,
-                   nm: fn_ident,
                    id: node_id) {
     /* Compute the pre- and post-states for this function */
 
@@ -155,20 +154,20 @@ fn check_fn_states(fcx: fn_ctxt,
     /* Now compare each expr's pre-state to its precondition
        and post-state to its postcondition */
 
-    check_states_against_conditions(fcx, f_decl, f_body, sp, nm, id);
+    check_states_against_conditions(fcx, fk, f_decl, f_body, sp, id);
 }
 
-fn fn_states(f_decl: ast::fn_decl, tps: [ast::ty_param], f_body: ast::blk,
-             sp: span, i: ast::fn_ident, id: node_id,
+fn fn_states(fk: visit::fn_kind, f_decl: ast::fn_decl, f_body: ast::blk,
+             sp: span, id: node_id,
              ccx: crate_ctxt, v: visit::vt<crate_ctxt>) {
-    visit::visit_fn(f_decl, tps, f_body, sp, i, id, ccx, v);
+    visit::visit_fn(fk, f_decl, f_body, sp, id, ccx, v);
     /* Look up the var-to-bit-num map for this function */
 
     assert (ccx.fm.contains_key(id));
     let f_info = ccx.fm.get(id);
-    let name = option::from_maybe("anon", i); // XXXX
+    let name = visit::name_of_fn(fk);
     let fcx = {enclosing: f_info, id: id, name: name, ccx: ccx};
-    check_fn_states(fcx, f_decl, f_body, sp, i, id)
+    check_fn_states(fcx, fk, f_decl, f_body, sp, id)
 }
 
 fn check_crate(cx: ty::ctxt, crate: @crate) {
diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs
index 457a6ca0173..60c79468589 100644
--- a/src/comp/middle/tstate/collect_locals.rs
+++ b/src/comp/middle/tstate/collect_locals.rs
@@ -1,6 +1,5 @@
 import syntax::ast::*;
 import syntax::ast_util::*;
-import util::ppaux::fn_ident_to_string;
 import option::*;
 import syntax::visit;
 import aux::*;
@@ -45,11 +44,10 @@ fn collect_pred(e: @expr, cx: ctxt, v: visit::vt<ctxt>) {
 }
 
 fn find_locals(tcx: ty::ctxt,
+               fk: visit::fn_kind,
                f_decl: fn_decl,
-               tps: [ty_param],
                f_body: blk,
                sp: span,
-               n: fn_ident,
                id: node_id) -> ctxt {
     let cx: ctxt = {cs: @mutable [], tcx: tcx};
     let visitor = visit::default_visitor::<ctxt>();
@@ -57,10 +55,10 @@ fn find_locals(tcx: ty::ctxt,
     visitor =
         @{visit_local: collect_local,
           visit_expr: collect_pred,
-          visit_fn: bind do_nothing(_, _, _, _, _, _, _, _)
+          visit_fn: bind do_nothing(_, _, _, _, _, _, _)
           with *visitor};
-    visit::visit_fn(f_decl, tps, f_body, sp,
-                    n, id, cx, visit::mk_vt(visitor));
+    visit::visit_fn(fk, f_decl, f_body, sp,
+                    id, cx, visit::mk_vt(visitor));
     ret cx;
 }
 
@@ -98,18 +96,16 @@ fn add_constraint(tcx: ty::ctxt, c: sp_constr, next: uint, tbl: constr_map) ->
 /* builds a table mapping each local var defined in f
    to a bit number in the precondition/postcondition vectors */
 fn mk_fn_info(ccx: crate_ctxt,
+              fk: visit::fn_kind,
               f_decl: fn_decl,
-              tps: [ty_param],
               f_body: blk,
               f_sp: span,
-              f_name: fn_ident,
               id: node_id) {
-    let name = fn_ident_to_string(id, f_name);
+    let name = visit::name_of_fn(fk);
     let res_map = @new_def_hash::<constraint>();
     let next: uint = 0u;
 
-    let cx: ctxt = find_locals(ccx.tcx, f_decl, tps, f_body, f_sp,
-                               f_name, id);
+    let cx: ctxt = find_locals(ccx.tcx, fk, f_decl, f_body, f_sp, id);
     /* now we have to add bit nums for both the constraints
        and the variables... */
 
@@ -167,7 +163,7 @@ fn mk_fn_info(ccx: crate_ctxt,
 fn mk_f_to_fn_info(ccx: crate_ctxt, c: @crate) {
     let visitor =
         visit::mk_simple_visitor(@{visit_fn:
-                                       bind mk_fn_info(ccx, _, _, _, _, _, _)
+                                       bind mk_fn_info(ccx, _, _, _, _, _)
                                    with *visit::default_simple_visitor()});
     visit::visit_crate(*c, (), visitor);
 }
diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs
index 9a3100e7bb2..fb1dd7564a8 100644
--- a/src/comp/middle/tstate/pre_post_conditions.rs
+++ b/src/comp/middle/tstate/pre_post_conditions.rs
@@ -14,7 +14,6 @@ import syntax::visit;
 import util::common::{new_def_hash, log_expr, field_exprs,
                       has_nonlocal_exits, log_stmt};
 import syntax::codemap::span;
-import util::ppaux::fn_ident_to_string;
 
 fn find_pre_post_mod(_m: _mod) -> _mod {
     #debug("implement find_pre_post_mod!");
@@ -346,7 +345,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
       expr_log(_, lvl, arg) {
         find_pre_post_exprs(fcx, [lvl, arg], e.id);
       }
-      expr_fn(_, _, cap_clause) {
+      expr_fn(_, _, _, cap_clause) {
         find_pre_post_expr_fn_upvars(fcx, e);
 
         let use_cap_item = lambda(&&cap_item: @capture_item) {
@@ -727,15 +726,15 @@ fn find_pre_post_fn(fcx: fn_ctxt, body: blk) {
     }
 }
 
-fn fn_pre_post(decl: fn_decl, tps: [ty_param], body: blk, sp: span,
-               i: fn_ident, id: node_id,
+fn fn_pre_post(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span,
+               id: node_id,
                ccx: crate_ctxt, v: visit::vt<crate_ctxt>) {
-    visit::visit_fn(decl, tps, body, sp, i, id, ccx, v);
+    visit::visit_fn(fk, decl, body, sp, id, ccx, v);
     assert (ccx.fm.contains_key(id));
     let fcx =
         {enclosing: ccx.fm.get(id),
          id: id,
-         name: fn_ident_to_string(id, i),
+         name: visit::name_of_fn(fk),
          ccx: ccx};
     find_pre_post_fn(fcx, body);
 }
diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs
index 492570e9123..2652585f09b 100644
--- a/src/comp/middle/tstate/states.rs
+++ b/src/comp/middle/tstate/states.rs
@@ -371,7 +371,7 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
       }
       expr_mac(_) { fcx.ccx.tcx.sess.bug("unexpanded macro"); }
       expr_lit(l) { ret pure_exp(fcx.ccx, e.id, pres); }
-      expr_fn(_, _, cap_clause) {
+      expr_fn(_, _, _, cap_clause) {
         ret find_pre_post_state_cap_clause(fcx, e.id, pres, *cap_clause);
       }
       expr_fn_block(_, _) { ret pure_exp(fcx.ccx, e.id, pres); }
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 137804b59d4..5d65ce78049 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -333,8 +333,8 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
         }
         typ = ty::mk_rec(tcx, flds);
       }
-      ast::ty_fn(decl) {
-        typ = ty::mk_fn(tcx, ty_of_fn_decl(tcx, mode, decl));
+      ast::ty_fn(proto, decl) {
+        typ = ty::mk_fn(tcx, ty_of_fn_decl(tcx, mode, proto, decl));
       }
       ast::ty_path(path, id) {
         alt tcx.def_map.find(id) {
@@ -465,7 +465,8 @@ fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg {
     let ty = ast_ty_to_ty(tcx, mode, a.ty);
     {mode: default_arg_mode_for_ty(tcx, a.mode, ty), ty: ty}
 }
-fn ty_of_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl) -> ty::fn_ty {
+fn ty_of_fn_decl(tcx: ty::ctxt, mode: mode,
+                 proto: ast::proto, decl: ast::fn_decl) -> ty::fn_ty {
     let input_tys = [];
     for a: ast::arg in decl.inputs { input_tys += [ty_of_arg(tcx, mode, a)]; }
     let output_ty = ast_ty_to_ty(tcx, mode, decl.output);
@@ -474,19 +475,20 @@ fn ty_of_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl) -> ty::fn_ty {
     for constr: @ast::constr in decl.constraints {
         out_constrs += [ty::ast_constr_to_constr(tcx, constr)];
     }
-    {proto: decl.proto, inputs: input_tys,
+    {proto: proto, inputs: input_tys,
      output: output_ty, ret_style: decl.cf, constraints: out_constrs}
 }
 fn ty_of_fn(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl,
             ty_params: [ast::ty_param], def_id: ast::def_id)
     -> ty::ty_param_bounds_and_ty {
-    let tpt = @{bounds: ty_param_bounds(tcx, mode, ty_params),
-               ty: ty::mk_fn(tcx, ty_of_fn_decl(tcx, mode, decl))};
+    let bounds = ty_param_bounds(tcx, mode, ty_params);
+    let tofd = ty_of_fn_decl(tcx, mode, ast::proto_bare, decl);
+    let tpt = @{bounds: bounds, ty: ty::mk_fn(tcx, tofd)};
     tcx.tcache.insert(def_id, tpt);
     ret tpt;
 }
 fn ty_of_native_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl,
-                  ty_params: [ast::ty_param], def_id: ast::def_id)
+                        ty_params: [ast::ty_param], def_id: ast::def_id)
     -> ty::ty_param_bounds_and_ty {
     let input_tys = [], bounds = ty_param_bounds(tcx, mode, ty_params);
     for a: ast::arg in decl.inputs { input_tys += [ty_of_arg(tcx, mode, a)]; }
@@ -524,12 +526,12 @@ fn ty_param_bounds(tcx: ty::ctxt, mode: mode, params: [ast::ty_param])
 }
 fn ty_of_method(tcx: ty::ctxt, mode: mode, m: @ast::method) -> ty::method {
     {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps),
-     fty: ty_of_fn_decl(tcx, mode, m.decl)}
+     fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl)}
 }
 fn ty_of_ty_method(tcx: ty::ctxt, mode: mode, m: ast::ty_method)
     -> ty::method {
     {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps),
-     fty: ty_of_fn_decl(tcx, mode, m.decl)}
+     fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl)}
 }
 fn ty_of_obj(tcx: ty::ctxt, mode: mode, id: ast::ident, ob: ast::_obj,
         ty_params: [ast::ty_param]) -> ty::ty_param_bounds_and_ty {
@@ -691,8 +693,9 @@ mod collect {
             ty_param_bounds(cx.tcx, m_collect, tps);
             for m in ms {
                 let bounds = ty_param_bounds(cx.tcx, m_collect, m.tps);
-                let ty = ty::mk_fn(cx.tcx, ty_of_fn_decl(cx.tcx, m_collect,
-                                                         m.decl));
+                let ty = ty::mk_fn(cx.tcx,
+                                   ty_of_fn_decl(cx.tcx, m_collect,
+                                                 ast::proto_bare, m.decl));
                 cx.tcx.tcache.insert(local_def(m.id), @{bounds: bounds,
                                                        ty: ty});
                 write::ty_only(cx.tcx, m.id, ty);
@@ -1005,7 +1008,7 @@ mod writeback {
         if !wbcx.success { ret; }
         resolve_type_vars_for_node(wbcx, e.span, e.id);
         alt e.node {
-          ast::expr_fn(decl, _, _) |
+          ast::expr_fn(_, decl, _, _) |
           ast::expr_fn_block(decl, _) {
             for input in decl.inputs {
                 resolve_type_vars_for_node(wbcx, e.span, input.id);
@@ -1154,16 +1157,15 @@ fn gather_locals(ccx: @crate_ctxt,
         };
 
     // Don't descend into fns and items
-    fn visit_fn<T>(_decl: ast::fn_decl, _ts: [ast::ty_param], _body: ast::blk,
-                   _sp: span, _nm: ast::fn_ident, _id: ast::node_id,
-                   _t: T, _v: visit::vt<T>) {
+    fn visit_fn<T>(_fk: visit::fn_kind, _decl: ast::fn_decl, _body: ast::blk,
+                   _sp: span, _id: ast::node_id, _t: T, _v: visit::vt<T>) {
     }
     fn visit_item<E>(_i: @ast::item, _e: E, _v: visit::vt<E>) { }
 
     let visit =
         @{visit_local: visit_local,
           visit_pat: visit_pat,
-          visit_fn: bind visit_fn(_, _, _, _, _, _, _, _),
+          visit_fn: bind visit_fn(_, _, _, _, _, _, _),
           visit_item: bind visit_item(_, _, _)
               with *visit::default_visitor()};
 
@@ -1510,13 +1512,15 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
 
 fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
                               expr: @ast::expr,
+                              proto: ast::proto,
                               decl: ast::fn_decl,
                               body: ast::blk,
                               unify: unifier,
                               expected: ty::t) {
     let tcx = fcx.ccx.tcx;
 
-    let fty = ty::mk_fn(tcx, ty_of_fn_decl(tcx, m_check_tyvar(fcx), decl));
+    let fty = ty::mk_fn(tcx, ty_of_fn_decl(tcx, m_check_tyvar(fcx),
+                                           proto, decl));
 
     #debug("check_expr_fn_with_unifier %s fty=%s",
            expr_to_str(expr),
@@ -1530,7 +1534,7 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
     // record projection work on type inferred arguments.
     unify(fcx, expr.span, expected, fty);
 
-    check_fn(fcx.ccx, decl, body, expr.id, some(fcx));
+    check_fn(fcx.ccx, proto, decl, body, expr.id, some(fcx));
 }
 
 fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
@@ -1964,10 +1968,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
         write::ty_only_fixup(fcx, id, result_ty);
       }
-      ast::expr_fn(decl, body, captures) {
-        check_expr_fn_with_unifier(fcx, expr, decl, body,
+      ast::expr_fn(proto, decl, body, captures) {
+        check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
                                    unify, expected);
-        capture::check_capture_clause(tcx, expr.id, decl.proto, *captures);
+        capture::check_capture_clause(tcx, expr.id, proto, *captures);
       }
       ast::expr_fn_block(decl, body) {
         // Take the prototype from the expected type, but default to block:
@@ -1983,7 +1987,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         #debug("checking expr_fn_block %s expected=%s",
                expr_to_str(expr),
                ty_to_str(tcx, expected));
-        check_expr_fn_with_unifier(fcx, expr, {proto: proto with decl}, body,
+        check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
                                    unify, expected);
         write::ty_only_fixup(fcx, id, expected);
       }
@@ -2602,10 +2606,11 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) {
 }
 
 fn check_fn(ccx: @crate_ctxt,
-             decl: ast::fn_decl,
-             body: ast::blk,
-             id: ast::node_id,
-             old_fcx: option::t<@fn_ctxt>) {
+            proto: ast::proto,
+            decl: ast::fn_decl,
+            body: ast::blk,
+            id: ast::node_id,
+            old_fcx: option::t<@fn_ctxt>) {
     // If old_fcx is some(...), this is a block fn { |x| ... }.
     // In that case, the purity is inherited from the context.
     let purity = alt old_fcx {
@@ -2618,7 +2623,7 @@ fn check_fn(ccx: @crate_ctxt,
     let fcx: @fn_ctxt =
         @{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)),
           purity: purity,
-          proto: decl.proto,
+          proto: proto,
           var_bindings: gather_result.var_bindings,
           locals: gather_result.locals,
           next_var_id: gather_result.next_var_id,
@@ -2655,15 +2660,17 @@ fn check_fn(ccx: @crate_ctxt,
 }
 
 fn check_method(ccx: @crate_ctxt, method: @ast::method) {
-    check_fn(ccx, method.decl, method.body, method.id, none);
+    check_fn(ccx, ast::proto_bare, method.decl, method.body, method.id, none);
 }
 
 fn check_item(ccx: @crate_ctxt, it: @ast::item) {
     alt it.node {
       ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); }
-      ast::item_fn(decl, _, body) { check_fn(ccx, decl, body, it.id, none); }
+      ast::item_fn(decl, _, body) {
+        check_fn(ccx, ast::proto_bare, decl, body, it.id, none);
+      }
       ast::item_res(decl, _, body, dtor_id, _) {
-        check_fn(ccx, decl, body, dtor_id, none);
+        check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none);
       }
       ast::item_obj(ob, _, _) {
         // We're entering an object, so gather up the info we need.
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index 04516826ba7..b0d51b58040 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -202,7 +202,7 @@ tag expr_ {
     expr_for(@local, @expr, blk);
     expr_do_while(blk, @expr);
     expr_alt(@expr, [arm]);
-    expr_fn(fn_decl, blk, @capture_clause);
+    expr_fn(proto, fn_decl, blk, @capture_clause);
     expr_fn_block(fn_decl, blk);
     expr_block(blk);
 
@@ -317,7 +317,7 @@ tag ty_ {
     ty_port(@ty);
     ty_chan(@ty);
     ty_rec([ty_field]);
-    ty_fn(fn_decl);
+    ty_fn(proto, fn_decl);
     ty_obj([ty_method]);
     ty_tup([@ty]);
     ty_path(@path, node_id);
@@ -368,8 +368,7 @@ type ty_constr = spanned<ty_constr_>;
 type arg = {mode: mode, ty: @ty, ident: ident, id: node_id};
 
 type fn_decl =
-    {proto: proto,
-     inputs: [arg],
+    {inputs: [arg],
      output: @ty,
      purity: purity,
      cf: ret_style,
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index d06c98b0a31..9313bbcdc58 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -143,8 +143,7 @@ fn fold_mac_(m: mac, fld: ast_fold) -> mac {
 }
 
 fn fold_fn_decl(decl: ast::fn_decl, fld: ast_fold) -> ast::fn_decl {
-    ret {proto: decl.proto,
-         inputs: vec::map(decl.inputs, bind fold_arg_(_, fld)),
+    ret {inputs: vec::map(decl.inputs, bind fold_arg_(_, fld)),
          output: fld.fold_ty(decl.output),
          purity: decl.purity,
          cf: decl.cf,
@@ -192,8 +191,7 @@ fn noop_fold_native_item(&&ni: @native_item, fld: ast_fold) -> @native_item {
               alt ni.node {
                 native_item_ty. { native_item_ty }
                 native_item_fn(fdec, typms) {
-                  native_item_fn({proto: fdec.proto,
-                                  inputs: vec::map(fdec.inputs, fold_arg),
+                  native_item_fn({inputs: vec::map(fdec.inputs, fold_arg),
                                   output: fld.fold_ty(fdec.output),
                                   purity: fdec.purity,
                                   cf: fdec.cf,
@@ -398,8 +396,9 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
           expr_alt(expr, arms) {
             expr_alt(fld.fold_expr(expr), vec::map(arms, fld.fold_arm))
           }
-          expr_fn(decl, body, captures) {
-              expr_fn(fold_fn_decl(decl, fld), fld.fold_block(body), captures)
+          expr_fn(proto, decl, body, captures) {
+              expr_fn(proto, fold_fn_decl(decl, fld),
+                      fld.fold_block(body), captures)
           }
           expr_fn_block(decl, body) {
             expr_fn_block(fold_fn_decl(decl, fld), fld.fold_block(body))
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index b681f713422..dd649779235 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -280,21 +280,21 @@ fn parse_ty_fn(proto: ast::proto, p: parser) -> ast::ty_ {
     //  auto constrs = parse_constrs(~[], p);
     let constrs: [@ast::constr] = [];
     let (ret_style, ret_ty) = parse_ret_ty(p);
-    ret ast::ty_fn({proto: proto, inputs: inputs.node, output: ret_ty,
-                    purity: ast::impure_fn, cf: ret_style,
-                    constraints: constrs});
+    ret ast::ty_fn(proto, {inputs: inputs.node, output: ret_ty,
+                           purity: ast::impure_fn, cf: ret_style,
+                           constraints: constrs});
 }
 
 fn parse_ty_methods(p: parser, allow_tps: bool) -> [ast::ty_method] {
     parse_seq(token::LBRACE, token::RBRACE, seq_sep_none(), {|p|
         let flo = p.get_lo_pos();
-        let proto: ast::proto = parse_method_proto(p);
+        expect_word(p, "fn");
         let ident = parse_value_ident(p);
         let tps = allow_tps ? parse_ty_params(p) : [];
-        let f = parse_ty_fn(proto, p), fhi = p.get_last_hi_pos();
+        let f = parse_ty_fn(ast::proto_bare, p), fhi = p.get_last_hi_pos();
         expect(p, token::SEMI);
         alt f {
-          ast::ty_fn(d) {
+          ast::ty_fn(_, d) {
             {ident: ident, decl: d, tps: tps,
              span: ast_util::mk_sp(flo, fhi)}
           }
@@ -1284,10 +1284,10 @@ fn parse_capture_clause(p: parser) -> @ast::capture_clause {
 fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {
     let lo = p.get_last_lo_pos();
     let capture_clause = parse_capture_clause(p);
-    let decl = parse_fn_decl(p, proto, ast::impure_fn);
+    let decl = parse_fn_decl(p, ast::impure_fn);
     let body = parse_block(p);
     ret mk_expr(p, lo, body.span.hi,
-                ast::expr_fn(decl, body, capture_clause));
+                ast::expr_fn(proto, decl, body, capture_clause));
 }
 
 fn parse_fn_block_expr(p: parser) -> @ast::expr {
@@ -1738,7 +1738,7 @@ fn parse_ty_params(p: parser) -> [ast::ty_param] {
     } else { [] }
 }
 
-fn parse_fn_decl(p: parser, proto: ast::proto, purity: ast::purity)
+fn parse_fn_decl(p: parser, purity: ast::purity)
     -> ast::fn_decl {
     let inputs: ast::spanned<[ast::arg]> =
         parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
@@ -1752,8 +1752,7 @@ fn parse_fn_decl(p: parser, proto: ast::proto, purity: ast::purity)
         constrs = parse_constrs({|x| parse_ty_constr(inputs.node, x) }, p);
     }
     let (ret_style, ret_ty) = parse_ret_ty(p);
-    ret {proto: proto,
-         inputs: inputs.node,
+    ret {inputs: inputs.node,
          output: ret_ty,
          purity: purity,
          cf: ret_style,
@@ -1766,8 +1765,7 @@ fn parse_fn_block_decl(p: parser) -> ast::fn_decl {
                   seq_sep(token::COMMA), parse_fn_block_arg, p).node;
     let output = eat(p, token::RARROW) ? parse_ty(p, false) :
         @spanned(p.get_lo_pos(), p.get_hi_pos(), ast::ty_infer);
-    ret {proto: ast::proto_block,
-         inputs: inputs,
+    ret {inputs: inputs,
          output: output,
          purity: ast::impure_fn,
          cf: ast::return_val,
@@ -1789,11 +1787,11 @@ fn mk_item(p: parser, lo: uint, hi: uint, ident: ast::ident, node: ast::item_,
           span: ast_util::mk_sp(lo, hi)};
 }
 
-fn parse_item_fn(p: parser, purity: ast::purity, proto: ast::proto,
+fn parse_item_fn(p: parser, purity: ast::purity,
                  attrs: [ast::attribute]) -> @ast::item {
     let lo = p.get_last_lo_pos();
     let t = parse_fn_header(p);
-    let decl = parse_fn_decl(p, proto, purity);
+    let decl = parse_fn_decl(p, purity);
     let body = parse_block(p);
     ret mk_item(p, lo, body.span.hi, t.ident,
                 ast::item_fn(decl, t.tps, body), attrs);
@@ -1819,10 +1817,10 @@ fn parse_anon_obj_field(p: parser) -> ast::anon_obj_field {
 
 fn parse_method(p: parser, allow_tps: bool) -> @ast::method {
     let lo = p.get_lo_pos();
-    let proto = parse_method_proto(p);
+    expect_word(p, "fn");
     let ident = parse_value_ident(p);
     let tps = allow_tps ? parse_ty_params(p) : [];
-    let decl = parse_fn_decl(p, proto, ast::impure_fn);
+    let decl = parse_fn_decl(p, ast::impure_fn);
     let body = parse_block(p);
     @{ident: ident, tps: tps, decl: decl, body: body,
       id: p.get_id(), span: ast_util::mk_sp(lo, body.span.hi)}
@@ -1900,8 +1898,7 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
     expect(p, token::RPAREN);
     let dtor = parse_block_no_value(p);
     let decl =
-        {proto: ast::proto_bare,
-         inputs:
+        {inputs:
              [{mode: ast::by_ref, ty: t, ident: arg_ident,
                id: p.get_id()}],
          output: @spanned(lo, lo, ast::ty_nil),
@@ -1974,7 +1971,7 @@ fn parse_item_native_fn(p: parser, attrs: [ast::attribute],
                         purity: ast::purity) -> @ast::native_item {
     let lo = p.get_last_lo_pos();
     let t = parse_fn_header(p);
-    let decl = parse_fn_decl(p, ast::proto_bare, purity);
+    let decl = parse_fn_decl(p, purity);
     let hi = p.get_hi_pos();
     expect(p, token::SEMI);
     ret @{ident: t.ident,
@@ -2107,10 +2104,6 @@ fn parse_item_tag(p: parser, attrs: [ast::attribute]) -> @ast::item {
     ret mk_item(p, lo, hi, id, ast::item_tag(variants, ty_params), attrs);
 }
 
-fn parse_fn_item_proto(_p: parser) -> ast::proto {
-    ast::proto_bare
-}
-
 fn parse_fn_ty_proto(p: parser) -> ast::proto {
     if p.peek() == token::AT {
         p.bump();
@@ -2120,32 +2113,22 @@ fn parse_fn_ty_proto(p: parser) -> ast::proto {
     }
 }
 
-fn parse_method_proto(p: parser) -> ast::proto {
-    if eat_word(p, "fn") {
-        ret ast::proto_bare;
-    } else { unexpected(p, p.peek()); }
-}
-
 fn parse_item(p: parser, attrs: [ast::attribute]) -> option::t<@ast::item> {
     if eat_word(p, "const") {
         ret some(parse_item_const(p, attrs));
     } else if eat_word(p, "inline") {
         expect_word(p, "fn");
-        let proto = parse_fn_item_proto(p);
-        ret some(parse_item_fn(p, ast::impure_fn, proto, attrs));
+        ret some(parse_item_fn(p, ast::impure_fn, attrs));
     } else if is_word(p, "fn") && p.look_ahead(1u) != token::LPAREN {
         p.bump();
-        let proto = parse_fn_item_proto(p);
-        ret some(parse_item_fn(p, ast::impure_fn, proto, attrs));
+        ret some(parse_item_fn(p, ast::impure_fn, attrs));
     } else if eat_word(p, "pure") {
         expect_word(p, "fn");
-        let proto = parse_fn_item_proto(p);
-        ret some(parse_item_fn(p, ast::pure_fn, proto, attrs));
+        ret some(parse_item_fn(p, ast::pure_fn, attrs));
     } else if is_word(p, "unsafe") && p.look_ahead(1u) != token::LBRACE {
         p.bump();
         expect_word(p, "fn");
-        let proto = parse_fn_item_proto(p);
-        ret some(parse_item_fn(p, ast::unsafe_fn, proto, attrs));
+        ret some(parse_item_fn(p, ast::unsafe_fn, attrs));
     } else if eat_word(p, "mod") {
         ret some(parse_item_mod(p, attrs));
     } else if eat_word(p, "native") {
diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs
index 48893f67227..c8f6b1b0a87 100644
--- a/src/comp/syntax/print/pprust.rs
+++ b/src/comp/syntax/print/pprust.rs
@@ -305,8 +305,8 @@ fn print_type(s: ps, &&ty: @ast::ty) {
         commasep(s, inconsistent, elts, print_type);
         pclose(s);
       }
-      ast::ty_fn(d) {
-        print_ty_fn(s, d, none::<str>);
+      ast::ty_fn(proto, d) {
+        print_ty_fn(s, proto, d, none::<str>);
       }
       ast::ty_obj(methods) {
         head(s, "obj");
@@ -519,7 +519,7 @@ fn print_ty_method(s: ps, m: ast::ty_method) {
     hardbreak_if_not_bol(s);
     cbox(s, indent_unit);
     maybe_print_comment(s, m.span.lo);
-    print_ty_fn(s, m.decl, some(m.ident));
+    print_ty_fn(s, ast::proto_bare, m.decl, some(m.ident));
     word(s.s, ";");
     end(s);
 }
@@ -840,8 +840,8 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
         }
         bclose_(s, expr.span, alt_indent_unit);
       }
-      ast::expr_fn(decl, body, captures) { // NDM captures
-        head(s, proto_to_str(decl.proto));
+      ast::expr_fn(proto, decl, body, captures) { // NDM captures
+        head(s, proto_to_str(proto));
         print_fn_args_and_ret(s, decl);
         space(s.s);
         print_block(s, body);
@@ -1147,8 +1147,9 @@ fn print_pat(s: ps, &&pat: @ast::pat) {
 fn print_fn(s: ps, decl: ast::fn_decl, name: ast::ident,
             typarams: [ast::ty_param]) {
     alt decl.purity {
-      ast::impure_fn. { head(s, proto_to_str(decl.proto)); }
-      _ { head(s, "pure fn"); }
+      ast::impure_fn. { head(s, "fn"); }
+      ast::unsafe_fn. { head(s, "unsafe fn"); }
+      ast::pure_fn. { head(s, "pure fn"); }
     }
     word(s.s, name);
     print_type_params(s, typarams);
@@ -1360,9 +1361,10 @@ fn print_mt(s: ps, mt: ast::mt) {
     print_type(s, mt.ty);
 }
 
-fn print_ty_fn(s: ps, decl: ast::fn_decl, id: option::t<ast::ident>) {
+fn print_ty_fn(s: ps, proto: ast::proto,
+               decl: ast::fn_decl, id: option::t<ast::ident>) {
     ibox(s, indent_unit);
-    word(s.s, proto_to_str(decl.proto));
+    word(s.s, proto_to_str(proto));
     alt id { some(id) { word(s.s, " "); word(s.s, id); } _ { } }
     zerobreak(s.s);
     popen(s);
diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs
index 64dfafb9c4b..e2767160302 100644
--- a/src/comp/syntax/visit.rs
+++ b/src/comp/syntax/visit.rs
@@ -15,6 +15,28 @@ import codemap::span;
 // hold functions that take visitors. A vt tag is used to break the cycle.
 tag vt<E> { mk_vt(visitor<E>); }
 
+tag fn_kind {
+    fk_item_fn(ident, [ty_param]); //< an item declared with fn()
+    fk_method(ident, [ty_param]);
+    fk_res(ident, [ty_param]);
+    fk_anon(proto);  //< an anonymous function like lambda(...)
+    fk_fn_block;     //< a block {||...}
+}
+
+fn name_of_fn(fk: fn_kind) -> ident {
+    alt fk {
+      fk_item_fn(name, _) | fk_method(name, _) | fk_res(name, _) { name }
+      fk_anon(_) | fk_fn_block. { "anon" }
+    }
+}
+
+fn tps_of_fn(fk: fn_kind) -> [ty_param] {
+    alt fk {
+      fk_item_fn(_, tps) | fk_method(_, tps) | fk_res(_, tps) { tps }
+      fk_anon(_) | fk_fn_block. { [] }
+    }
+}
+
 type visitor<E> =
     // takes the components so that one function can be
     // generic over constr and ty_constr
@@ -31,8 +53,7 @@ type visitor<E> =
       visit_expr: fn@(@expr, E, vt<E>),
       visit_ty: fn@(@ty, E, vt<E>),
       visit_constr: fn@(@path, span, node_id, E, vt<E>),
-      visit_fn: fn@(fn_decl, [ty_param], blk, span, fn_ident, node_id,
-                    E, vt<E>)};
+      visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id, E, vt<E>)};
 
 fn default_visitor<E>() -> visitor<E> {
     ret @{visit_mod: bind visit_mod::<E>(_, _, _, _),
@@ -48,7 +69,7 @@ fn default_visitor<E>() -> visitor<E> {
           visit_expr: bind visit_expr::<E>(_, _, _),
           visit_ty: bind skip_ty::<E>(_, _, _),
           visit_constr: bind visit_constr::<E>(_, _, _, _, _),
-          visit_fn: bind visit_fn::<E>(_, _, _, _, _, _, _, _)};
+          visit_fn: bind visit_fn::<E>(_, _, _, _, _, _, _)};
 }
 
 fn visit_crate<E>(c: crate, e: E, v: vt<E>) {
@@ -85,7 +106,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
     alt i.node {
       item_const(t, ex) { v.visit_ty(t, e, v); v.visit_expr(ex, e, v); }
       item_fn(decl, tp, body) {
-        v.visit_fn(decl, tp, body, i.span, some(i.ident), i.id, e, v);
+        v.visit_fn(fk_item_fn(i.ident, tp), decl, body, i.span, i.id, e, v);
       }
       item_mod(m) { v.visit_mod(m, i.span, e, v); }
       item_native_mod(nm) {
@@ -94,8 +115,8 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
       }
       item_ty(t, tps) { v.visit_ty(t, e, v); visit_ty_params(tps, e, v); }
       item_res(decl, tps, body, dtor_id, _) {
-        v.visit_fn(decl, tps, body, i.span, some(i.ident), dtor_id,
-                   e, v);
+        v.visit_fn(fk_res(i.ident, tps), decl, body, i.span,
+                   dtor_id, e, v);
       }
       item_tag(variants, tps) {
         visit_ty_params(tps, e, v);
@@ -107,8 +128,8 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
         visit_ty_params(tps, e, v);
         for f: obj_field in ob.fields { v.visit_ty(f.ty, e, v); }
         for m: @method in ob.methods {
-            v.visit_fn(m.decl, m.tps, m.body, m.span,
-                       some(m.ident), m.id, e, v);
+            v.visit_fn(fk_method(m.ident, m.tps), m.decl, m.body, m.span,
+                       m.id, e, v);
         }
       }
       item_impl(tps, ifce, ty, methods) {
@@ -116,8 +137,8 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
         alt ifce { some(ty) { v.visit_ty(ty, e, v); } _ {} }
         v.visit_ty(ty, e, v);
         for m in methods {
-            v.visit_fn(m.decl, m.tps, m.body, m.span,
-                       some(m.ident), m.id, e, v);
+            v.visit_fn(fk_method(m.ident, m.tps), m.decl, m.body, m.span,
+                       m.id, e, v);
         }
       }
       item_iface(tps, methods) {
@@ -142,7 +163,7 @@ fn visit_ty<E>(t: @ty, e: E, v: vt<E>) {
         for f: ty_field in flds { v.visit_ty(f.node.mt.ty, e, v); }
       }
       ty_tup(ts) { for tt in ts { v.visit_ty(tt, e, v); } }
-      ty_fn(decl) {
+      ty_fn(_, decl) {
         for a in decl.inputs { v.visit_ty(a.ty, e, v); }
         for c: @constr in decl.constraints {
             v.visit_constr(c.node.path, c.span, c.node.id, e, v);
@@ -222,10 +243,10 @@ fn visit_fn_decl<E>(fd: fn_decl, e: E, v: vt<E>) {
     v.visit_ty(fd.output, e, v);
 }
 
-fn visit_fn<E>(decl: fn_decl, tp: [ty_param], body: blk, _sp: span,
-               _i: fn_ident, _id: node_id, e: E, v: vt<E>) {
+fn visit_fn<E>(fk: fn_kind, decl: fn_decl, body: blk, _sp: span,
+               _id: node_id, e: E, v: vt<E>) {
     visit_fn_decl(decl, e, v);
-    visit_ty_params(tp, e, v);
+    visit_ty_params(tps_of_fn(fk), e, v);
     v.visit_block(body, e, v);
 }
 
@@ -314,11 +335,11 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
         v.visit_expr(x, e, v);
         for a: arm in arms { v.visit_arm(a, e, v); }
       }
-      expr_fn(decl, body, _) {
-        v.visit_fn(decl, [], body, ex.span, none, ex.id, e, v);
+      expr_fn(proto, decl, body, _) {
+        v.visit_fn(fk_anon(proto), decl, body, ex.span, ex.id, e, v);
       }
       expr_fn_block(decl, body) {
-        v.visit_fn(decl, [], body, ex.span, none, ex.id, e, v);
+        v.visit_fn(fk_fn_block, decl, body, ex.span, ex.id, e, v);
       }
       expr_block(b) { v.visit_block(b, e, v); }
       expr_assign(a, b) { v.visit_expr(b, e, v); v.visit_expr(a, e, v); }
@@ -361,8 +382,8 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
           some(ex) { v.visit_expr(ex, e, v); }
         }
         for m: @method in anon_obj.methods {
-            v.visit_fn(m.decl, m.tps, m.body, m.span,
-                       some(m.ident), m.id, e, v);
+            v.visit_fn(fk_method(m.ident, m.tps), m.decl, m.body, m.span,
+                       m.id, e, v);
         }
       }
       expr_mac(mac) { visit_mac(mac, e, v); }
@@ -394,7 +415,7 @@ type simple_visitor =
       visit_expr: fn@(@expr),
       visit_ty: fn@(@ty),
       visit_constr: fn@(@path, span, node_id),
-      visit_fn: fn@(fn_decl, [ty_param], blk, span, fn_ident, node_id)};
+      visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id)};
 
 fn simple_ignore_ty(_t: @ty) {}
 
@@ -412,8 +433,8 @@ fn default_simple_visitor() -> simple_visitor {
           visit_expr: fn(_e: @expr) { },
           visit_ty: simple_ignore_ty,
           visit_constr: fn(_p: @path, _sp: span, _id: node_id) { },
-          visit_fn: fn(_d: fn_decl, _tps: [ty_param], _b: blk, _sp: span,
-                       _ident: fn_ident, _id: node_id) { }
+          visit_fn: fn(_fk: fn_kind, _d: fn_decl, _b: blk, _sp: span,
+                       _id: node_id) { }
          };
 }
 
@@ -472,11 +493,11 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
         f(pt, sp, id);
         visit_constr(pt, sp, id, e, v);
     }
-    fn v_fn(f: fn@(fn_decl, [ty_param], blk, span, fn_ident, node_id),
-            decl: fn_decl, tps: [ty_param], body: blk, sp: span,
-            ident: fn_ident, id: node_id, &&e: (), v: vt<()>) {
-        f(decl, tps, body, sp, ident, id);
-        visit_fn(decl, tps, body, sp, ident, id, e, v);
+    fn v_fn(f: fn@(fn_kind, fn_decl, blk, span, node_id),
+            fk: fn_kind, decl: fn_decl, body: blk, sp: span,
+            id: node_id, &&e: (), v: vt<()>) {
+        f(fk, decl, body, sp, id);
+        visit_fn(fk, decl, body, sp, id, e, v);
     }
     let visit_ty = if v.visit_ty == simple_ignore_ty {
         bind skip_ty(_, _, _)
@@ -497,7 +518,7 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
                 visit_expr: bind v_expr(v.visit_expr, _, _, _),
                 visit_ty: visit_ty,
                 visit_constr: bind v_constr(v.visit_constr, _, _, _, _, _),
-                visit_fn: bind v_fn(v.visit_fn, _, _, _, _, _, _, _, _)
+                visit_fn: bind v_fn(v.visit_fn, _, _, _, _, _, _, _)
                });
 }
 
diff --git a/src/comp/util/ppaux.rs b/src/comp/util/ppaux.rs
index 39cb65dcf30..ec1b90572c0 100644
--- a/src/comp/util/ppaux.rs
+++ b/src/comp/util/ppaux.rs
@@ -23,10 +23,6 @@ fn mode_str_1(m: ty::mode) -> str {
     alt m { ast::by_ref. { "ref" } _ { mode_str(m) } }
 }
 
-fn fn_ident_to_string(id: ast::node_id, i: ast::fn_ident) -> str {
-    ret alt i { none. { "anon" + int::str(id) } some(s) { s } };
-}
-
 fn ty_to_str(cx: ctxt, typ: t) -> str {
     fn fn_input_to_str(cx: ctxt, input: {mode: middle::ty::mode, ty: t}) ->
        str {
diff --git a/src/test/run-pass/block-arg-call-as.rs b/src/test/run-pass/block-arg-call-as.rs
new file mode 100644
index 00000000000..caef692060e
--- /dev/null
+++ b/src/test/run-pass/block-arg-call-as.rs
@@ -0,0 +1,22 @@
+use std;
+
+fn asSendfn( f : sendfn()->uint ) -> uint {
+   ret f();
+}
+
+fn asLambda( f : lambda()->uint ) -> uint {
+   ret f();
+}
+
+fn asBlock( f : block()->uint ) -> uint {
+   ret f();
+}
+
+fn main() {
+   let x = asSendfn({|| 22u});
+   assert(x == 22u);
+   let x = asLambda({|| 22u});
+   assert(x == 22u);
+   let x = asBlock({|| 22u});
+   assert(x == 22u);
+}