about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fuzzer/fuzzer.rs4
-rw-r--r--src/libcore/vec.rs8
-rw-r--r--src/librustsyntax/ast.rs10
-rw-r--r--src/librustsyntax/fold.rs5
-rw-r--r--src/librustsyntax/parse/parser.rs238
-rw-r--r--src/librustsyntax/print/pprust.rs95
-rw-r--r--src/librustsyntax/visit.rs2
-rw-r--r--src/rustc/front/test.rs7
-rw-r--r--src/rustc/middle/alias.rs10
-rw-r--r--src/rustc/middle/capture.rs62
-rw-r--r--src/rustc/middle/check_loop.rs4
-rw-r--r--src/rustc/middle/freevars.rs4
-rw-r--r--src/rustc/middle/kind.rs10
-rw-r--r--src/rustc/middle/last_use.rs9
-rw-r--r--src/rustc/middle/mutbl.rs17
-rw-r--r--src/rustc/middle/region.rs2
-rw-r--r--src/rustc/middle/resolve.rs11
-rw-r--r--src/rustc/middle/trans/base.rs12
-rw-r--r--src/rustc/middle/trans/debuginfo.rs2
-rw-r--r--src/rustc/middle/trans/type_use.rs2
-rw-r--r--src/rustc/middle/tstate/pre_post_conditions.rs19
-rw-r--r--src/rustc/middle/tstate/states.rs12
-rw-r--r--src/rustc/middle/typeck.rs188
-rw-r--r--src/rustc/util/ppaux.rs15
-rw-r--r--src/test/compile-fail/cap-clause-move-upvar.rs5
-rw-r--r--src/test/compile-fail/pptypedef.rs8
-rw-r--r--src/test/compile-fail/vec-concat-bug.rs1
-rw-r--r--src/test/pretty/cap-clause.rs12
-rw-r--r--src/test/run-pass/cap-clause-move.rs23
-rw-r--r--src/test/run-pass/cap-clause-not-used.rs2
-rw-r--r--src/test/run-pass/last-use-in-cap-clause.rs2
31 files changed, 444 insertions, 357 deletions
diff --git a/src/fuzzer/fuzzer.rs b/src/fuzzer/fuzzer.rs
index 47c6371ad16..594748e2eb9 100644
--- a/src/fuzzer/fuzzer.rs
+++ b/src/fuzzer/fuzzer.rs
@@ -154,11 +154,11 @@ fn steal(crate: ast::crate, tm: test_mode) -> stolen_stuff {
 fn safe_to_replace_expr(e: ast::expr_, _tm: test_mode) -> bool {
     alt e {
       // https://github.com/mozilla/rust/issues/652
-      ast::expr_if(_, _, _) { false }
+      ast::expr_if(*) { false }
       ast::expr_block(_) { false }
 
       // expr_call is also missing a constraint
-      ast::expr_fn_block(_, _) { false }
+      ast::expr_fn_block(*) { false }
 
       _ { true }
     }
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 3215f3b9f28..cddb1346c01 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -1096,6 +1096,14 @@ impl extensions<T> for [T] {
     #[inline]
     fn map<U>(f: fn(T) -> U) -> [U] { map(self, f) }
     #[doc = "
+    Apply a function to the index and value of each element in the vector
+    and return the results
+    "]
+    fn mapi<U>(f: fn(uint, T) -> U) -> [U] {
+        let mut i = 0u;
+        self.map { |e| i += 1u; f(i - 1u, e) }
+    }
+    #[doc = "
     Apply a function to each element of a vector and return a concatenation
     of each result vector
     "]
diff --git a/src/librustsyntax/ast.rs b/src/librustsyntax/ast.rs
index 4a4b5ea4d38..12e29bcc3ec 100644
--- a/src/librustsyntax/ast.rs
+++ b/src/librustsyntax/ast.rs
@@ -311,8 +311,8 @@ enum expr_ {
        (implicit) condition is always true. */
     expr_loop(blk),
     expr_alt(@expr, [arm], alt_mode),
-    expr_fn(proto, fn_decl, blk, @capture_clause),
-    expr_fn_block(fn_decl, blk),
+    expr_fn(proto, fn_decl, blk, capture_clause),
+    expr_fn_block(fn_decl, blk, capture_clause),
     // Inner expr is always an expr_fn_block. We need the wrapping node to
     // sanely type this (a function returning nil on the inside but bool on
     // the outside).
@@ -356,15 +356,13 @@ enum expr_ {
 #[auto_serialize]
 type capture_item = {
     id: int,
+    is_move: bool,
     name: ident, // Currently, can only capture a local var.
     span: span
 };
 
 #[auto_serialize]
-type capture_clause = {
-    copies: [@capture_item],
-    moves: [@capture_item]
-};
+type capture_clause = [capture_item];
 
 /*
 // Says whether this is a block the user marked as
diff --git a/src/librustsyntax/fold.rs b/src/librustsyntax/fold.rs
index 30e8c5173b2..5ebaee71339 100644
--- a/src/librustsyntax/fold.rs
+++ b/src/librustsyntax/fold.rs
@@ -456,8 +456,9 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
               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))
+          expr_fn_block(decl, body, captures) {
+            expr_fn_block(fold_fn_decl(decl, fld), fld.fold_block(body),
+                          captures)
           }
           expr_block(blk) { expr_block(fld.fold_block(blk)) }
           expr_move(el, er) {
diff --git a/src/librustsyntax/parse/parser.rs b/src/librustsyntax/parse/parser.rs
index 0c681900dd5..0432faecba0 100644
--- a/src/librustsyntax/parse/parser.rs
+++ b/src/librustsyntax/parse/parser.rs
@@ -398,25 +398,51 @@ fn parse_arg_mode(p: parser) -> ast::mode {
     } else { ast::infer(p.get_id()) }
 }
 
-fn parse_arg(p: parser) -> ast::arg {
+fn parse_capture_item_or(
+    p: parser,
+    parse_arg_fn: fn() -> arg_or_capture_item) -> arg_or_capture_item {
+
+    fn parse_capture_item(p: parser, is_move: bool) -> ast::capture_item {
+        let id = p.get_id();
+        let sp = mk_sp(p.span.lo, p.span.hi);
+        let ident = parse_ident(p);
+        {id: id, is_move: is_move, name: ident, span: sp}
+    }
+
+    if eat_keyword(p, "move") {
+        either::right(parse_capture_item(p, true))
+    } else if eat_keyword(p, "copy") {
+        either::right(parse_capture_item(p, false))
+    } else {
+        parse_arg_fn()
+    }
+}
+
+fn parse_arg(p: parser) -> arg_or_capture_item {
     let m = parse_arg_mode(p);
     let i = parse_value_ident(p);
     expect(p, token::COLON);
     let t = parse_ty(p, false);
-    ret {mode: m, ty: t, ident: i, id: p.get_id()};
+    either::left({mode: m, ty: t, ident: i, id: p.get_id()})
 }
 
-fn parse_fn_block_arg(p: parser) -> ast::arg {
-    let m = parse_arg_mode(p);
-    let i = parse_value_ident(p);
-    let t = if eat(p, token::COLON) {
-                parse_ty(p, false)
-            } else {
-                @{id: p.get_id(),
-                  node: ast::ty_infer,
-                  span: mk_sp(p.span.lo, p.span.hi)}
-            };
-    ret {mode: m, ty: t, ident: i, id: p.get_id()};
+fn parse_arg_or_capture_item(p: parser) -> arg_or_capture_item {
+    parse_capture_item_or(p) {|| parse_arg(p) }
+}
+
+fn parse_fn_block_arg(p: parser) -> arg_or_capture_item {
+    parse_capture_item_or(p) {||
+        let m = parse_arg_mode(p);
+        let i = parse_value_ident(p);
+        let t = if eat(p, token::COLON) {
+                    parse_ty(p, false)
+                } else {
+                    @{id: p.get_id(),
+                      node: ast::ty_infer,
+                      span: mk_sp(p.span.lo, p.span.hi)}
+                };
+        either::left({mode: m, ty: t, ident: i, id: p.get_id()})
+    }
 }
 
 fn maybe_parse_dollar_mac(p: parser) -> option<ast::mac_> {
@@ -1149,74 +1175,27 @@ fn parse_if_expr(p: parser) -> @ast::expr {
     }
 }
 
-// Parses:
-//
-//   CC := [copy ID*; move ID*]
-//
-// where any part is optional and trailing ; is permitted.
-fn parse_capture_clause(p: parser) -> @ast::capture_clause {
-    fn expect_opt_trailing_semi(p: parser) {
-        if !eat(p, token::SEMI) {
-            if p.token != token::RBRACKET {
-                p.fatal("expecting ; or ]");
-            }
-        }
-    }
-
-    fn eat_ident_list(p: parser) -> [@ast::capture_item] {
-        let mut res = [];
-        loop {
-            alt p.token {
-              token::IDENT(_, _) {
-                let id = p.get_id();
-                let sp = mk_sp(p.span.lo, p.span.hi);
-                let ident = parse_ident(p);
-                res += [@{id:id, name:ident, span:sp}];
-                if !eat(p, token::COMMA) {
-                    ret res;
-                }
-              }
-
-              _ { ret res; }
-            }
-        };
-    }
-
-    let mut copies = [];
-    let mut moves = [];
+fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {
+    let lo = p.last_span.lo;
 
-    if eat(p, token::LBRACKET) {
-        while !eat(p, token::RBRACKET) {
-            if eat_keyword(p, "copy") {
-                copies += eat_ident_list(p);
-                expect_opt_trailing_semi(p);
-            } else if eat_keyword(p, "move") {
-                moves += eat_ident_list(p);
-                expect_opt_trailing_semi(p);
-            } else {
-                let s: str = "expecting send, copy, or move clause";
-                p.fatal(s);
-            }
-        }
-    }
+    let cc_old = parse_old_skool_capture_clause(p);
 
-    ret @{copies: copies, moves: moves};
-}
+    // if we want to allow fn expression argument types to be inferred in the
+    // future, just have to change parse_arg to parse_fn_block_arg.
+    let (decl, capture_clause) =
+        parse_fn_decl(p, ast::impure_fn, parse_arg_or_capture_item);
 
-fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {
-    let lo = p.last_span.lo;
-    let capture_clause = parse_capture_clause(p);
-    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(proto, decl, body, capture_clause));
+                ast::expr_fn(proto, decl, body, capture_clause + cc_old));
 }
 
 fn parse_fn_block_expr(p: parser) -> @ast::expr {
     let lo = p.last_span.lo;
-    let decl = parse_fn_block_decl(p);
+    let (decl, captures) = parse_fn_block_decl(p);
     let body = parse_block_tail(p, lo, ast::default_blk);
-    ret mk_expr(p, lo, body.span.hi, ast::expr_fn_block(decl, body));
+    ret mk_expr(p, lo, body.span.hi,
+                ast::expr_fn_block(decl, body, captures));
 }
 
 fn parse_else_expr(p: parser) -> @ast::expr {
@@ -1699,46 +1678,107 @@ fn parse_ty_params(p: parser) -> [ast::ty_param] {
     } else { [] }
 }
 
-fn parse_fn_decl(p: parser, purity: ast::purity)
-    -> ast::fn_decl {
-    let inputs: ast::spanned<[ast::arg]> =
+// FIXME Remove after snapshot
+fn parse_old_skool_capture_clause(p: parser) -> ast::capture_clause {
+    fn expect_opt_trailing_semi(p: parser) {
+        if !eat(p, token::SEMI) {
+            if p.token != token::RBRACKET {
+                p.fatal("expecting ; or ]");
+            }
+        }
+    }
+
+    fn eat_ident_list(p: parser, is_move: bool) -> [ast::capture_item] {
+        let mut res = [];
+        loop {
+            alt p.token {
+              token::IDENT(_, _) {
+                let id = p.get_id();
+                let sp = mk_sp(p.span.lo, p.span.hi);
+                let ident = parse_ident(p);
+                res += [{id:id, is_move: is_move, name:ident, span:sp}];
+                if !eat(p, token::COMMA) {
+                    ret res;
+                }
+              }
+
+              _ { ret res; }
+            }
+        };
+    }
+
+    let mut cap_items = [];
+
+    if eat(p, token::LBRACKET) {
+        while !eat(p, token::RBRACKET) {
+            if eat_keyword(p, "copy") {
+                cap_items += eat_ident_list(p, false);
+                expect_opt_trailing_semi(p);
+            } else if eat_keyword(p, "move") {
+                cap_items += eat_ident_list(p, true);
+                expect_opt_trailing_semi(p);
+            } else {
+                let s: str = "expecting send, copy, or move clause";
+                p.fatal(s);
+            }
+        }
+    }
+
+    ret cap_items;
+}
+
+type arg_or_capture_item = either<ast::arg, ast::capture_item>;
+
+
+fn parse_fn_decl(p: parser, purity: ast::purity,
+                 parse_arg_fn: fn(parser) -> arg_or_capture_item)
+    -> (ast::fn_decl, ast::capture_clause) {
+
+    let args_or_capture_items: [arg_or_capture_item] =
         parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
-                  parse_arg, p);
+                  parse_arg_fn, p).node;
+
+    let inputs = either::lefts(args_or_capture_items);
+    let capture_clause = either::rights(args_or_capture_items);
+
     // Use the args list to translate each bound variable
     // mentioned in a constraint to an arg index.
     // Seems weird to do this in the parser, but I'm not sure how else to.
     let mut constrs = [];
     if p.token == token::COLON {
         p.bump();
-        constrs = parse_constrs({|x| parse_ty_constr(inputs.node, x) }, p);
+        constrs = parse_constrs({|x| parse_ty_constr(inputs, x) }, p);
     }
     let (ret_style, ret_ty) = parse_ret_ty(p);
-    ret {inputs: inputs.node,
-         output: ret_ty,
-         purity: purity,
-         cf: ret_style,
-         constraints: constrs};
+    ret ({inputs: inputs,
+          output: ret_ty,
+          purity: purity,
+          cf: ret_style,
+          constraints: constrs}, capture_clause);
 }
 
-fn parse_fn_block_decl(p: parser) -> ast::fn_decl {
-    let inputs = if eat(p, token::OROR) {
-                     []
-                 } else {
-                     parse_seq(token::BINOP(token::OR),
-                               token::BINOP(token::OR),
-                               seq_sep(token::COMMA),
-                               parse_fn_block_arg, p).node
-                 };
+fn parse_fn_block_decl(p: parser) -> (ast::fn_decl, ast::capture_clause) {
+    let inputs_captures = {
+        if eat(p, token::OROR) {
+            []
+        } else {
+            parse_seq(token::BINOP(token::OR),
+                      token::BINOP(token::OR),
+                      seq_sep(token::COMMA),
+                      parse_fn_block_arg, p).node
+        }
+    };
     let output = if eat(p, token::RARROW) {
                      parse_ty(p, false)
                  } else {
                      @{id: p.get_id(), node: ast::ty_infer, span: p.span}
                  };
-    ret {inputs: inputs,
-         output: output,
-         purity: ast::impure_fn,
-         cf: ast::return_val,
-         constraints: []};
+    ret ({inputs: either::lefts(inputs_captures),
+          output: output,
+          purity: ast::impure_fn,
+          cf: ast::return_val,
+          constraints: []},
+         either::rights(inputs_captures));
 }
 
 fn parse_fn_header(p: parser) -> {ident: ast::ident, tps: [ast::ty_param]} {
@@ -1760,7 +1800,7 @@ fn parse_item_fn(p: parser, purity: ast::purity,
                  attrs: [ast::attribute]) -> @ast::item {
     let lo = p.last_span.lo;
     let t = parse_fn_header(p);
-    let decl = parse_fn_decl(p, purity);
+    let (decl, _) = parse_fn_decl(p, purity, parse_arg);
     let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
     let attrs = attrs + inner_attrs;
     ret mk_item(p, lo, body.span.hi, t.ident,
@@ -1785,7 +1825,7 @@ fn parse_method(p: parser, pr: ast::privacy) -> @ast::method {
     let lo = p.span.lo, pur = parse_fn_purity(p);
     let ident = parse_method_name(p);
     let tps = parse_ty_params(p);
-    let decl = parse_fn_decl(p, pur);
+    let (decl, _) = parse_fn_decl(p, pur, parse_arg);
     let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
     let attrs = attrs + inner_attrs;
     @{ident: ident, attrs: attrs, tps: tps, decl: decl, body: body,
@@ -1969,7 +2009,7 @@ fn parse_class_item(p:parser, class_name_with_tps: @ast::path)
         let lo = p.last_span.lo;
         // Can ctors have attrs?
             // result type is always the type of the class
-        let decl_ = parse_fn_decl(p, ast::impure_fn);
+        let (decl_, _) = parse_fn_decl(p, ast::impure_fn, parse_arg);
         let decl = {output: @{id: p.get_id(),
                       node: ast::ty_path(class_name_with_tps, p.get_id()),
                       span: decl_.output.span}
@@ -2048,7 +2088,7 @@ fn parse_item_native_fn(p: parser, attrs: [ast::attribute],
                         purity: ast::purity) -> @ast::native_item {
     let lo = p.last_span.lo;
     let t = parse_fn_header(p);
-    let decl = parse_fn_decl(p, purity);
+    let (decl, _) = parse_fn_decl(p, purity, parse_arg);
     let mut hi = p.span.hi;
     expect(p, token::SEMI);
     ret @{ident: t.ident,
diff --git a/src/librustsyntax/print/pprust.rs b/src/librustsyntax/print/pprust.rs
index b50f4f341a7..6e573041265 100644
--- a/src/librustsyntax/print/pprust.rs
+++ b/src/librustsyntax/print/pprust.rs
@@ -519,7 +519,7 @@ fn print_item(s: ps, &&item: @ast::item) {
           hardbreak_if_not_bol(s);
           maybe_print_comment(s, ctor.span.lo);
           head(s, "new");
-          print_fn_args_and_ret(s, ctor.node.dec);
+          print_fn_args_and_ret(s, ctor.node.dec, []);
           space(s.s);
           print_block(s, ctor.node.body);
           for items.each {|ci|
@@ -1018,18 +1018,17 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
         // head-box, will be closed by print-block at start
         ibox(s, 0u);
         word(s.s, proto_to_str(proto));
-        print_cap_clause(s, *cap_clause);
-        print_fn_args_and_ret(s, decl);
+        print_fn_args_and_ret(s, decl, cap_clause);
         space(s.s);
         print_block(s, body);
       }
-      ast::expr_fn_block(decl, body) {
+      ast::expr_fn_block(decl, body, cap_clause) {
         // containing cbox, will be closed by print-block at }
         cbox(s, indent_unit);
         // head-box, will be closed by print-block at start
         ibox(s, 0u);
         word(s.s, "{");
-        print_fn_block_args(s, decl);
+        print_fn_block_args(s, decl, cap_clause);
         print_possibly_embedded_block(s, body, block_block_fn, indent_unit);
       }
       ast::expr_loop_body(body) {
@@ -1319,46 +1318,27 @@ fn print_fn(s: ps, decl: ast::fn_decl, name: ast::ident,
     }
     word(s.s, name);
     print_type_params(s, typarams);
-    print_fn_args_and_ret(s, decl);
+    print_fn_args_and_ret(s, decl, []);
 }
 
-fn print_cap_clause(s: ps, cap_clause: ast::capture_clause) {
-    fn print_cap_item(s: ps, &&cap_item: @ast::capture_item) {
-        word(s.s, cap_item.name);
-    }
-
-    let has_copies = vec::is_not_empty(cap_clause.copies);
-    let has_moves = vec::is_not_empty(cap_clause.moves);
-    if !has_copies && !has_moves { ret; }
-
-    word(s.s, "[");
-
-    if has_copies {
-        word_nbsp(s, "copy");
-        commasep(s, inconsistent, cap_clause.copies, print_cap_item);
-        if has_moves {
-            word_space(s, ";");
+fn print_fn_args(s: ps, decl: ast::fn_decl,
+                 cap_items: [ast::capture_item]) {
+    commasep(s, inconsistent, decl.inputs, print_arg);
+    if cap_items.is_not_empty() {
+        let mut first = decl.inputs.is_empty();
+        for cap_items.each { |cap_item|
+            if first { first = false; } else { word_space(s, ","); }
+            if cap_item.is_move { word_nbsp(s, "move") }
+            else { word_nbsp(s, "copy") }
+            word(s.s, cap_item.name);
         }
     }
-
-    if has_moves {
-        word_nbsp(s, "move");
-        commasep(s, inconsistent, cap_clause.moves, print_cap_item);
-    }
-
-    word(s.s, "]");
 }
 
-fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
+fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl,
+                         cap_items: [ast::capture_item]) {
     popen(s);
-    fn print_arg(s: ps, x: ast::arg) {
-        ibox(s, indent_unit);
-        print_arg_mode(s, x.mode);
-        word_space(s, x.ident + ":");
-        print_type(s, x.ty);
-        end(s);
-    }
-    commasep(s, inconsistent, decl.inputs, print_arg);
+    print_fn_args(s, decl, cap_items);
     pclose(s);
     word(s.s, constrs_str(decl.constraints, {|c|
         ast_fn_constr_to_str(decl, c)
@@ -1372,19 +1352,10 @@ fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
     }
 }
 
-fn print_fn_block_args(s: ps, decl: ast::fn_decl) {
+fn print_fn_block_args(s: ps, decl: ast::fn_decl,
+                       cap_items: [ast::capture_item]) {
     word(s.s, "|");
-    fn print_arg(s: ps, x: ast::arg) {
-        ibox(s, indent_unit);
-        print_arg_mode(s, x.mode);
-        word(s.s, x.ident);
-        if x.ty.node != ast::ty_infer {
-            word_space(s, ":");
-            print_type(s, x.ty);
-        }
-        end(s);
-    }
-    commasep(s, inconsistent, decl.inputs, print_arg);
+    print_fn_args(s, decl, cap_items);
     word(s.s, "|");
     if decl.output.node != ast::ty_infer {
         space_if_not_bol(s);
@@ -1541,6 +1512,23 @@ fn print_mt(s: ps, mt: ast::mt) {
     print_type(s, mt.ty);
 }
 
+fn print_arg(s: ps, input: ast::arg) {
+    ibox(s, indent_unit);
+    print_arg_mode(s, input.mode);
+    alt input.ty.node {
+      ast::ty_infer {
+        word(s.s, input.ident);
+      }
+      _ {
+        if str::len(input.ident) > 0u {
+            word_space(s, input.ident + ":");
+        }
+        print_type(s, input.ty);
+      }
+    }
+    end(s);
+}
+
 fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
                decl: ast::fn_decl, id: option<ast::ident>,
                tps: option<[ast::ty_param]>) {
@@ -1550,13 +1538,6 @@ fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
     alt tps { some(tps) { print_type_params(s, tps); } _ { } }
     zerobreak(s.s);
     popen(s);
-    fn print_arg(s: ps, input: ast::arg) {
-        print_arg_mode(s, input.mode);
-        if str::len(input.ident) > 0u {
-            word_space(s, input.ident + ":");
-        }
-        print_type(s, input.ty);
-    }
     commasep(s, inconsistent, decl.inputs, print_arg);
     pclose(s);
     maybe_print_comment(s, decl.output.span.lo);
diff --git a/src/librustsyntax/visit.rs b/src/librustsyntax/visit.rs
index d2188977af0..2cac7f53e83 100644
--- a/src/librustsyntax/visit.rs
+++ b/src/librustsyntax/visit.rs
@@ -384,7 +384,7 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
       expr_fn(proto, decl, body, _) {
         v.visit_fn(fk_anon(proto), decl, body, ex.span, ex.id, e, v);
       }
-      expr_fn_block(decl, body) {
+      expr_fn_block(decl, body, _) {
         v.visit_fn(fk_fn_block, decl, body, ex.span, ex.id, e, v);
       }
       expr_block(b) { v.visit_block(b, e, v); }
diff --git a/src/rustc/front/test.rs b/src/rustc/front/test.rs
index 258c49daa9d..c23c6d5a997 100644
--- a/src/rustc/front/test.rs
+++ b/src/rustc/front/test.rs
@@ -365,15 +365,10 @@ fn mk_test_wrapper(cx: test_ctxt,
         rules: ast::default_blk
     });
 
-    let wrapper_capture: @ast::capture_clause = @{
-        copies: [],
-        moves: []
-    };
-
     let wrapper_expr: ast::expr = {
         id: cx.sess.next_node_id(),
         node: ast::expr_fn(ast::proto_bare, wrapper_decl,
-                           wrapper_body, wrapper_capture),
+                           wrapper_body, []),
         span: span
     };
 
diff --git a/src/rustc/middle/alias.rs b/src/rustc/middle/alias.rs
index f48a38e6a89..444947c471b 100644
--- a/src/rustc/middle/alias.rs
+++ b/src/rustc/middle/alias.rs
@@ -182,8 +182,8 @@ fn cant_copy(cx: ctx, b: binding) -> bool {
 fn local_id_for_args(cx: ctx, args: [@ast::expr]) -> uint {
     for vec::each(args) {|arg|
         alt arg.node {
-          ast::expr_fn_block(decl, _) | ast::expr_fn(_, decl, _, _) |
-          ast::expr_loop_body(@{node: ast::expr_fn_block(decl, _), _}) {
+          ast::expr_fn_block(decl, _, _) | ast::expr_fn(_, decl, _, _) |
+          ast::expr_loop_body(@{node: ast::expr_fn_block(decl, _, _), _}) {
             if decl.inputs.len() > 0u {
                 ret local_id_of_node(cx, decl.inputs[0].id);
             }
@@ -216,7 +216,7 @@ fn check_call(cx: @ctx, sc: scope, f: @ast::expr, args: [@ast::expr],
           ast::by_ref | ast::by_val | ast::by_move | ast::by_copy {}
         }
         alt arg.node {
-          ast::expr_fn_block(_, _) { blocks += [arg]; }
+          ast::expr_fn_block(*) { blocks += [arg]; }
           ast::expr_loop_body(b) { blocks += [b]; }
           _ {
             let root_var = path_def_id(*cx, root.ex);
@@ -267,7 +267,7 @@ fn check_call(cx: @ctx, sc: scope, f: @ast::expr, args: [@ast::expr],
                 let mut_alias =
                     (ast::by_mutbl_ref == ty::arg_mode(cx.tcx, arg_t));
                 alt args[i].node {
-                  ast::expr_fn_block(_, _) | ast::expr_loop_body(_) {}
+                  ast::expr_fn_block(*) | ast::expr_loop_body(_) {}
                   _ {
                     if i != j && ty_can_unsafely_include(
                         *cx, unsafe_ty, arg_t.ty, mut_alias) &&
@@ -306,7 +306,7 @@ fn check_call(cx: @ctx, sc: scope, f: @ast::expr, args: [@ast::expr],
         let inner_sc = {bs: bindings + sc.bs, invalid: sc.invalid};
         for blocks.each {|blk|
             alt check blk.node {
-              ast::expr_fn_block(_, body) {
+              ast::expr_fn_block(_, body, _) {
                 v.visit_block(body, inner_sc, v);
               }
             }
diff --git a/src/rustc/middle/capture.rs b/src/rustc/middle/capture.rs
index d7e09cce271..745469d0148 100644
--- a/src/rustc/middle/capture.rs
+++ b/src/rustc/middle/capture.rs
@@ -36,7 +36,7 @@ fn check_capture_clause(tcx: ty::ctxt,
     let freevars = freevars::get_freevars(tcx, fn_expr_id);
     let seen_defs = map::int_hash();
 
-    let check_capture_item = fn@(&&cap_item: @ast::capture_item) {
+    let check_capture_item = fn@(cap_item: ast::capture_item) {
         let cap_def = tcx.def_map.get(cap_item.id);
         if !vec::any(*freevars, {|fv| fv.def == cap_def}) {
             tcx.sess.span_warn(
@@ -54,36 +54,19 @@ fn check_capture_clause(tcx: ty::ctxt,
         }
     };
 
-    let check_not_upvar = fn@(&&cap_item: @ast::capture_item) {
-        alt tcx.def_map.get(cap_item.id) {
-          ast::def_upvar(_, _, _) {
-            tcx.sess.span_err(
-                cap_item.span,
-                #fmt("upvars (like '%s') cannot be moved into a closure",
-                     cap_item.name));
-          }
-          _ {}
-        }
-    };
-
-    let check_block_captures = fn@(v: [@ast::capture_item]) {
-        if check vec::is_not_empty(v) {
-            let cap_item0 = vec::head(v);
+    alt fn_proto {
+      ast::proto_any | ast::proto_block {
+        if vec::is_not_empty(cap_clause) {
+            let cap_item0 = vec::head(cap_clause);
             tcx.sess.span_err(
                 cap_item0.span,
                 "cannot capture values explicitly with a block closure");
         }
-    };
-
-    alt fn_proto {
-      ast::proto_any | ast::proto_block {
-        check_block_captures(cap_clause.copies);
-        check_block_captures(cap_clause.moves);
       }
       ast::proto_bare | ast::proto_box | ast::proto_uniq {
-        vec::iter(cap_clause.copies, check_capture_item);
-        vec::iter(cap_clause.moves, check_capture_item);
-        vec::iter(cap_clause.moves, check_not_upvar);
+        for cap_clause.each { |cap_item|
+            check_capture_item(cap_item);
+        }
       }
     }
 }
@@ -95,24 +78,31 @@ fn compute_capture_vars(tcx: ty::ctxt,
     let freevars = freevars::get_freevars(tcx, fn_expr_id);
     let cap_map = map::int_hash();
 
-    vec::iter(cap_clause.copies) { |cap_item|
-        let cap_def = tcx.def_map.get(cap_item.id);
-        let cap_def_id = ast_util::def_id_of_def(cap_def).node;
-        if vec::any(*freevars, {|fv| fv.def == cap_def}) {
-            cap_map.insert(cap_def_id, { def:cap_def, mode:cap_copy });
-        }
-    }
+    // first add entries for anything explicitly named in the cap clause
 
-    vec::iter(cap_clause.moves) { |cap_item|
+    for cap_clause.each { |cap_item|
         let cap_def = tcx.def_map.get(cap_item.id);
         let cap_def_id = ast_util::def_id_of_def(cap_def).node;
-        if vec::any(*freevars, {|fv| fv.def == cap_def}) {
-            cap_map.insert(cap_def_id, { def:cap_def, mode:cap_move });
+        if cap_item.is_move {
+            // if we are moving the value in, but it's not actually used,
+            // must drop it.
+            if vec::any(*freevars, {|fv| fv.def == cap_def}) {
+                cap_map.insert(cap_def_id, { def:cap_def, mode:cap_move });
+            } else {
+                cap_map.insert(cap_def_id, { def:cap_def, mode:cap_drop });
+            }
         } else {
-            cap_map.insert(cap_def_id, { def:cap_def, mode:cap_drop });
+            // if we are copying the value in, but it's not actually used,
+            // just ignore it.
+            if vec::any(*freevars, {|fv| fv.def == cap_def}) {
+                cap_map.insert(cap_def_id, { def:cap_def, mode:cap_copy });
+            }
         }
     }
 
+    // now go through anything that is referenced but was not explicitly
+    // named and add that
+
     let implicit_mode = alt fn_proto {
       ast::proto_any | ast::proto_block { cap_ref }
       ast::proto_bare | ast::proto_box | ast::proto_uniq { cap_copy }
diff --git a/src/rustc/middle/check_loop.rs b/src/rustc/middle/check_loop.rs
index 5082aba1394..99dadb5922a 100644
--- a/src/rustc/middle/check_loop.rs
+++ b/src/rustc/middle/check_loop.rs
@@ -21,10 +21,10 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
               expr_fn(_, _, _, _) {
                 visit::visit_expr(e, {in_loop: false, can_ret: true}, v);
               }
-              expr_fn_block(_, b) {
+              expr_fn_block(_, b, _) {
                 v.visit_block(b, {in_loop: false, can_ret: false}, v);
               }
-              expr_loop_body(@{node: expr_fn_block(_, b), _}) {
+              expr_loop_body(@{node: expr_fn_block(_, b, _), _}) {
                 let blk = is_blockish(ty::ty_fn_proto(ty::expr_ty(tcx, e)));
                 v.visit_block(b, {in_loop: true, can_ret: blk}, v);
               }
diff --git a/src/rustc/middle/freevars.rs b/src/rustc/middle/freevars.rs
index 727cbac4f23..df6a718de1d 100644
--- a/src/rustc/middle/freevars.rs
+++ b/src/rustc/middle/freevars.rs
@@ -40,12 +40,12 @@ fn collect_freevars(def_map: resolve::def_map, blk: ast::blk)
 
     let walk_expr = fn@(expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
             alt expr.node {
-              ast::expr_fn(proto, decl, _, captures) {
+              ast::expr_fn(proto, decl, _, _) {
                 if proto != ast::proto_bare {
                     visit::visit_expr(expr, depth + 1, v);
                 }
               }
-              ast::expr_fn_block(_, _) {
+              ast::expr_fn_block(_, _, _) {
                 visit::visit_expr(expr, depth + 1, v);
               }
               ast::expr_path(path) {
diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs
index dee278e7ed0..672629577d9 100644
--- a/src/rustc/middle/kind.rs
+++ b/src/rustc/middle/kind.rs
@@ -117,16 +117,14 @@ fn check_fn_cap_clause(cx: ctx,
     });
     //log("freevar_ids", freevar_ids);
     with_appropriate_checker(cx, id) { |checker|
-        let check_var = fn@(&&cap_item: @capture_item) {
+        for cap_clause.each { |cap_item|
             let cap_def = cx.tcx.def_map.get(cap_item.id);
             let cap_def_id = ast_util::def_id_of_def(cap_def).node;
             if !vec::contains(freevar_ids, cap_def_id) {
                 let ty = ty::node_id_to_type(cx.tcx, cap_def_id);
                 checker(cx, ty, cap_item.span);
             }
-        };
-        vec::iter(cap_clause.copies, check_var);
-        vec::iter(cap_clause.moves, check_var);
+        }
     }
 }
 
@@ -227,8 +225,8 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
             }
         }
       }
-      expr_fn(_, _, _, cap_clause) {
-        check_fn_cap_clause(cx, e.id, *cap_clause);
+      expr_fn(_, _, _, cap_clause) | expr_fn_block(_, _, cap_clause) {
+        check_fn_cap_clause(cx, e.id, cap_clause);
       }
       _ { }
     }
diff --git a/src/rustc/middle/last_use.rs b/src/rustc/middle/last_use.rs
index 083274c8db5..1364118730a 100644
--- a/src/rustc/middle/last_use.rs
+++ b/src/rustc/middle/last_use.rs
@@ -154,12 +154,15 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
         v.visit_expr(dest, cx, v);
         clear_if_path(cx, dest, v, true);
       }
+      expr_fn_block(_, _, cap_clause) |
       expr_fn(_, _, _, cap_clause) {
         // n.b.: safe to ignore copies, as if they are unused
         // then they are ignored, otherwise they will show up
         // as freevars in the body.
-        vec::iter(cap_clause.moves) {|ci|
-            clear_def_if_local(cx, cx.def_map.get(ci.id), false);
+        for cap_clause.each { |ci|
+            if ci.is_move {
+                clear_def_if_local(cx, cx.def_map.get(ci.id), false);
+            }
         }
         visit::visit_expr(ex, cx, v);
       }
@@ -169,7 +172,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
         let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f));
         vec::iter2(args, arg_ts) {|arg, arg_t|
             alt arg.node {
-              expr_fn(_, _, _, _) | expr_fn_block(_, _)
+              expr_fn(*) | expr_fn_block(*)
               if is_blockish(ty::ty_fn_proto(arg_t.ty)) {
                 fns += [arg];
               }
diff --git a/src/rustc/middle/mutbl.rs b/src/rustc/middle/mutbl.rs
index 35561c56e65..572d1c234de 100644
--- a/src/rustc/middle/mutbl.rs
+++ b/src/rustc/middle/mutbl.rs
@@ -199,14 +199,17 @@ fn visit_expr(ex: @expr, &&cx: @ctx, v: visit::vt<@ctx>) {
       expr_assign(dest, src) | expr_assign_op(_, dest, src) {
         check_lval(cx, dest, msg_assign);
       }
-      expr_fn(_, _, _, cap) {
-        for cap.moves.each {|moved|
-            let def = cx.tcx.def_map.get(moved.id);
-            alt is_illegal_to_modify_def(cx, def, msg_move_out) {
-              some(name) { mk_err(cx, moved.span, msg_move_out, moved.name); }
-              _ { }
+      expr_fn(_, _, _, cap_clause) | expr_fn_block(_, _, cap_clause) {
+        for cap_clause.each { |cap_item|
+            if cap_item.is_move {
+                let def = cx.tcx.def_map.get(cap_item.id);
+                alt is_illegal_to_modify_def(cx, def, msg_move_out) {
+                  some(name) { mk_err(cx, cap_item.span,
+                                      msg_move_out, name); }
+                  _ { }
+                }
+                cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ());
             }
-            cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ());
         }
       }
       _ { }
diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs
index 53c52cf9fc2..87ba22fc8bb 100644
--- a/src/rustc/middle/region.rs
+++ b/src/rustc/middle/region.rs
@@ -286,7 +286,7 @@ fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt<ctxt>) {
 fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
     record_parent(cx, expr.id);
     alt expr.node {
-      ast::expr_fn(_, _, _, _) | ast::expr_fn_block(_, _) {
+      ast::expr_fn(*) | ast::expr_fn_block(*) {
         let new_cx = {parent: some(expr.id) with cx};
         visit::visit_expr(expr, new_cx, visitor);
       }
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index 933a3ba48b2..379c5c66ab8 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -390,7 +390,7 @@ fn check_unused_imports(e: @env, level: lint::level) {
     };
 }
 
-fn resolve_capture_item(e: @env, sc: scopes, &&cap_item: @ast::capture_item) {
+fn resolve_capture_item(e: @env, sc: scopes, cap_item: ast::capture_item) {
     let dcur = lookup_in_scope_strict(
         *e, sc, cap_item.span, cap_item.name, ns_val);
     maybe_insert(e, cap_item.id, dcur);
@@ -453,10 +453,11 @@ fn resolve_names(e: @env, c: @ast::crate) {
             maybe_insert(e, exp.id,
                          lookup_path_strict(*e, sc, exp.span, p, ns_val));
           }
-          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);
+          ast::expr_fn(_, _, _, cap_clause) |
+          ast::expr_fn_block(_, _, cap_clause) {
+            for cap_clause.each { |ci|
+                resolve_capture_item(e, sc, ci);
+            }
           }
           _ { }
         }
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index a06d78c24bb..6c1b81a371d 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -2544,11 +2544,11 @@ fn trans_cast(cx: block, e: @ast::expr, id: ast::node_id,
 fn trans_loop_body(bcx: block, e: @ast::expr, ret_flag: option<ValueRef>,
                    dest: dest) -> block {
     alt check e.node {
-      ast::expr_loop_body(b@@{node: ast::expr_fn_block(decl, body), _}) {
+      ast::expr_loop_body(b@@{node: ast::expr_fn_block(decl, body, cap), _}) {
         alt check ty::get(expr_ty(bcx, e)).struct {
           ty::ty_fn({proto, _}) {
             closure::trans_expr_fn(bcx, proto, decl, body, e.span, b.id,
-                                   {copies: [], moves: []}, some(ret_flag),
+                                   cap, some(ret_flag),
                                    dest)
           }
         }
@@ -2800,7 +2800,7 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t, ret_ty: ty::t,
     -> block {
     let ret_in_loop = alt args {
       arg_exprs(args) { args.len() > 0u && alt vec::last(args).node {
-        ast::expr_loop_body(@{node: ast::expr_fn_block(_, body), _}) {
+        ast::expr_loop_body(@{node: ast::expr_fn_block(_, body, _), _}) {
           body_contains_ret(body)
         }
         _ { false }
@@ -3166,15 +3166,15 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
       ast::expr_addr_of(_, x) { ret trans_addr_of(bcx, x, dest); }
       ast::expr_fn(proto, decl, body, cap_clause) {
         ret closure::trans_expr_fn(bcx, proto, decl, body, e.span, e.id,
-                                   *cap_clause, none, dest);
+                                   cap_clause, none, dest);
       }
-      ast::expr_fn_block(decl, body) {
+      ast::expr_fn_block(decl, body, cap_clause) {
         alt check ty::get(expr_ty(bcx, e)).struct {
           ty::ty_fn({proto, _}) {
             #debug("translating fn_block %s with type %s",
                    expr_to_str(e), ty_to_str(tcx, expr_ty(bcx, e)));
             ret closure::trans_expr_fn(bcx, proto, decl, body, e.span, e.id,
-                                       {copies: [], moves: []}, none, dest);
+                                       cap_clause, none, dest);
           }
         }
       }
diff --git a/src/rustc/middle/trans/debuginfo.rs b/src/rustc/middle/trans/debuginfo.rs
index 3176c234b7a..44f66f7a70e 100644
--- a/src/rustc/middle/trans/debuginfo.rs
+++ b/src/rustc/middle/trans/debuginfo.rs
@@ -772,7 +772,7 @@ fn create_function(fcx: fn_ctxt) -> @metadata<subprogram_md> {
           ast::expr_fn(_, decl, _, _) {
             (dbg_cx.names("fn"), decl.output, expr.id)
           }
-          ast::expr_fn_block(decl, _) {
+          ast::expr_fn_block(decl, _, _) {
             (dbg_cx.names("fn"), decl.output, expr.id)
           }
           _ { fcx.ccx.sess.span_bug(expr.span, "create_function: \
diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs
index bee159e3373..3ec11d5b0c4 100644
--- a/src/rustc/middle/trans/type_use.rs
+++ b/src/rustc/middle/trans/type_use.rs
@@ -160,7 +160,7 @@ fn mark_for_expr(cx: ctx, e: @expr) {
             }
         }
       }
-      expr_fn(_, _, _, _) | expr_fn_block(_, _) {
+      expr_fn(*) | expr_fn_block(*) {
         alt ty::ty_fn_proto(ty::expr_ty(cx.ccx.tcx, e)) {
           proto_bare | proto_any | proto_uniq {}
           proto_box | proto_block {
diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs
index 4cc00940202..196b891850e 100644
--- a/src/rustc/middle/tstate/pre_post_conditions.rs
+++ b/src/rustc/middle/tstate/pre_post_conditions.rs
@@ -340,24 +340,21 @@ 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) | expr_fn_block(_, _, cap_clause) {
         find_pre_post_expr_fn_upvars(fcx, e);
 
-        let use_cap_item = fn@(&&cap_item: @capture_item) {
+        for cap_clause.each { |cap_item|
             let d = local_node_id_to_local_def_id(fcx, cap_item.id);
             option::iter(d, { |id| use_var(fcx, id) });
-        };
-        vec::iter(cap_clause.copies, use_cap_item);
-        vec::iter(cap_clause.moves, use_cap_item);
+        }
 
-        vec::iter(cap_clause.moves) { |cap_item|
-            log(debug, ("forget_in_postcond: ", cap_item));
-            forget_in_postcond(fcx, e.id, cap_item.id);
+        for cap_clause.each { |cap_item|
+            if cap_item.is_move {
+                log(debug, ("forget_in_postcond: ", cap_item));
+                forget_in_postcond(fcx, e.id, cap_item.id);
+            }
         }
       }
-      expr_fn_block(_, _) {
-        find_pre_post_expr_fn_upvars(fcx, e);
-      }
       expr_block(b) {
         find_pre_post_block(fcx, b);
         let p = block_pp(fcx.ccx, b);
diff --git a/src/rustc/middle/tstate/states.rs b/src/rustc/middle/tstate/states.rs
index efad557fbe7..8397fa879cf 100644
--- a/src/rustc/middle/tstate/states.rs
+++ b/src/rustc/middle/tstate/states.rs
@@ -363,8 +363,10 @@ fn find_pre_post_state_cap_clause(fcx: fn_ctxt, e_id: node_id,
     let ccx = fcx.ccx;
     let pres_changed = set_prestate_ann(ccx, e_id, pres);
     let post = tritv_clone(pres);
-    vec::iter(cap_clause.moves) { |cap_item|
-        forget_in_poststate(fcx, post, cap_item.id);
+    for cap_clause.each { |cap_item|
+        if cap_item.is_move {
+            forget_in_poststate(fcx, post, cap_item.id);
+        }
     }
     ret set_poststate_ann(ccx, e_id, post) || pres_changed;
 }
@@ -418,9 +420,11 @@ 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) {
-        ret find_pre_post_state_cap_clause(fcx, e.id, pres, *cap_clause);
+        ret find_pre_post_state_cap_clause(fcx, e.id, pres, cap_clause);
+      }
+      expr_fn_block(_, _, 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); }
       expr_block(b) {
         ret find_pre_post_state_block(fcx, pres, b) |
                 set_prestate_ann(fcx.ccx, e.id, pres) |
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index d8db45d8919..81e32078215 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -275,7 +275,8 @@ fn instantiate_path(fcx: @fn_ctxt,
     fcx.write_ty_substs(id, tpt.ty, substs);
 }
 
-// Type tests
+// Resolves `typ` by a single level if `typ` is a type variable.  If no
+// resolution is possible, then an error is reported.
 fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
     alt infer::resolve_shallow(fcx.infcx, tp, false) {
       result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; }
@@ -286,7 +287,6 @@ fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
     }
 }
 
-
 // Returns the one-level-deep structure of the given type.
 fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty {
     ty::get(structurally_resolved_type(fcx, sp, typ)).struct
@@ -689,7 +689,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
         ty::mk_rec(tcx, flds)
       }
       ast::ty_fn(proto, decl) {
-        ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl))
+        ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl, none))
       }
       ast::ty_path(path, id) {
         let a_def = alt tcx.def_map.find(id) {
@@ -777,7 +777,13 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
         ty::mk_constr(tcx, ast_ty_to_ty(self, rscope, t), out_cs)
       }
       ast::ty_infer {
-        self.ty_infer(ast_ty.span)
+        // ty_infer should only appear as the type of arguments or return
+        // values in a fn_expr, or as the type of local variables.  Both of
+        // these cases are handled specially and should not descend into this
+        // routine.
+        self.tcx().sess.span_bug(
+            ast_ty.span,
+            "found `ty_infer` in unexpected place");
       }
       ast::ty_mac(_) {
         tcx.sess.span_bug(ast_ty.span,
@@ -850,7 +856,8 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
       }
       ast::item_fn(decl, tps, _) {
         let bounds = ty_param_bounds(ccx, tps);
-        let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare, decl);
+        let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare,
+                                 decl, none);
         let tpt = {bounds: bounds,
                    rp: ast::rp_none, // functions do not have a self
                    ty: ty::mk_fn(ccx.tcx, tofd)};
@@ -884,7 +891,8 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
       }
       ast::item_res(decl, tps, _, _, _, rp) {
         let {bounds, substs} = mk_substs(ccx, tps, rp);
-        let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
+        let t_arg = ty_of_arg(ccx, type_rscope(rp),
+                              decl.inputs[0], none);
         let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs);
         let t_res = {bounds: bounds, rp: rp, ty: t};
         tcx.tcache.insert(local_def(it.id), t_res);
@@ -1027,16 +1035,27 @@ fn replace_bound_regions(
 }
 
 fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
-    self: AC, rscope: RS, a: ast::arg) -> ty::arg {
+    self: AC, rscope: RS, a: ast::arg,
+    expected_ty: option<ty::arg>) -> ty::arg {
+
+    let ty = alt a.ty.node {
+      ast::ty_infer if expected_ty.is_some() {expected_ty.get().ty}
+      ast::ty_infer {self.ty_infer(a.ty.span)}
+      _ {ast_ty_to_ty(self, rscope, a.ty)}
+    };
 
-    fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode {
-        alt m {
+    let mode = {
+        alt a.mode {
+          ast::infer(_) if expected_ty.is_some() {
+            result::get(ty::unify_mode(self.tcx(), a.mode,
+                                       expected_ty.get().mode))
+          }
           ast::infer(_) {
             alt ty::get(ty).struct {
               // If the type is not specified, then this must be a fn expr.
               // Leave the mode as infer(_), it will get inferred based
               // on constraints elsewhere.
-              ty::ty_var(_) { m }
+              ty::ty_var(_) {a.mode}
 
               // If the type is known, then use the default for that type.
               // Here we unify m and the default.  This should update the
@@ -1044,30 +1063,48 @@ fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
               // will have been unified with m yet:
               _ {
                 let m1 = ast::expl(ty::default_arg_mode_for_ty(ty));
-                result::get(ty::unify_mode(tcx, m, m1))
+                result::get(ty::unify_mode(self.tcx(), a.mode, m1))
               }
             }
           }
-          ast::expl(_) { m }
+          ast::expl(_) {a.mode}
         }
-    }
+    };
 
-    let ty = ast_ty_to_ty(self, rscope, a.ty);
-    let mode = arg_mode(self.tcx(), a.mode, ty);
     {mode: mode, ty: ty}
 }
+
+type expected_tys = option<{inputs: [ty::arg],
+                            output: ty::t}>;
+
 fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy>(
     self: AC, rscope: RS,
     proto: ast::proto,
-    decl: ast::fn_decl) -> ty::fn_ty {
+    decl: ast::fn_decl,
+    expected_tys: expected_tys) -> ty::fn_ty {
 
     #debug["ty_of_fn_decl"];
     indent {||
         // new region names that appear inside of the fn decl are bound to
         // that function type
         let rb = in_binding_rscope(rscope);
-        let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(self, rb, a) };
-        let output_ty = ast_ty_to_ty(self, rb, decl.output);
+
+        let input_tys = decl.inputs.mapi { |i, a|
+            let expected_arg_ty = expected_tys.chain { |e|
+                // no guarantee that the correct number of expected args
+                // were supplied
+                if i < e.inputs.len() {some(e.inputs[i])} else {none}
+            };
+            ty_of_arg(self, rb, a, expected_arg_ty)
+        };
+
+        let expected_ret_ty = expected_tys.map { |e| e.output };
+        let output_ty = alt decl.output.node {
+          ast::ty_infer if expected_ret_ty.is_some() {expected_ret_ty.get()}
+          ast::ty_infer {self.ty_infer(decl.output.span)}
+          _ {ast_ty_to_ty(self, rb, decl.output)}
+        };
+
         let out_constrs = vec::map(decl.constraints) {|constr|
             ty::ast_constr_to_constr(self.tcx(), constr)
         };
@@ -1083,7 +1120,7 @@ fn ty_of_native_fn_decl(ccx: @crate_ctxt,
 
     let bounds = ty_param_bounds(ccx, ty_params);
     let rb = in_binding_rscope(empty_rscope);
-    let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(ccx, rb, a) };
+    let input_tys = decl.inputs.map { |a| ty_of_arg(ccx, rb, a, none) };
     let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
 
     let t_fn = ty::mk_fn(ccx.tcx, {proto: ast::proto_bare,
@@ -1135,7 +1172,8 @@ fn ty_of_method(ccx: @crate_ctxt,
                 rp: ast::region_param) -> ty::method {
     {ident: m.ident,
      tps: ty_param_bounds(ccx, m.tps),
-     fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, m.decl),
+     fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
+                        m.decl, none),
      purity: m.decl.purity,
      privacy: m.privacy}
 }
@@ -1145,7 +1183,8 @@ fn ty_of_ty_method(self: @crate_ctxt,
                    rp: ast::region_param) -> ty::method {
     {ident: m.ident,
      tps: ty_param_bounds(self, m.tps),
-     fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.decl),
+     fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
+                        m.decl, none),
      // assume public, because this is only invoked on iface methods
      purity: m.decl.purity, privacy: ast::pub}
 }
@@ -1649,7 +1688,8 @@ mod collect {
           ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
             let {bounds, substs} = mk_substs(ccx, tps, rp);
             let def_id = local_def(it.id);
-            let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
+            let t_arg = ty_of_arg(ccx, type_rscope(rp),
+                                  decl.inputs[0], none);
             let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs);
 
             let t_ctor = ty::mk_fn(tcx, {
@@ -1691,7 +1731,8 @@ mod collect {
                           ty_of_fn_decl(ccx,
                                         empty_rscope,
                                         ast::proto_any,
-                                        ctor.node.dec));
+                                        ctor.node.dec,
+                                        none));
             write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
             tcx.tcache.insert(local_def(ctor.node.id),
                               {bounds: tpt.bounds,
@@ -1961,7 +2002,7 @@ mod writeback {
         resolve_type_vars_for_node(wbcx, e.span, e.id);
         alt e.node {
           ast::expr_fn(_, decl, _, _) |
-          ast::expr_fn_block(decl, _) {
+          ast::expr_fn_block(decl, _, _) {
             vec::iter(decl.inputs) {|input|
                 let r_ty = resolve_type_vars_for_node(wbcx, e.span, input.id);
 
@@ -2902,35 +2943,6 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region {
     }
 }
 
-fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
-                              expr: @ast::expr,
-                              proto: ast::proto,
-                              decl: ast::fn_decl,
-                              body: ast::blk,
-                              is_loop_body: bool,
-                              unifier: fn()) {
-    let tcx = fcx.ccx.tcx;
-    let fty = ty::mk_fn(tcx, ty_of_fn_decl(fcx, fcx, proto, decl));
-
-    #debug("check_expr_fn_with_unifier %s fty=%s",
-           expr_to_str(expr), fcx.ty_to_str(fty));
-
-    fcx.write_ty(expr.id, fty);
-
-    // Unify the type of the function with the expected type before we
-    // typecheck the body so that we have more information about the
-    // argument types in the body. This is needed to make binops and
-    // record projection work on type inferred arguments.
-    unifier();
-
-    let ret_ty = ty::ty_fn_ret(fty);
-    let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
-
-    check_fn(fcx.ccx, proto, decl, body, expr.id,
-             ret_ty, arg_tys, is_loop_body, some(fcx),
-             fcx.self_ty);
-}
-
 fn check_expr_with_unifier(fcx: @fn_ctxt,
                            expr: @ast::expr,
                            expected: option<ty::t>,
@@ -2999,7 +3011,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
                 alt a_opt {
                   some(a) {
                     let is_block = alt a.node {
-                      ast::expr_fn_block(_, _) { true }
+                      ast::expr_fn_block(*) { true }
                       _ { false }
                     };
                     if is_block == check_blocks {
@@ -3227,6 +3239,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
           }
         }
     }
+
+    // Resolves `expected` by a single level if it is a variable and passes it
+    // through the `unpack` function.  It there is no expected type or
+    // resolution is not possible (e.g., no constraints yet present), just
+    // returns `none`.
     fn unpack_expected<O: copy>(fcx: @fn_ctxt, expected: option<ty::t>,
                                 unpack: fn(ty::sty) -> option<O>)
         -> option<O> {
@@ -3241,6 +3258,42 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         }
     }
 
+    fn check_expr_fn(fcx: @fn_ctxt,
+                     expr: @ast::expr,
+                     proto: ast::proto,
+                     decl: ast::fn_decl,
+                     body: ast::blk,
+                     is_loop_body: bool,
+                     expected: option<ty::t>) {
+        let tcx = fcx.ccx.tcx;
+
+        let expected_tys = unpack_expected(fcx, expected) { |sty|
+            alt sty {
+              ty::ty_fn(fn_ty) {some({inputs:fn_ty.inputs,
+                                      output:fn_ty.output})}
+              _ {none}
+            }
+        };
+
+        // construct the function type
+        let fty = ty::mk_fn(tcx,
+                            ty_of_fn_decl(fcx, fcx, proto, decl,
+                                          expected_tys));
+
+        #debug("check_expr_fn_with_unifier %s fty=%s",
+               expr_to_str(expr), fcx.ty_to_str(fty));
+
+        fcx.write_ty(expr.id, fty);
+
+        let ret_ty = ty::ty_fn_ret(fty);
+        let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
+
+        check_fn(fcx.ccx, proto, decl, body, expr.id,
+                 ret_ty, arg_tys, is_loop_body, some(fcx),
+                 fcx.self_ty);
+    }
+
+
     let tcx = fcx.ccx.tcx;
     let id = expr.id;
     let mut bot = false;
@@ -3510,20 +3563,25 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
         fcx.write_ty(id, result_ty);
       }
-      ast::expr_fn(proto, decl, body, captures) {
-        check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
-                                   false, unifier);
-        capture::check_capture_clause(tcx, expr.id, proto, *captures);
+      ast::expr_fn(proto, decl, body, cap_clause) {
+        check_expr_fn(fcx, expr, proto, decl, body, false, expected);
+        capture::check_capture_clause(tcx, expr.id, proto, cap_clause);
       }
-      ast::expr_fn_block(decl, body) {
+      ast::expr_fn_block(decl, body, cap_clause) {
         // Take the prototype from the expected type, but default to block:
         let proto = unpack_expected(fcx, expected, {|sty|
             alt sty { ty::ty_fn({proto, _}) { some(proto) } _ { none } }
         }).get_default(ast::proto_box);
-        check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
-                                   false, unifier);
+        check_expr_fn(fcx, expr, proto, decl, body, false, expected);
+        capture::check_capture_clause(tcx, expr.id, proto, cap_clause);
       }
       ast::expr_loop_body(b) {
+        // a loop body is the special argument to a `for` loop.  We know that
+        // there will be an expected type in this context because it can only
+        // appear in the context of a call, so we get the expected type of the
+        // parameter. The catch here is that we need to validate two things:
+        // 1. a closure that returns a bool is expected
+        // 2. the cloure that was given returns unit
         let expected_sty = unpack_expected(fcx, expected, {|x|some(x)}).get();
         let (inner_ty, proto) = alt expected_sty {
           ty::ty_fn(fty) {
@@ -3544,10 +3602,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
           }
         };
         alt check b.node {
-          ast::expr_fn_block(decl, body) {
-            check_expr_fn_with_unifier(fcx, b, proto, decl, body, true) {||
-                demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
-            }
+          ast::expr_fn_block(decl, body, cap_clause) {
+            check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
+            demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
+            capture::check_capture_clause(tcx, b.id, proto, cap_clause);
           }
         }
         let block_ty = structurally_resolved_type(
diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs
index 227dc0c8645..80af3229bc4 100644
--- a/src/rustc/util/ppaux.rs
+++ b/src/rustc/util/ppaux.rs
@@ -130,18 +130,9 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
     }
 
     // if there is an id, print that instead of the structural type:
-    alt ty::type_def_id(typ) {
-      some(def_id) {
-        let cs = ast_map::path_to_str(ty::item_path(cx, def_id));
-        ret alt ty::get(typ).struct {
-          ty_enum(_, substs) | ty_res(_, _, substs) | ty_class(_, substs) |
-          ty_iface(_, substs) {
-            parameterized(cx, cs, substs.self_r, substs.tps)
-          }
-          _ { cs }
-        };
-      }
-      none { /* fallthrough */}
+    for ty::type_def_id(typ).each { |def_id|
+        // note that this typedef cannot have type parameters
+        ret ast_map::path_to_str(ty::item_path(cx, def_id));
     }
 
     // pretty print the structural type representation:
diff --git a/src/test/compile-fail/cap-clause-move-upvar.rs b/src/test/compile-fail/cap-clause-move-upvar.rs
index bb0ddcd3cf7..c10fb806af4 100644
--- a/src/test/compile-fail/cap-clause-move-upvar.rs
+++ b/src/test/compile-fail/cap-clause-move-upvar.rs
@@ -1,8 +1,7 @@
-// error-pattern:upvars (like 'x') cannot be moved into a closure
 fn main() {
     let x = 5;
-    let _y = fn~[move x]() -> int {
-        let _z = fn~[move x]() -> int { x };
+    let _y = fn~(move x) -> int {
+        let _z = fn~(move x) -> int { x }; //! ERROR moving out of upvar
         22
     };
 }
diff --git a/src/test/compile-fail/pptypedef.rs b/src/test/compile-fail/pptypedef.rs
new file mode 100644
index 00000000000..941535ef0f1
--- /dev/null
+++ b/src/test/compile-fail/pptypedef.rs
@@ -0,0 +1,8 @@
+type foo = option<int>;
+
+fn bar(_t: foo) {}
+
+fn main() {
+    // we used to print foo<int>:
+    bar(some(3u)); //! ERROR mismatched types: expected `foo`
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/vec-concat-bug.rs b/src/test/compile-fail/vec-concat-bug.rs
index b75623d6233..510bef1cae0 100644
--- a/src/test/compile-fail/vec-concat-bug.rs
+++ b/src/test/compile-fail/vec-concat-bug.rs
@@ -4,7 +4,6 @@ fn concat<T: copy>(v: [const [const T]]) -> [T] {
     // Earlier versions of our type checker accepted this:
     vec::iter(v) {|&&inner: [T]|
         //!^ ERROR values differ in mutability
-        //!^^ ERROR values differ in mutability
         r += inner;
     }
 
diff --git a/src/test/pretty/cap-clause.rs b/src/test/pretty/cap-clause.rs
index e6a78c3d762..b17ea3fa68e 100644
--- a/src/test/pretty/cap-clause.rs
+++ b/src/test/pretty/cap-clause.rs
@@ -4,14 +4,14 @@ fn main() {
     let x = 1;
     let y = 2;
     let z = 3;
-    let l1 = fn@[copy x]() -> int { x + y };
-    let l2 = fn@[copy x; move y]() -> int { x + y };
-    let l3 = fn@[move z]() -> int { z };
+    let l1 = fn@(w: int, copy x) -> int { w + x + y };
+    let l2 = fn@(w: int, copy x, move y) -> int { w + x + y };
+    let l3 = fn@(w: int, move z) -> int { w + z };
 
     let x = 1;
     let y = 2;
     let z = 3;
-    let s1 = fn~[copy x]() -> int { x + y };
-    let s2 = fn~[copy x; move y]() -> int { x + y };
-    let s3 = fn~[move z]() -> int { z };
+    let s1 = fn~(copy x) -> int { x + y };
+    let s2 = fn~(copy x, move y) -> int { x + y };
+    let s3 = fn~(move z) -> int { z };
 }
diff --git a/src/test/run-pass/cap-clause-move.rs b/src/test/run-pass/cap-clause-move.rs
index 3050d534ac8..c2e0f4b58dd 100644
--- a/src/test/run-pass/cap-clause-move.rs
+++ b/src/test/run-pass/cap-clause-move.rs
@@ -1,16 +1,29 @@
 fn main() {
     let x = ~1;
     let y = ptr::addr_of(*x) as uint;
-
-    let lam_copy = fn@[copy x]() -> uint { ptr::addr_of(*x) as uint };
-    let lam_move = fn@[move x]() -> uint { ptr::addr_of(*x) as uint };
+    let lam_copy = fn@(copy x) -> uint { ptr::addr_of(*x) as uint };
+    let lam_move = fn@(move x) -> uint { ptr::addr_of(*x) as uint };
     assert lam_copy() != y;
     assert lam_move() == y;
 
     let x = ~2;
     let y = ptr::addr_of(*x) as uint;
-    let snd_copy = fn~[copy x]() -> uint { ptr::addr_of(*x) as uint };
-    let snd_move = fn~[move x]() -> uint { ptr::addr_of(*x) as uint };
+    let lam_copy: fn@() -> uint = { |copy x| ptr::addr_of(*x) as uint };
+    let lam_move: fn@() -> uint = { |move x| ptr::addr_of(*x) as uint };
+    assert lam_copy() != y;
+    assert lam_move() == y;
+
+    let x = ~3;
+    let y = ptr::addr_of(*x) as uint;
+    let snd_copy = fn~(copy x) -> uint { ptr::addr_of(*x) as uint };
+    let snd_move = fn~(move x) -> uint { ptr::addr_of(*x) as uint };
     assert snd_copy() != y;
     assert snd_move() == y;
+
+    let x = ~4;
+    let y = ptr::addr_of(*x) as uint;
+    let lam_copy: fn~() -> uint = { |copy x| ptr::addr_of(*x) as uint };
+    let lam_move: fn~() -> uint = { |move x| ptr::addr_of(*x) as uint };
+    assert lam_copy() != y;
+    assert lam_move() == y;
 }
diff --git a/src/test/run-pass/cap-clause-not-used.rs b/src/test/run-pass/cap-clause-not-used.rs
index 742214ee2a1..08fca191abd 100644
--- a/src/test/run-pass/cap-clause-not-used.rs
+++ b/src/test/run-pass/cap-clause-not-used.rs
@@ -1,5 +1,5 @@
 // error-pattern: warning: Captured variable 'y' not used in closure
 fn main() {
     let x = 5;
-    let _y = fn~[copy x]() { };
+    let _y = fn~(copy x) { };
 }
diff --git a/src/test/run-pass/last-use-in-cap-clause.rs b/src/test/run-pass/last-use-in-cap-clause.rs
index 6ac7404c3ce..fc5425f24e9 100644
--- a/src/test/run-pass/last-use-in-cap-clause.rs
+++ b/src/test/run-pass/last-use-in-cap-clause.rs
@@ -3,7 +3,7 @@
 fn foo() -> fn@() -> int {
     let k = ~22;
     let _u = {a: k};
-    ret fn@[move k]() -> int { 22 };
+    ret fn@(move k) -> int { 22 };
 }
 
 fn main() {