about summary refs log tree commit diff
path: root/src
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
parent4709038d641ad009b44ed2bf5980fa3a252d6927 (diff)
downloadrust-f9fbd86f52cf597b85359ade1ca60b8d6ebf7286.tar.gz
rust-f9fbd86f52cf597b85359ade1ca60b8d6ebf7286.zip
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')
-rw-r--r--src/comp/front/attr.rs6
-rw-r--r--src/comp/front/config.rs43
-rw-r--r--src/comp/front/test.rs2
-rw-r--r--src/comp/lib/llvm.rs4
-rw-r--r--src/comp/metadata/common.rs2
-rw-r--r--src/comp/metadata/encoder.rs2
-rw-r--r--src/comp/metadata/tydecode.rs15
-rw-r--r--src/comp/metadata/tyencode.rs3
-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
-rw-r--r--src/comp/syntax/ast.rs2
-rw-r--r--src/comp/syntax/ast_util.rs4
-rw-r--r--src/comp/syntax/ext/simplext.rs4
-rw-r--r--src/comp/syntax/fold.rs62
-rw-r--r--src/comp/syntax/parse/parser.rs19
-rw-r--r--src/comp/syntax/print/pprust.rs30
-rw-r--r--src/comp/syntax/visit.rs28
-rw-r--r--src/comp/util/ppaux.rs4
-rw-r--r--src/lib/io.rs13
-rw-r--r--src/lib/list.rs2
-rw-r--r--src/lib/map.rs8
-rw-r--r--src/lib/option.rs5
-rw-r--r--src/lib/vec.rs11
32 files changed, 230 insertions, 197 deletions
diff --git a/src/comp/front/attr.rs b/src/comp/front/attr.rs
index a84c74b94f4..62c6a0282ce 100644
--- a/src/comp/front/attr.rs
+++ b/src/comp/front/attr.rs
@@ -57,7 +57,7 @@ fn get_attr_name(attr: ast::attribute) -> ast::ident {
 fn find_meta_items_by_name(metas: [@ast::meta_item], name: ast::ident) ->
    [@ast::meta_item] {
     let filter =
-        bind fn (m: @ast::meta_item, name: ast::ident) ->
+        bind fn (&&m: @ast::meta_item, name: ast::ident) ->
                 option::t<@ast::meta_item> {
                  if get_meta_item_name(m) == name {
                      option::some(m)
@@ -134,7 +134,7 @@ fn contains_name(metas: [@ast::meta_item], name: ast::ident) -> bool {
 
 // FIXME: This needs to sort by meta_item variant in addition to the item name
 fn sort_meta_items(items: [@ast::meta_item]) -> [@ast::meta_item] {
-    fn lteq(ma: @ast::meta_item, mb: @ast::meta_item) -> bool {
+    fn lteq(&&ma: @ast::meta_item, &&mb: @ast::meta_item) -> bool {
         fn key(m: @ast::meta_item) -> ast::ident {
             alt m.node {
               ast::meta_word(name) { name }
@@ -160,7 +160,7 @@ fn remove_meta_items_by_name(items: [@ast::meta_item], name: str) ->
    [@ast::meta_item] {
 
     let filter =
-        bind fn (item: @ast::meta_item, name: str) ->
+        bind fn (&&item: @ast::meta_item, name: str) ->
                 option::t<@ast::meta_item> {
                  if get_meta_item_name(item) != name {
                      option::some(item)
diff --git a/src/comp/front/config.rs b/src/comp/front/config.rs
index cdd95bd6313..cc2b35d8d9e 100644
--- a/src/comp/front/config.rs
+++ b/src/comp/front/config.rs
@@ -20,7 +20,7 @@ fn strip_unconfigured_items(crate: @ast::crate) -> @ast::crate {
     ret res;
 }
 
-fn filter_item(cfg: ast::crate_cfg, item: @ast::item) ->
+fn filter_item(cfg: ast::crate_cfg, &&item: @ast::item) ->
    option::t<@ast::item> {
     if item_in_cfg(cfg, item) { option::some(item) } else { option::none }
 }
@@ -29,11 +29,11 @@ fn fold_mod(cfg: ast::crate_cfg, m: ast::_mod, fld: fold::ast_fold) ->
    ast::_mod {
     let filter = bind filter_item(cfg, _);
     let filtered_items = vec::filter_map(filter, m.items);
-    ret {view_items: vec::map(fld.fold_view_item, m.view_items),
-         items: vec::map(fld.fold_item, filtered_items)};
+    ret {view_items: vec::map_imm(fld.fold_view_item, m.view_items),
+         items: vec::map_imm(fld.fold_item, filtered_items)};
 }
 
-fn filter_native_item(cfg: ast::crate_cfg, item: @ast::native_item) ->
+fn filter_native_item(cfg: ast::crate_cfg, &&item: @ast::native_item) ->
    option::t<@ast::native_item> {
     if native_item_in_cfg(cfg, item) {
         option::some(item)
@@ -46,11 +46,11 @@ fn fold_native_mod(cfg: ast::crate_cfg, nm: ast::native_mod,
     let filtered_items = vec::filter_map(filter, nm.items);
     ret {native_name: nm.native_name,
          abi: nm.abi,
-         view_items: vec::map(fld.fold_view_item, nm.view_items),
+         view_items: vec::map_imm(fld.fold_view_item, nm.view_items),
          items: filtered_items};
 }
 
-fn filter_stmt(cfg: ast::crate_cfg, stmt: @ast::stmt) ->
+fn filter_stmt(cfg: ast::crate_cfg, &&stmt: @ast::stmt) ->
    option::t<@ast::stmt> {
     alt stmt.node {
       ast::stmt_decl(decl, _) {
@@ -71,8 +71,8 @@ fn fold_block(cfg: ast::crate_cfg, b: ast::blk_, fld: fold::ast_fold) ->
    ast::blk_ {
     let filter = bind filter_stmt(cfg, _);
     let filtered_stmts = vec::filter_map(filter, b.stmts);
-    ret {stmts: vec::map(fld.fold_stmt, filtered_stmts),
-         expr: option::map(fld.fold_expr, b.expr),
+    ret {stmts: vec::map_imm(fld.fold_stmt, filtered_stmts),
+         expr: option::map_imm(fld.fold_expr, b.expr),
          id: b.id,
          rules: b.rules};
 }
@@ -97,21 +97,20 @@ fn in_cfg(cfg: ast::crate_cfg, attrs: [ast::attribute]) -> bool {
     // 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 item_cfg_metas =
-        {
-            fn extract_metas(inner_items: [@ast::meta_item],
-                             cfg_item: @ast::meta_item) -> [@ast::meta_item] {
-                alt cfg_item.node {
-                  ast::meta_list(name, items) {
-                    assert (name == "cfg");
-                    inner_items + items
-                  }
-                  _ { inner_items }
-                }
+    let item_cfg_metas = {
+        fn extract_metas(inner_items: [@ast::meta_item],
+                         &&cfg_item: @ast::meta_item) -> [@ast::meta_item] {
+            alt cfg_item.node {
+              ast::meta_list(name, items) {
+                assert (name == "cfg");
+                inner_items + items
+              }
+              _ { inner_items }
             }
-            let cfg_metas = attr::attr_metas(item_cfg_attrs);
-            vec::foldl(extract_metas, [], cfg_metas)
-        };
+        }
+        let cfg_metas = attr::attr_metas(item_cfg_attrs);
+        vec::foldl(extract_metas, [], cfg_metas)
+    };
 
     for cfg_mi: @ast::meta_item in item_cfg_metas {
         if attr::contains(cfg, cfg_mi) { ret true; }
diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs
index 9aed642a2d5..030a4faf5f9 100644
--- a/src/comp/front/test.rs
+++ b/src/comp/front/test.rs
@@ -56,7 +56,7 @@ fn fold_mod(_cx: test_ctxt, m: ast::_mod, fld: fold::ast_fold) -> ast::_mod {
     // the one we're going to add.  FIXME: This is sloppy. Instead we should
     // have some mechanism to indicate to the translation pass which function
     // we want to be main.
-    fn nomain(item: @ast::item) -> option::t<@ast::item> {
+    fn nomain(&&item: @ast::item) -> option::t<@ast::item> {
         alt item.node {
           ast::item_fn(f, _) {
             if item.ident == "main" {
diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs
index 83f5f4d8ef6..c47f75135d7 100644
--- a/src/comp/lib/llvm.rs
+++ b/src/comp/lib/llvm.rs
@@ -909,9 +909,9 @@ obj type_names(type_names: std::map::hashmap<TypeRef, str>,
 fn mk_type_names() -> type_names {
     let nt = std::map::new_str_hash::<TypeRef>();
 
-    fn hash(t: TypeRef) -> uint { ret t as uint; }
+    fn hash(&&t: TypeRef) -> uint { ret t as uint; }
 
-    fn eq(a: TypeRef, b: TypeRef) -> bool { ret a as uint == b as uint; }
+    fn eq(&&a: TypeRef, &&b: TypeRef) -> bool { ret a as uint == b as uint; }
 
     let hasher: std::map::hashfn<TypeRef> = hash;
     let eqer: std::map::eqfn<TypeRef> = eq;
diff --git a/src/comp/metadata/common.rs b/src/comp/metadata/common.rs
index a22dfa62d2b..134e43d6280 100644
--- a/src/comp/metadata/common.rs
+++ b/src/comp/metadata/common.rs
@@ -65,7 +65,7 @@ const tag_crate_dep: uint = 0x26u;
 const tag_items_data_item_inlineness: uint = 0x27u;
 
 // djb's cdb hashes.
-fn hash_node_id(node_id: int) -> uint { ret 177573u ^ (node_id as uint); }
+fn hash_node_id(&&node_id: int) -> uint { ret 177573u ^ (node_id as uint); }
 
 fn hash_path(s: str) -> uint {
     let h = 5381u;
diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs
index bf43b158be7..f8145c306c8 100644
--- a/src/comp/metadata/encoder.rs
+++ b/src/comp/metadata/encoder.rs
@@ -427,7 +427,7 @@ fn encode_index<T>(ebml_w: ebml::writer, buckets: [@[entry<T>]],
 
 fn write_str(writer: io::writer, s: str) { writer.write_str(s); }
 
-fn write_int(writer: io::writer, n: int) {
+fn write_int(writer: io::writer, &&n: int) {
     writer.write_be_uint(n as uint, 4u);
 }
 
diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs
index 3158b623439..e1123c3b623 100644
--- a/src/comp/metadata/tydecode.rs
+++ b/src/comp/metadata/tydecode.rs
@@ -380,14 +380,13 @@ fn parse_ty_fn(st: @pstate, sd: str_def) ->
     assert (next(st) as char == '[');
     let inputs: [ty::arg] = [];
     while peek(st) as char != ']' {
-        let mode = ast::by_ref;
-        if peek(st) as char == '&' {
-            mode = ast::by_mut_ref;
-            st.pos += 1u;
-        } else if peek(st) as char == '-' {
-            mode = ast::by_move;
-            st.pos += 1u;
-        }
+        let mode = alt peek(st) as char {
+          '&' { ast::by_mut_ref }
+          '-' { ast::by_move }
+          '=' { ast::by_ref }
+          '+' { ast::by_val }
+        };
+        st.pos += 1u;
         inputs += [{mode: mode, ty: parse_ty(st, sd)}];
     }
     st.pos += 1u; // eat the ']'
diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs
index 55c3b2bc5b7..4867b80e125 100644
--- a/src/comp/metadata/tyencode.rs
+++ b/src/comp/metadata/tyencode.rs
@@ -207,7 +207,8 @@ fn enc_ty_fn(w: io::writer, cx: @ctxt, args: [ty::arg], out: ty::t,
         alt arg.mode {
           by_mut_ref. { w.write_char('&'); }
           by_move. { w.write_char('-'); }
-          by_ref. { }
+          by_ref. { w.write_char('='); }
+          by_val. { w.write_char('+'); }
         }
         enc_ty(w, cx, arg.ty);
     }
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 {
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index 52aa6cb31d9..1864af6de9e 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -132,7 +132,7 @@ tag unop {
     deref; not; neg;
 }
 
-tag mode { by_ref; by_mut_ref; by_move; }
+tag mode { by_ref; by_val; by_mut_ref; by_move; mode_infer; }
 
 type stmt = spanned<stmt_>;
 
diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs
index c4d0272b95f..d70b63dac67 100644
--- a/src/comp/syntax/ast_util.rs
+++ b/src/comp/syntax/ast_util.rs
@@ -180,9 +180,9 @@ fn is_constraint_arg(e: @expr) -> bool {
     }
 }
 
-fn eq_ty(a: @ty, b: @ty) -> bool { ret std::box::ptr_eq(a, b); }
+fn eq_ty(&&a: @ty, &&b: @ty) -> bool { ret std::box::ptr_eq(a, b); }
 
-fn hash_ty(t: @ty) -> uint { ret t.span.lo << 16u + t.span.hi; }
+fn hash_ty(&&t: @ty) -> uint { ret t.span.lo << 16u + t.span.hi; }
 
 fn block_from_expr(e: @expr) -> blk {
     let blk_ = checked_blk([], option::some::<@expr>(e), e.id);
diff --git a/src/comp/syntax/ext/simplext.rs b/src/comp/syntax/ext/simplext.rs
index 528b2cdc756..5fafcdbb437 100644
--- a/src/comp/syntax/ext/simplext.rs
+++ b/src/comp/syntax/ext/simplext.rs
@@ -266,7 +266,7 @@ fn transcribe_exprs(cx: ext_ctxt, b: bindings, idx_path: @mutable [uint],
                     recur: fn(@expr) -> @expr, exprs: [@expr]) -> [@expr] {
     alt elts_to_ell(cx, exprs) {
       {pre: pre, rep: repeat_me_maybe, post: post} {
-        let res = vec::map(recur, pre);
+        let res = vec::map_imm(recur, pre);
         alt repeat_me_maybe {
           none. { }
           some(repeat_me) {
@@ -315,7 +315,7 @@ fn transcribe_exprs(cx: ext_ctxt, b: bindings, idx_path: @mutable [uint],
             }
           }
         }
-        res += vec::map(recur, post);
+        res += vec::map_imm(recur, post);
         ret res;
       }
     }
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index bf8504f3c1a..edee54fb808 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -110,7 +110,7 @@ fn fold_meta_item_(mi: @meta_item, fld: ast_fold) -> @meta_item {
                 meta_word(id) { meta_word(fld.fold_ident(id)) }
                 meta_list(id, mis) {
                   let fold_meta_item = bind fold_meta_item_(_, fld);
-                  meta_list(id, vec::map(fold_meta_item, mis))
+                  meta_list(id, vec::map_imm(fold_meta_item, mis))
                 }
                 meta_name_value(id, s) {
                   meta_name_value(fld.fold_ident(id), s)
@@ -153,10 +153,10 @@ fn noop_fold_crate(c: crate_, fld: ast_fold) -> crate_ {
     let fold_meta_item = bind fold_meta_item_(_, fld);
     let fold_attribute = bind fold_attribute_(_, fold_meta_item);
 
-    ret {directives: vec::map(fld.fold_crate_directive, c.directives),
+    ret {directives: vec::map_imm(fld.fold_crate_directive, c.directives),
          module: fld.fold_mod(c.module),
          attrs: vec::map(fold_attribute, c.attrs),
-         config: vec::map(fold_meta_item, c.config)};
+         config: vec::map_imm(fold_meta_item, c.config)};
 }
 
 fn noop_fold_crate_directive(cd: crate_directive_, fld: ast_fold) ->
@@ -167,7 +167,7 @@ fn noop_fold_crate_directive(cd: crate_directive_, fld: ast_fold) ->
           }
           cdir_dir_mod(id, fname, cds, attrs) {
             cdir_dir_mod(fld.fold_ident(id), fname,
-                         vec::map(fld.fold_crate_directive, cds), attrs)
+                         vec::map_imm(fld.fold_crate_directive, cds), attrs)
           }
           cdir_view_item(vi) { cdir_view_item(fld.fold_view_item(vi)) }
           cdir_syntax(_) { cd }
@@ -198,8 +198,8 @@ fn noop_fold_native_item(ni: @native_item, fld: ast_fold) -> @native_item {
                                   il: fdec.il,
                                   cf: fdec.cf,
                                   constraints:
-                                      vec::map(fld.fold_constr,
-                                               fdec.constraints)}, typms)
+                                      vec::map_imm(fld.fold_constr,
+                                                   fdec.constraints)}, typms)
                 }
               },
           id: ni.id,
@@ -237,8 +237,8 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
           }
           item_obj(o, typms, d) {
             item_obj({fields: vec::map(fold_obj_field, o.fields),
-                      methods: vec::map(fld.fold_method, o.methods)}, typms,
-                     d)
+                      methods: vec::map_imm(fld.fold_method, o.methods)},
+                     typms, d)
           }
           item_res(dtor, did, typms, cid) {
             item_res(fld.fold_fn(dtor), did, typms, cid)
@@ -252,8 +252,8 @@ fn noop_fold_method(m: method_, fld: ast_fold) -> method_ {
 
 
 fn noop_fold_block(b: blk_, fld: ast_fold) -> blk_ {
-    ret {stmts: vec::map(fld.fold_stmt, b.stmts),
-         expr: option::map(fld.fold_expr, b.expr),
+    ret {stmts: vec::map_imm(fld.fold_stmt, b.stmts),
+         expr: option::map_imm(fld.fold_expr, b.expr),
          id: b.id,
          rules: b.rules};
 }
@@ -269,8 +269,8 @@ fn noop_fold_stmt(s: stmt_, fld: ast_fold) -> stmt_ {
 }
 
 fn noop_fold_arm(a: arm, fld: ast_fold) -> arm {
-    ret {pats: vec::map(fld.fold_pat, a.pats),
-         guard: option::map(fld.fold_expr, a.guard),
+    ret {pats: vec::map_imm(fld.fold_pat, a.pats),
+         guard: option::map_imm(fld.fold_expr, a.guard),
          body: fld.fold_block(a.body)};
 }
 
@@ -280,7 +280,7 @@ fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ {
           pat_bind(ident) { pat_bind(fld.fold_ident(ident)) }
           pat_lit(_) { p }
           pat_tag(pth, pats) {
-            pat_tag(fld.fold_path(pth), vec::map(fld.fold_pat, pats))
+            pat_tag(fld.fold_path(pth), vec::map_imm(fld.fold_pat, pats))
           }
           pat_rec(fields, etc) {
             let fs = [];
@@ -289,7 +289,7 @@ fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ {
             }
             pat_rec(fs, etc)
           }
-          pat_tup(elts) { pat_tup(vec::map(fld.fold_pat, elts)) }
+          pat_tup(elts) { pat_tup(vec::map_imm(fld.fold_pat, elts)) }
           pat_box(inner) { pat_box(fld.fold_pat(inner)) }
           pat_uniq(inner) { pat_uniq(fld.fold_pat(inner)) }
           pat_range(_, _) { p }
@@ -334,8 +334,8 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
                      option::some(vec::map(fold_anon_obj_field, v))
                    }
                  },
-             methods: vec::map(fld.fold_method, ao.methods),
-             inner_obj: option::map(fld.fold_expr, ao.inner_obj)}
+             methods: vec::map_imm(fld.fold_method, ao.methods),
+             inner_obj: option::map_imm(fld.fold_expr, ao.inner_obj)}
     }
     let fold_anon_obj = bind fold_anon_obj_(_, fld);
 
@@ -347,15 +347,15 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
           }
           expr_rec(fields, maybe_expr) {
             expr_rec(vec::map(fold_field, fields),
-                     option::map(fld.fold_expr, maybe_expr))
+                     option::map_imm(fld.fold_expr, maybe_expr))
           }
-          expr_tup(elts) { expr_tup(vec::map(fld.fold_expr, elts)) }
+          expr_tup(elts) { expr_tup(vec::map_imm(fld.fold_expr, elts)) }
           expr_call(f, args) {
             expr_call(fld.fold_expr(f), fld.map_exprs(fld.fold_expr, args))
           }
           expr_self_method(id) { expr_self_method(fld.fold_ident(id)) }
           expr_bind(f, args) {
-            let opt_map_se = bind option::map(fld.fold_expr, _);
+            let opt_map_se = bind option::map_imm(fld.fold_expr, _);
             expr_bind(fld.fold_expr(f), vec::map(opt_map_se, args))
           }
           expr_binary(binop, lhs, rhs) {
@@ -366,7 +366,7 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
           expr_cast(expr, ty) { expr_cast(fld.fold_expr(expr), ty) }
           expr_if(cond, tr, fl) {
             expr_if(fld.fold_expr(cond), fld.fold_block(tr),
-                    option::map(fld.fold_expr, fl))
+                    option::map_imm(fld.fold_expr, fl))
           }
           expr_ternary(cond, tr, fl) {
             expr_ternary(fld.fold_expr(cond), fld.fold_expr(tr),
@@ -411,18 +411,18 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
             expr_index(fld.fold_expr(el), fld.fold_expr(er))
           }
           expr_path(pth) { expr_path(fld.fold_path(pth)) }
-          expr_fail(e) { expr_fail(option::map(fld.fold_expr, e)) }
+          expr_fail(e) { expr_fail(option::map_imm(fld.fold_expr, e)) }
           expr_break. { e }
           expr_cont. { e }
-          expr_ret(e) { expr_ret(option::map(fld.fold_expr, e)) }
-          expr_put(e) { expr_put(option::map(fld.fold_expr, e)) }
+          expr_ret(e) { expr_ret(option::map_imm(fld.fold_expr, e)) }
+          expr_put(e) { expr_put(option::map_imm(fld.fold_expr, e)) }
           expr_be(e) { expr_be(fld.fold_expr(e)) }
           expr_log(lv, e) { expr_log(lv, fld.fold_expr(e)) }
           expr_assert(e) { expr_assert(fld.fold_expr(e)) }
           expr_check(m, e) { expr_check(m, fld.fold_expr(e)) }
           expr_if_check(cond, tr, fl) {
             expr_if_check(fld.fold_expr(cond), fld.fold_block(tr),
-                          option::map(fld.fold_expr, fl))
+                          option::map_imm(fld.fold_expr, fl))
           }
           expr_anon_obj(ao) { expr_anon_obj(fold_anon_obj(ao)) }
           expr_mac(mac) { expr_mac(fold_mac(mac)) }
@@ -448,22 +448,22 @@ fn noop_fold_fn(f: _fn, fld: ast_fold) -> _fn {
               purity: f.decl.purity,
               il: f.decl.il,
               cf: f.decl.cf,
-              constraints: vec::map(fld.fold_constr, f.decl.constraints)},
+              constraints: vec::map_imm(fld.fold_constr, f.decl.constraints)},
          proto: f.proto,
          body: fld.fold_block(f.body)};
 }
 
 // ...nor do modules
 fn noop_fold_mod(m: _mod, fld: ast_fold) -> _mod {
-    ret {view_items: vec::map(fld.fold_view_item, m.view_items),
-         items: vec::map(fld.fold_item, m.items)};
+    ret {view_items: vec::map_imm(fld.fold_view_item, m.view_items),
+         items: vec::map_imm(fld.fold_item, m.items)};
 }
 
 fn noop_fold_native_mod(nm: native_mod, fld: ast_fold) -> native_mod {
     ret {native_name: nm.native_name,
          abi: nm.abi,
-         view_items: vec::map(fld.fold_view_item, nm.view_items),
-         items: vec::map(fld.fold_native_item, nm.items)}
+         view_items: vec::map_imm(fld.fold_view_item, nm.view_items),
+         items: vec::map_imm(fld.fold_native_item, nm.items)}
 }
 
 fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
@@ -479,7 +479,7 @@ fn noop_fold_ident(i: ident, _fld: ast_fold) -> ident { ret i; }
 fn noop_fold_path(p: path_, fld: ast_fold) -> path_ {
     ret {global: p.global,
          idents: vec::map(fld.fold_ident, p.idents),
-         types: vec::map(fld.fold_ty, p.types)};
+         types: vec::map_imm(fld.fold_ty, p.types)};
 }
 
 fn noop_fold_local(l: local_, fld: ast_fold) -> local_ {
@@ -499,7 +499,7 @@ fn noop_fold_local(l: local_, fld: ast_fold) -> local_ {
 /* temporarily eta-expand because of a compiler bug with using `fn<T>` as a
    value */
 fn noop_map_exprs(f: fn(@expr) -> @expr, es: [@expr]) -> [@expr] {
-    ret vec::map(f, es);
+    ret vec::map_imm(f, es);
 }
 
 fn noop_id(i: node_id) -> node_id { ret i; }
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 53c3aa01bf0..e220149f6f8 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -587,17 +587,11 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty {
 }
 
 fn parse_arg_mode(p: parser) -> ast::mode {
-    if eat(p, token::BINOP(token::AND)) {
-        ret ast::by_mut_ref;
-    } else if eat(p, token::BINOP(token::MINUS)) {
-        ret ast::by_move;
-    } else {
-        // FIXME Temporarily ignore these, to make it possible to implement
-        // them without breaking the stage0 build.
-        eat(p, token::ANDAND);
-        eat(p, token::BINOP(token::PLUS));
-        ret ast::by_ref;
-    }
+    if eat(p, token::BINOP(token::AND)) { ast::by_mut_ref }
+    else if eat(p, token::BINOP(token::MINUS)) { ast::by_move }
+    else if eat(p, token::ANDAND) { ast::by_ref }
+    else if eat(p, token::BINOP(token::PLUS)) { ast::by_val }
+    else { ast::mode_infer }
 }
 
 fn parse_arg(p: parser) -> ast::arg {
@@ -1890,7 +1884,8 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
     let dtor = parse_block_no_value(p);
     let decl =
         {inputs:
-             [{mode: ast::by_ref, ty: t, ident: arg_ident, id: p.get_id()}],
+             [{mode: ast::by_ref, ty: t, ident: arg_ident,
+               id: p.get_id()}],
          output: @spanned(lo, lo, ast::ty_nil),
          purity: ast::impure_fn,
          il: ast::il_normal,
diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs
index 555cd7fddee..a24b4c9b984 100644
--- a/src/comp/syntax/print/pprust.rs
+++ b/src/comp/syntax/print/pprust.rs
@@ -226,7 +226,7 @@ fn commasep_cmnt<IN>(s: ps, b: breaks, elts: [IN], op: fn(ps, IN),
 }
 
 fn commasep_exprs(s: ps, b: breaks, exprs: [@ast::expr]) {
-    fn expr_span(expr: @ast::expr) -> codemap::span { ret expr.span; }
+    fn expr_span(&&expr: @ast::expr) -> codemap::span { ret expr.span; }
     commasep_cmnt(s, b, exprs, print_expr, expr_span);
 }
 
@@ -246,7 +246,7 @@ fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) {
     for item: @ast::native_item in nmod.items { print_native_item(s, item); }
 }
 
-fn print_type(s: ps, ty: @ast::ty) {
+fn print_type(s: ps, &&ty: @ast::ty) {
     maybe_print_comment(s, ty.span.lo);
     ibox(s, 0u);
     alt ty.node {
@@ -365,7 +365,7 @@ fn print_native_item(s: ps, item: @ast::native_item) {
     }
 }
 
-fn print_item(s: ps, item: @ast::item) {
+fn print_item(s: ps, &&item: @ast::item) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, item.span.lo);
     print_outer_attributes(s, item.attrs);
@@ -678,7 +678,7 @@ fn print_mac(s: ps, m: ast::mac) {
     }
 }
 
-fn print_expr(s: ps, expr: @ast::expr) {
+fn print_expr(s: ps, &&expr: @ast::expr) {
     maybe_print_comment(s, expr.span.lo);
     ibox(s, indent_unit);
     let ann_node = node_expr(s, expr);
@@ -1080,7 +1080,7 @@ fn print_path(s: ps, path: ast::path, colons_before_params: bool) {
     }
 }
 
-fn print_pat(s: ps, pat: @ast::pat) {
+fn print_pat(s: ps, &&pat: @ast::pat) {
     maybe_print_comment(s, pat.span.lo);
     let ann_node = node_pat(s, pat);
     s.ann.pre(ann_node);
@@ -1145,7 +1145,7 @@ fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl, constrs: [@ast::constr]) {
     popen(s);
     fn print_arg(s: ps, x: ast::arg) {
         ibox(s, indent_unit);
-        print_alias(s, x.mode);
+        print_arg_mode(s, x.mode);
         word_space(s, x.ident + ":");
         print_type(s, x.ty);
         end(s);
@@ -1174,7 +1174,7 @@ fn print_fn_block_args(s: ps, decl: ast::fn_decl) {
     word(s.s, "|");
     fn print_arg(s: ps, x: ast::arg) {
         ibox(s, indent_unit);
-        print_alias(s, x.mode);
+        print_arg_mode(s, x.mode);
         word(s.s, x.ident);
         end(s);
     }
@@ -1183,11 +1183,13 @@ fn print_fn_block_args(s: ps, decl: ast::fn_decl) {
     maybe_print_comment(s, decl.output.span.lo);
 }
 
-fn print_alias(s: ps, m: ast::mode) {
+fn print_arg_mode(s: ps, m: ast::mode) {
     alt m {
       ast::by_mut_ref. { word(s.s, "&"); }
       ast::by_move. { word(s.s, "-"); }
-      ast::by_ref. { }
+      ast::by_ref. { word(s.s, "&&"); }
+      ast::by_val. { word(s.s, "+"); }
+      ast::mode_infer. {}
     }
 }
 
@@ -1211,7 +1213,7 @@ fn print_type_params(s: ps, params: [ast::ty_param]) {
     }
 }
 
-fn print_meta_item(s: ps, item: @ast::meta_item) {
+fn print_meta_item(s: ps, &&item: @ast::meta_item) {
     ibox(s, indent_unit);
     alt item.node {
       ast::meta_word(name) { word(s.s, name); }
@@ -1351,7 +1353,7 @@ fn print_ty_fn(s: ps, proto: ast::proto, id: option::t<ast::ident>,
     zerobreak(s.s);
     popen(s);
     fn print_arg(s: ps, input: ast::ty_arg) {
-        print_alias(s, input.node.mode);
+        print_arg_mode(s, input.node.mode);
         print_type(s, input.node.ty);
     }
     commasep(s, inconsistent, inputs, print_arg);
@@ -1418,7 +1420,7 @@ fn in_cbox(s: ps) -> bool {
     ret s.boxes[len - 1u] == pp::consistent;
 }
 
-fn print_literal(s: ps, lit: @ast::lit) {
+fn print_literal(s: ps, &&lit: @ast::lit) {
     maybe_print_comment(s, lit.span.lo);
     alt next_lit(s) {
       some(lt) {
@@ -1596,7 +1598,7 @@ fn constr_arg_to_str<T>(f: fn(T) -> str, c: ast::constr_arg_general_<T>) ->
 // needed b/c constr_args_to_str needs
 // something that takes an alias
 // (argh)
-fn uint_to_str(i: uint) -> str { ret uint::str(i); }
+fn uint_to_str(&&i: uint) -> str { ret uint::str(i); }
 
 fn ast_ty_fn_constr_to_str(c: @ast::constr) -> str {
     ret path_to_str(c.node.path) +
@@ -1614,7 +1616,7 @@ fn ast_ty_fn_constrs_str(constrs: [@ast::constr]) -> str {
     ret s;
 }
 
-fn fn_arg_idx_to_str(decl: ast::fn_decl, idx: uint) -> str {
+fn fn_arg_idx_to_str(decl: ast::fn_decl, &&idx: uint) -> str {
     decl.inputs[idx].ident
 }
 
diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs
index 2a002c3ada3..f234c2fb221 100644
--- a/src/comp/syntax/visit.rs
+++ b/src/comp/syntax/visit.rs
@@ -377,62 +377,62 @@ fn default_simple_visitor() -> simple_visitor {
 }
 
 fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
-    fn v_mod(f: fn(_mod, span), m: _mod, sp: span, e: (), v: vt<()>) {
+    fn v_mod(f: fn(_mod, span), m: _mod, sp: span, &&e: (), v: vt<()>) {
         f(m, sp);
         visit_mod(m, sp, e, v);
     }
-    fn v_view_item(f: fn(@view_item), vi: @view_item, e: (), v: vt<()>) {
+    fn v_view_item(f: fn(@view_item), vi: @view_item, &&e: (), v: vt<()>) {
         f(vi);
         visit_view_item(vi, e, v);
     }
-    fn v_native_item(f: fn(@native_item), ni: @native_item, e: (),
+    fn v_native_item(f: fn(@native_item), ni: @native_item, &&e: (),
                      v: vt<()>) {
         f(ni);
         visit_native_item(ni, e, v);
     }
-    fn v_item(f: fn(@item), i: @item, e: (), v: vt<()>) {
+    fn v_item(f: fn(@item), i: @item, &&e: (), v: vt<()>) {
         f(i);
         visit_item(i, e, v);
     }
-    fn v_local(f: fn(@local), l: @local, e: (), v: vt<()>) {
+    fn v_local(f: fn(@local), l: @local, &&e: (), v: vt<()>) {
         f(l);
         visit_local(l, e, v);
     }
-    fn v_block(f: fn(ast::blk), bl: ast::blk, e: (), v: vt<()>) {
+    fn v_block(f: fn(ast::blk), bl: ast::blk, &&e: (), v: vt<()>) {
         f(bl);
         visit_block(bl, e, v);
     }
-    fn v_stmt(f: fn(@stmt), st: @stmt, e: (), v: vt<()>) {
+    fn v_stmt(f: fn(@stmt), st: @stmt, &&e: (), v: vt<()>) {
         f(st);
         visit_stmt(st, e, v);
     }
-    fn v_arm(f: fn(arm), a: arm, e: (), v: vt<()>) {
+    fn v_arm(f: fn(arm), a: arm, &&e: (), v: vt<()>) {
         f(a);
         visit_arm(a, e, v);
     }
-    fn v_pat(f: fn(@pat), p: @pat, e: (), v: vt<()>) {
+    fn v_pat(f: fn(@pat), p: @pat, &&e: (), v: vt<()>) {
         f(p);
         visit_pat(p, e, v);
     }
-    fn v_decl(f: fn(@decl), d: @decl, e: (), v: vt<()>) {
+    fn v_decl(f: fn(@decl), d: @decl, &&e: (), v: vt<()>) {
         f(d);
         visit_decl(d, e, v);
     }
-    fn v_expr(f: fn(@expr), ex: @expr, e: (), v: vt<()>) {
+    fn v_expr(f: fn(@expr), ex: @expr, &&e: (), v: vt<()>) {
         f(ex);
         visit_expr(ex, e, v);
     }
-    fn v_ty(f: fn(@ty), ty: @ty, e: (), v: vt<()>) {
+    fn v_ty(f: fn(@ty), ty: @ty, &&e: (), v: vt<()>) {
         f(ty);
         visit_ty(ty, e, v);
     }
     fn v_constr(f: fn(path, span, node_id), pt: path, sp: span, id: node_id,
-                e: (), v: vt<()>) {
+                &&e: (), v: vt<()>) {
         f(pt, sp, id);
         visit_constr(pt, sp, id, e, v);
     }
     fn v_fn(f: fn(_fn, [ty_param], span, fn_ident, node_id), ff: _fn,
-            tps: [ty_param], sp: span, ident: fn_ident, id: node_id, e: (),
+            tps: [ty_param], sp: span, ident: fn_ident, id: node_id, &&e: (),
             v: vt<()>) {
         f(ff, tps, sp, ident, id);
         visit_fn(ff, tps, sp, ident, id, e, v);
diff --git a/src/comp/util/ppaux.rs b/src/comp/util/ppaux.rs
index 11c50affd28..3502eb80a06 100644
--- a/src/comp/util/ppaux.rs
+++ b/src/comp/util/ppaux.rs
@@ -13,9 +13,11 @@ import metadata::csearch;
 
 fn mode_str(m: ty::mode) -> str {
     alt m {
-      ast::by_ref. { "" }
+      ast::by_ref. { "&&" }
+      ast::by_val. { "+" }
       ast::by_mut_ref. { "&" }
       ast::by_move. { "-" }
+      _ { "" }
     }
 }
 
diff --git a/src/lib/io.rs b/src/lib/io.rs
index 73460e50588..d8f7f36b24f 100644
--- a/src/lib/io.rs
+++ b/src/lib/io.rs
@@ -175,14 +175,11 @@ fn stdin() -> reader {
 }
 
 fn file_reader(path: str) -> reader {
-    let f =
-        str::as_buf(path,
-                    {|pathbuf|
-                        str::as_buf("r",
-                                    {|modebuf|
-                                        os::libc::fopen(pathbuf, modebuf)
-                                    })
-                    });
+    let f = str::as_buf(path, {|pathbuf|
+        str::as_buf("r", {|modebuf|
+            os::libc::fopen(pathbuf, modebuf)
+        })
+    });
     if f as uint == 0u { log_err "error opening " + path; fail; }
     ret new_reader(FILE_buf_reader(f, option::some(@FILE_res(f))));
 }
diff --git a/src/lib/list.rs b/src/lib/list.rs
index 7037cff365a..58f976110d9 100644
--- a/src/lib/list.rs
+++ b/src/lib/list.rs
@@ -49,7 +49,7 @@ fn has<@T>(ls_: list<T>, elt: T) -> bool {
 }
 
 fn length<@T>(ls: list<T>) -> uint {
-    fn count<T>(_t: T, u: uint) -> uint { ret u + 1u; }
+    fn count<T>(_t: T, &&u: uint) -> uint { ret u + 1u; }
     ret foldl(ls, 0u, count);
 }
 
diff --git a/src/lib/map.rs b/src/lib/map.rs
index 81be20a6620..c63183b1893 100644
--- a/src/lib/map.rs
+++ b/src/lib/map.rs
@@ -199,14 +199,14 @@ fn new_str_hash<@V>() -> hashmap<str, V> {
 }
 
 fn new_int_hash<@V>() -> hashmap<int, V> {
-    fn hash_int(x: int) -> uint { ret x as uint; }
-    fn eq_int(a: int, b: int) -> bool { ret a == b; }
+    fn hash_int(&&x: int) -> uint { ret x as uint; }
+    fn eq_int(&&a: int, &&b: int) -> bool { ret a == b; }
     ret mk_hashmap(hash_int, eq_int);
 }
 
 fn new_uint_hash<@V>() -> hashmap<uint, V> {
-    fn hash_uint(x: uint) -> uint { ret x; }
-    fn eq_uint(a: uint, b: uint) -> bool { ret a == b; }
+    fn hash_uint(&&x: uint) -> uint { ret x; }
+    fn eq_uint(&&a: uint, &&b: uint) -> bool { ret a == b; }
     ret mk_hashmap(hash_uint, eq_uint);
 }
 
diff --git a/src/lib/option.rs b/src/lib/option.rs
index 53c19ba8c0a..56b56b5f69f 100644
--- a/src/lib/option.rs
+++ b/src/lib/option.rs
@@ -9,6 +9,11 @@ fn get<@T>(opt: t<T>) -> &T {
 fn map<@T, @U>(f: block(T) -> U, opt: t<T>) -> t<U> {
     alt opt { some(x) { some(f(x)) } none. { none } }
 }
+// FIXME This is needed to make working with by-value functions a bit less
+// painful. We should come up with a better solution.
+fn map_imm<@T, @U>(f: block(+T) -> U, opt: t<T>) -> t<U> {
+    alt opt { some(x) { some(f(x)) } none. { none } }
+}
 
 fn is_none<@T>(opt: t<T>) -> bool {
     alt opt { none. { true } some(_) { false } }
diff --git a/src/lib/vec.rs b/src/lib/vec.rs
index 59f29d40d7c..bc4334a06bc 100644
--- a/src/lib/vec.rs
+++ b/src/lib/vec.rs
@@ -191,6 +191,17 @@ fn map<@T, @U>(f: block(T) -> U, v: [mutable? T]) -> [U] {
     }
     ret result;
 }
+// FIXME This is needed to make working with by-value functions a bit less
+// painful. We should come up with a better solution.
+fn map_imm<@T, @U>(f: block(+T) -> U, v: [mutable? T]) -> [U] {
+    let result = [];
+    reserve(result, len(v));
+    for elem: T in v {
+        let elem2 = elem; // satisfies alias checker
+        result += [f(elem2)];
+    }
+    ret result;
+}
 
 fn map2<@T, @U, @V>(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] {
     let v0_len = len::<T>(v0);