about summary refs log tree commit diff
path: root/src/comp/middle
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-10-06 12:26:12 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-10-07 09:09:50 +0200
commitf9fbd86f52cf597b85359ade1ca60b8d6ebf7286 (patch)
treed6f0cdd039642052f3ccb4ba8f3b9821bb7cbaaf /src/comp/middle
parent4709038d641ad009b44ed2bf5980fa3a252d6927 (diff)
Parse and typecheck by-value and by-ref arg specs
Add sprinkle && throughout the compiler to make it typecheck again.

Issue #1008
Diffstat (limited to 'src/comp/middle')
-rw-r--r--src/comp/middle/alias.rs4
-rw-r--r--src/comp/middle/ast_map.rs2
-rw-r--r--src/comp/middle/check_alt.rs4
-rw-r--r--src/comp/middle/freevars.rs4
-rw-r--r--src/comp/middle/mut.rs6
-rw-r--r--src/comp/middle/resolve.rs10
-rw-r--r--src/comp/middle/trans.rs20
-rw-r--r--src/comp/middle/trans_objects.rs5
-rw-r--r--src/comp/middle/tstate/pre_post_conditions.rs10
-rw-r--r--src/comp/middle/ty.rs34
-rw-r--r--src/comp/middle/typeck.rs59
11 files changed, 90 insertions, 68 deletions
diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs
index 03a060a57fd..5d9d736f209 100644
--- a/src/comp/middle/alias.rs
+++ b/src/comp/middle/alias.rs
@@ -251,10 +251,8 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
                        mutable ok: valid,
                        mutable copied: alt arg_t.mode {
                          ast::by_move. { copied }
-                         ast::by_ref. {
-                           i + 1u == by_ref ? not_allowed : not_copied
-                         }
                          ast::by_mut_ref. { not_allowed }
+                         _ { i + 1u == by_ref ? not_allowed : not_copied }
                        }}];
         i += 1u;
     }
diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs
index ce8c983c0f9..9b89ec63331 100644
--- a/src/comp/middle/ast_map.rs
+++ b/src/comp/middle/ast_map.rs
@@ -76,7 +76,7 @@ fn map_expr(cx: ctx, ex: @expr) {
 }
 
 fn new_smallintmap_int_adapter<@V>() -> std::map::hashmap<int, V> {
-    let key_idx = fn (key: int) -> uint { key as uint };
+    let key_idx = fn (&&key: int) -> uint { key as uint };
     let idx_key = fn (idx: uint) -> int { idx as int };
     ret new_smallintmap_adapter(key_idx, idx_key);
 }
diff --git a/src/comp/middle/check_alt.rs b/src/comp/middle/check_alt.rs
index 236b0403358..a3b58cf1600 100644
--- a/src/comp/middle/check_alt.rs
+++ b/src/comp/middle/check_alt.rs
@@ -11,7 +11,7 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
     tcx.sess.abort_if_errors();
 }
 
-fn check_expr(tcx: ty::ctxt, ex: @expr, s: (), v: visit::vt<()>) {
+fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
     visit::visit_expr(ex, s, v);
     alt ex.node { expr_alt(_, arms) { check_arms(tcx, arms); } _ { } }
 }
@@ -123,7 +123,7 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
     }
 }
 
-fn check_local(tcx: ty::ctxt, loc: @local, s: (), v: visit::vt<()>) {
+fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) {
     visit::visit_local(loc, s, v);
     if is_refutable(tcx, loc.node.pat) {
         tcx.sess.span_err(loc.node.pat.span,
diff --git a/src/comp/middle/freevars.rs b/src/comp/middle/freevars.rs
index e0a05a9f63e..5a6ed3283e7 100644
--- a/src/comp/middle/freevars.rs
+++ b/src/comp/middle/freevars.rs
@@ -29,10 +29,10 @@ fn collect_freevars(def_map: resolve::def_map, walker: fn(visit::vt<int>)) ->
     let seen = new_int_hash();
     let refs = @mutable [];
 
-    fn ignore_item(_i: @ast::item, _depth: int, _v: visit::vt<int>) { }
+    fn ignore_item(_i: @ast::item, &&_depth: int, _v: visit::vt<int>) { }
 
     let walk_expr =
-        lambda (expr: @ast::expr, depth: int, v: visit::vt<int>) {
+        lambda (expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
             alt expr.node {
               ast::expr_fn(f) {
                 if f.proto == ast::proto_block ||
diff --git a/src/comp/middle/mut.rs b/src/comp/middle/mut.rs
index 7952353ca2f..836f6de87e3 100644
--- a/src/comp/middle/mut.rs
+++ b/src/comp/middle/mut.rs
@@ -131,7 +131,7 @@ fn mk_err(cx: @ctx, span: syntax::codemap::span, msg: msg, name: str) {
     });
 }
 
-fn visit_decl(cx: @ctx, d: @decl, e: (), v: visit::vt<()>) {
+fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) {
     visit::visit_decl(d, e, v);
     alt d.node {
       decl_local(locs) {
@@ -148,7 +148,7 @@ fn visit_decl(cx: @ctx, d: @decl, e: (), v: visit::vt<()>) {
     }
 }
 
-fn visit_expr(cx: @ctx, ex: @expr, e: (), v: visit::vt<()>) {
+fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) {
     alt ex.node {
       expr_call(f, args) { check_call(cx, f, args); }
       expr_swap(lhs, rhs) {
@@ -225,7 +225,7 @@ fn check_call(cx: @ctx, f: @expr, args: [@expr]) {
         alt arg_t.mode {
           by_mut_ref. { check_lval(cx, args[i], msg_mut_ref); }
           by_move. { check_lval(cx, args[i], msg_move_out); }
-          by_ref. {}
+          _ {}
         }
         i += 1u;
     }
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 7018f8d1a85..fe95ecc0b85 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -1239,7 +1239,7 @@ fn mie_span(mie: mod_index_entry) -> span {
         };
 }
 
-fn check_item(e: @env, i: @ast::item, x: (), v: vt<()>) {
+fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) {
     fn typaram_names(tps: [ast::ty_param]) -> [ident] {
         let x: [ast::ident] = [];
         for tp: ast::ty_param in tps { x += [tp.ident]; }
@@ -1276,7 +1276,7 @@ fn check_pat(ch: checker, p: @ast::pat) {
     }
 }
 
-fn check_arm(e: @env, a: ast::arm, x: (), v: vt<()>) {
+fn check_arm(e: @env, a: ast::arm, &&x: (), v: vt<()>) {
     visit::visit_arm(a, x, v);
     let ch0 = checker(*e, "binding");
     check_pat(ch0, a.pats[0]);
@@ -1306,7 +1306,7 @@ fn check_arm(e: @env, a: ast::arm, x: (), v: vt<()>) {
     }
 }
 
-fn check_block(e: @env, b: ast::blk, x: (), v: vt<()>) {
+fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) {
     visit::visit_block(b, x, v);
     let values = checker(*e, "value");
     let types = checker(*e, "type");
@@ -1359,7 +1359,7 @@ fn check_fn(e: env, sp: span, f: ast::_fn) {
     ensure_unique(e, sp, f.decl.inputs, arg_name, "argument");
 }
 
-fn check_expr(e: @env, ex: @ast::expr, x: (), v: vt<()>) {
+fn check_expr(e: @env, ex: @ast::expr, &&x: (), v: vt<()>) {
     alt ex.node {
       ast::expr_rec(fields, _) {
         fn field_name(f: ast::field) -> ident { ret f.node.ident; }
@@ -1370,7 +1370,7 @@ fn check_expr(e: @env, ex: @ast::expr, x: (), v: vt<()>) {
     visit::visit_expr(ex, x, v);
 }
 
-fn check_ty(e: @env, ty: @ast::ty, x: (), v: vt<()>) {
+fn check_ty(e: @env, ty: @ast::ty, &&x: (), v: vt<()>) {
     alt ty.node {
       ast::ty_rec(fields) {
         fn field_name(f: ast::ty_field) -> ident { ret f.node.ident; }
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 10418cdfc54..294c9dfd15e 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -3699,7 +3699,7 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty0: TypeRef,
         // be inspected. It's important for the value
         // to have type lldestty0 (the callee's expected type).
         val = llvm::LLVMGetUndef(lldestty0);
-    } else if arg.mode == ast::by_ref {
+    } else if arg.mode == ast::by_ref || arg.mode == ast::by_val {
         let copied = false;
         if !lv.is_mem && type_is_immediate(ccx, e_ty) {
             val = do_spill_noroot(bcx, val);
@@ -4439,9 +4439,9 @@ fn lval_to_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
 // latter group "immediates" and, in some circumstances when we know we have a
 // pointer (or need one), perform load/store operations based on the
 // immediate-ness of the type.
+// FIXME simply call the version in ty.rs immediately
 fn type_is_immediate(ccx: @crate_ctxt, t: ty::t) -> bool {
-    ret ty::type_is_scalar(ccx.tcx, t) || ty::type_is_boxed(ccx.tcx, t) ||
-        ty::type_is_unique_box(ccx.tcx, t) || ty::type_is_native(ccx.tcx, t);
+    ty::type_is_immediate(ccx.tcx, t)
 }
 
 fn do_spill(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result {
@@ -5144,7 +5144,11 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
     for aarg: ast::arg in args {
         let arg_ty = arg_tys[arg_n].ty;
         alt aarg.mode {
-          ast::by_ref. {
+          ast::by_move. {
+            add_clean(bcx, fcx.llargs.get(aarg.id), arg_ty);
+          }
+          ast::by_mut_ref. { }
+          _ {
             let mutated =
                 !ignore_mut && fcx.lcx.ccx.mut_map.contains_key(aarg.id);
 
@@ -5160,10 +5164,6 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
                 add_clean(bcx, alloc, arg_ty);
             }
           }
-          ast::by_move. {
-            add_clean(bcx, fcx.llargs.get(aarg.id), arg_ty);
-          }
-          _ { }
         }
         arg_n += 1u;
     }
@@ -5790,7 +5790,7 @@ fn register_native_fn(ccx: @crate_ctxt, sp: span, path: [str], name: str,
     }
     fn convert_arg_to_i32(cx: @block_ctxt, v: ValueRef, t: ty::t,
                           mode: ty::mode) -> ValueRef {
-        if mode == ast::by_ref {
+        if mode == ast::by_ref || mode == ast::by_val {
             if ty::type_is_integral(bcx_tcx(cx), t) {
                 // FIXME: would be nice to have a postcondition that says
                 // if a type is integral, then it has static size (#586)
@@ -5845,7 +5845,7 @@ fn register_native_fn(ccx: @crate_ctxt, sp: span, path: [str], name: str,
     let i = arg_n;
     for arg: ty::arg in args {
         let llarg = llvm::LLVMGetParam(fcx.llfn, i);
-        if arg.mode == ast::by_ref {
+        if arg.mode == ast::by_ref || arg.mode == ast::by_val {
             llarg = load_if_immediate(bcx, llarg, arg.ty);
         }
         assert (llarg as int != 0);
diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs
index 3c42ce473dd..b9152d30ad2 100644
--- a/src/comp/middle/trans_objects.rs
+++ b/src/comp/middle/trans_objects.rs
@@ -41,7 +41,8 @@ fn trans_obj(cx: @local_ctxt, sp: span, ob: ast::_obj, ctor_id: ast::node_id,
     // we're creating.
     let fn_args: [ast::arg] = [];
     for f: ast::obj_field in ob.fields {
-        fn_args += [{mode: ast::by_ref, ty: f.ty, ident: f.ident, id: f.id}];
+        fn_args += [{mode: ast::by_ref, ty: f.ty, ident: f.ident,
+                     id: f.id}];
     }
     let fcx = new_fn_ctxt(cx, sp, llctor_decl);
 
@@ -397,7 +398,7 @@ tag vtbl_mthd {
 }
 
 // Alphabetize ast::methods by ident.  A helper for create_vtbl.
-fn ast_mthd_lteq(a: @ast::method, b: @ast::method) -> bool {
+fn ast_mthd_lteq(&&a: @ast::method, &&b: @ast::method) -> bool {
     ret str::lteq(a.node.ident, b.node.ident);
 }
 
diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs
index 9f2f1307478..036cf8ab0ce 100644
--- a/src/comp/middle/tstate/pre_post_conditions.rs
+++ b/src/comp/middle/tstate/pre_post_conditions.rs
@@ -99,10 +99,10 @@ fn find_pre_post_exprs(fcx: fn_ctxt, args: [@expr], id: node_id) {
     fn get_pp(ccx: crate_ctxt, e: @expr) -> pre_and_post {
         ret expr_pp(ccx, e);
     }
-    let pps = vec::map::<@expr, pre_and_post>(bind get_pp(fcx.ccx, _), args);
+    let pps = vec::map_imm(bind get_pp(fcx.ccx, _), args);
 
     set_pre_and_post(fcx.ccx, id, seq_preconds(fcx, pps),
-                     seq_postconds(fcx, vec::map(get_post, pps)));
+                     seq_postconds(fcx, vec::map_imm(get_post, pps)));
 }
 
 fn find_pre_post_loop(fcx: fn_ctxt, l: @local, index: @expr, body: blk,
@@ -476,8 +476,8 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
         }
         let alt_pps = [];
         for a: arm in alts { alt_pps += [do_an_alt(fcx, a)]; }
-        fn combine_pp(antec: pre_and_post, fcx: fn_ctxt, pp: pre_and_post,
-                      next: pre_and_post) -> pre_and_post {
+        fn combine_pp(antec: pre_and_post, fcx: fn_ctxt, &&pp: pre_and_post,
+                      &&next: pre_and_post) -> pre_and_post {
             union(pp.precondition, seq_preconds(fcx, [antec, next]));
             intersect(pp.postcondition, next.postcondition);
             ret pp;
@@ -694,7 +694,7 @@ fn find_pre_post_block(fcx: fn_ctxt, b: blk) {
         */
     }
     for s: @stmt in b.node.stmts { do_one_(fcx, s); }
-    fn do_inner_(fcx: fn_ctxt, e: @expr) { find_pre_post_expr(fcx, e); }
+    fn do_inner_(fcx: fn_ctxt, &&e: @expr) { find_pre_post_expr(fcx, e); }
     let do_inner = bind do_inner_(fcx, _);
     option::map::<@expr, ()>(do_inner, b.node.expr);
 
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index ec9821d6d26..faf11cb691a 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -160,6 +160,7 @@ export type_is_native;
 export type_is_nil;
 export type_is_pod;
 export type_is_scalar;
+export type_is_immediate;
 export type_is_sequence;
 export type_is_signed;
 export type_is_structural;
@@ -916,6 +917,12 @@ pure fn type_is_scalar(cx: ctxt, ty: t) -> bool {
     }
 }
 
+// FIXME maybe inline this for speed?
+fn type_is_immediate(cx: ctxt, ty: t) -> bool {
+    ret type_is_scalar(cx, ty) || type_is_boxed(cx, ty) ||
+        type_is_unique_box(cx, ty) || type_is_native(cx, ty);
+}
+
 fn type_has_pointers(cx: ctxt, ty: t) -> bool {
     alt cx.has_pointer_cache.find(ty) {
       some(result) { ret result; }
@@ -924,14 +931,8 @@ fn type_has_pointers(cx: ctxt, ty: t) -> bool {
 
     let result = false;
     alt struct(cx, ty) {
-
-
-
       // scalar types
-      ty_nil. {
-        /* no-op */
-
-      }
+      ty_nil. {/* no-op */ }
       ty_bot. {/* no-op */ }
       ty_bool. {/* no-op */ }
       ty_int. {/* no-op */ }
@@ -1446,14 +1447,14 @@ fn hash_type_info(st: sty, cname_opt: option::t<str>) -> uint {
     ret h;
 }
 
-fn hash_raw_ty(rt: @raw_t) -> uint { ret rt.hash; }
+fn hash_raw_ty(&&rt: @raw_t) -> uint { ret rt.hash; }
 
-fn hash_ty(typ: t) -> uint { ret typ; }
+fn hash_ty(&&typ: t) -> uint { ret typ; }
 
 
 // Type equality. This function is private to this module (and slow); external
 // users should use `eq_ty()` instead.
-fn eq_int(x: uint, y: uint) -> bool { ret x == y; }
+fn eq_int(&&x: uint, &&y: uint) -> bool { ret x == y; }
 
 fn arg_eq<T>(eq: fn(T, T) -> bool, a: @sp_constr_arg<T>, b: @sp_constr_arg<T>)
    -> bool {
@@ -1495,7 +1496,7 @@ fn constrs_eq(cs: [@constr], ds: [@constr]) -> bool {
 
 // An expensive type equality function. This function is private to this
 // module.
-fn eq_raw_ty(a: @raw_t, b: @raw_t) -> bool {
+fn eq_raw_ty(&&a: @raw_t, &&b: @raw_t) -> bool {
     // Check hashes (fast path).
 
     if a.hash != b.hash { ret false; }
@@ -1518,7 +1519,7 @@ fn eq_raw_ty(a: @raw_t, b: @raw_t) -> bool {
 
 // This is the equality function the public should use. It works as long as
 // the types are interned.
-fn eq_ty(a: t, b: t) -> bool { ret a == b; }
+fn eq_ty(&&a: t, &&b: t) -> bool { ret a == b; }
 
 
 // Type lookups
@@ -1954,12 +1955,15 @@ mod unify {
             let actual_input = actual_inputs[i];
             // Unify the result modes.
 
-            let result_mode;
-            if expected_input.mode != actual_input.mode {
+            let result_mode = if expected_input.mode == ast::mode_infer {
+                actual_input.mode
+            } else if actual_input.mode == ast::mode_infer {
+                expected_input.mode
+            } else if expected_input.mode != actual_input.mode {
                 ret fn_common_res_err
                     (ures_err(terr_mode_mismatch(expected_input.mode,
                                                  actual_input.mode)));
-            } else { result_mode = expected_input.mode; }
+            } else { expected_input.mode };
             let result = unify_step(cx, expected_input.ty, actual_input.ty);
             alt result {
               ures_ok(rty) { result_ins += [{mode: result_mode, ty: rty}]; }
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index bdf8b91c8ff..088e6eec6f5 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -224,7 +224,27 @@ fn type_is_scalar(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool {
 // Parses the programmer's textual representation of a type into our internal
 // notion of a type. `getter` is a function that returns the type
 // corresponding to a definition ID:
+fn default_arg_mode_for_ty(tcx: ty::ctxt, m: ast::mode,
+                           ty: ty::t) -> ast::mode {
+    alt m {
+      ast::mode_infer. {
+        alt ty::struct(tcx, ty) {
+            ty::ty_var(_) { ast::mode_infer }
+            _ {
+                if ty::type_is_immediate(tcx, ty) { ast::by_val }
+                else { ast::by_ref }
+            }
+        }
+      }
+      _ { m }
+    }
+}
 fn ast_ty_to_ty(tcx: ty::ctxt, getter: ty_getter, ast_ty: @ast::ty) -> ty::t {
+    fn ast_arg_to_arg(tcx: ty::ctxt, getter: ty_getter, arg: ast::ty_arg)
+        -> {mode: ty::mode, ty: ty::t} {
+        let ty = ast_ty_to_ty(tcx, getter, arg.node.ty);
+        ret {mode: default_arg_mode_for_ty(tcx, arg.node.mode, ty), ty: ty};
+    }
     alt tcx.ast_ty_to_ty_cache.find(ast_ty) {
       some(some(ty)) { ret ty; }
       some(none.) {
@@ -237,10 +257,6 @@ fn ast_ty_to_ty(tcx: ty::ctxt, getter: ty_getter, ast_ty: @ast::ty) -> ty::t {
     } /* go on */
 
     tcx.ast_ty_to_ty_cache.insert(ast_ty, none::<ty::t>);
-    fn ast_arg_to_arg(tcx: ty::ctxt, getter: ty_getter, arg: ast::ty_arg) ->
-       {mode: ty::mode, ty: ty::t} {
-        ret {mode: arg.node.mode, ty: ast_ty_to_ty(tcx, getter, arg.node.ty)};
-    }
     fn ast_mt_to_mt(tcx: ty::ctxt, getter: ty_getter, mt: ast::mt) -> ty::mt {
         ret {ty: ast_ty_to_ty(tcx, getter, mt.ty), mut: mt.mut};
     }
@@ -295,7 +311,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, getter: ty_getter, ast_ty: @ast::ty) -> ty::t {
         typ = ty::mk_ptr(tcx, ast_mt_to_mt(tcx, getter, mt));
       }
       ast::ty_tup(fields) {
-        let flds = vec::map(bind ast_ty_to_ty(tcx, getter, _), fields);
+        let flds = vec::map_imm(bind ast_ty_to_ty(tcx, getter, _), fields);
         typ = ty::mk_tup(tcx, flds);
       }
       ast::ty_rec(fields) {
@@ -550,9 +566,8 @@ mod collect {
         ret tpt;
     }
     fn ty_of_arg(cx: @ctxt, a: ast::arg) -> ty::arg {
-        let f = bind getter(cx, _);
-        let tt = ast_ty_to_ty(cx.tcx, f, a.ty);
-        ret {mode: a.mode, ty: tt};
+        let ty = ast_ty_to_ty(cx.tcx, bind getter(cx, _), a.ty);
+        {mode: default_arg_mode_for_ty(cx.tcx, a.mode, ty), ty: ty}
     }
     fn ty_of_method(cx: @ctxt, m: @ast::method) -> ty::method {
         let get = bind getter(cx, _);
@@ -1216,7 +1231,7 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
 
     // Add explicitly-declared locals.
     let visit_local =
-        lambda (local: @ast::local, e: (), v: visit::vt<()>) {
+        lambda (local: @ast::local, &&e: (), v: visit::vt<()>) {
             let local_ty = ast_ty_to_ty_crate_infer(ccx, local.node.ty);
             assign(local.node.id, ident_for_local(local), local_ty);
             visit::visit_local(local, e, v);
@@ -1224,7 +1239,7 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
 
     // Add pattern bindings.
     let visit_pat =
-        lambda (p: @ast::pat, e: (), v: visit::vt<()>) {
+        lambda (p: @ast::pat, &&e: (), v: visit::vt<()>) {
             alt p.node {
               ast::pat_bind(ident) { assign(p.id, ident, none); }
               _ {/* no-op */ }
@@ -2022,16 +2037,16 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         write::ty_only_fixup(fcx, id, result_ty);
       }
       ast::expr_fn(f) {
-        let cx = @{tcx: tcx};
         let convert = bind ast_ty_to_ty_crate_tyvar(fcx, _);
-        let ty_of_arg =
-            lambda (a: ast::arg) -> ty::arg {
-                let tt = ast_ty_to_ty_crate_tyvar(fcx, a.ty);
-                ret {mode: a.mode, ty: tt};
-            };
-        let fty =
-            collect::ty_of_fn_decl(cx, convert, ty_of_arg, f.decl, f.proto,
-                                   [], none).ty;
+        let ty_of_arg = lambda (a: ast::arg) -> ty::arg {
+            let tt = ast_ty_to_ty_crate_tyvar(fcx, a.ty);
+            ret {mode: default_arg_mode_for_ty(fcx.ccx.tcx, a.mode, tt),
+                 ty: tt};
+        };
+        let cx = @{tcx: tcx};
+        let fty = collect::ty_of_fn_decl(cx, convert, ty_of_arg, f.decl,
+                                         f.proto, [], none).ty;
+
         write::ty_only_fixup(fcx, id, fty);
 
         // Unify the type of the function with the expected type before we
@@ -2041,6 +2056,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         unify(fcx, expr.span, expected, fty);
 
         check_fn(fcx.ccx, f, id, some(fcx));
+        if f.proto == ast::proto_block {
+            write::ty_only_fixup(fcx, id, expected);
+        }
       }
       ast::expr_block(b) {
         // If this is an unchecked block, turn off purity-checking
@@ -2301,7 +2319,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         // FIXME: These next three functions are largely ripped off from
         // similar ones in collect::.  Is there a better way to do this?
         fn ty_of_arg(ccx: @crate_ctxt, a: ast::arg) -> ty::arg {
-            ret {mode: a.mode, ty: ast_ty_to_ty_crate(ccx, a.ty)};
+            let ty = ast_ty_to_ty_crate(ccx, a.ty);
+            ret {mode: default_arg_mode_for_ty(ccx.tcx, a.mode, ty), ty: ty};
         }
 
         fn ty_of_method(ccx: @crate_ctxt, m: @ast::method) -> ty::method {