about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/extfmt.rs16
-rw-r--r--src/libcore/send_map.rs4
-rw-r--r--src/librustc/lib/llvm.rs10
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs15
-rw-r--r--src/librustc/middle/check_alt.rs27
-rw-r--r--src/librustc/middle/liveness.rs26
-rw-r--r--src/librustc/middle/resolve.rs50
-rw-r--r--src/librustc/middle/trans/alt.rs78
-rw-r--r--src/librustc/middle/trans/base.rs20
-rw-r--r--src/librustc/middle/trans/common.rs44
-rw-r--r--src/librustc/middle/trans/debuginfo.rs40
-rw-r--r--src/librustc/middle/trans/deriving.rs4
-rw-r--r--src/librustc/middle/ty.rs15
-rw-r--r--src/librustc/middle/typeck/check.rs42
-rw-r--r--src/librustc/middle/typeck/check/alt.rs3
-rw-r--r--src/librustc/middle/typeck/check/writeback.rs5
-rw-r--r--src/librustc/middle/typeck/coherence.rs12
-rw-r--r--src/libsyntax/ast.rs6
-rw-r--r--src/libsyntax/ast_util.rs6
-rw-r--r--src/libsyntax/ext/auto_serialize.rs22
-rw-r--r--src/libsyntax/ext/base.rs17
-rw-r--r--src/libsyntax/ext/pipes/ast_builder.rs9
-rw-r--r--src/libsyntax/fold.rs6
-rw-r--r--src/libsyntax/parse/parser.rs23
-rw-r--r--src/libsyntax/print/pprust.rs19
-rw-r--r--src/libsyntax/visit.rs5
-rw-r--r--src/test/compile-fail/macro-2.rs2
-rw-r--r--src/test/compile-fail/nontrivial-fn-arg-pattern-in-pure-fn.rs6
-rw-r--r--src/test/compile-fail/refutable-pattern-in-fn-arg.rs5
-rw-r--r--src/test/compile-fail/regions-glb-free-free.rs2
-rw-r--r--src/test/run-pass/pattern-in-closure.rs12
31 files changed, 392 insertions, 159 deletions
diff --git a/src/libcore/extfmt.rs b/src/libcore/extfmt.rs
index 2b2180e7efc..c7139b16934 100644
--- a/src/libcore/extfmt.rs
+++ b/src/libcore/extfmt.rs
@@ -85,7 +85,7 @@ pub mod ct {
     pub enum Piece { PieceString(~str), PieceConv(Conv), }
     pub type ErrorFn = fn@(&str) -> ! ;
 
-    pub fn parse_fmt_string(s: &str, error: ErrorFn) -> ~[Piece] {
+    pub fn parse_fmt_string(s: &str, err: ErrorFn) -> ~[Piece] {
         let mut pieces: ~[Piece] = ~[];
         let lim = str::len(s);
         let mut buf = ~"";
@@ -103,7 +103,7 @@ pub mod ct {
             if curr == ~"%" {
                 i += 1;
                 if i >= lim {
-                    error(~"unterminated conversion at end of string");
+                    err(~"unterminated conversion at end of string");
                 }
                 let curr2 = str::slice(s, i, i+1);
                 if curr2 == ~"%" {
@@ -111,7 +111,7 @@ pub mod ct {
                     i += 1;
                 } else {
                     buf = flush_buf(move buf, &mut pieces);
-                    let rs = parse_conversion(s, i, lim, error);
+                    let rs = parse_conversion(s, i, lim, err);
                     pieces.push(copy rs.piece);
                     i = rs.next;
                 }
@@ -143,13 +143,13 @@ pub mod ct {
         }
     }
     pub fn parse_conversion(s: &str, i: uint, lim: uint,
-                            error: ErrorFn) ->
+                            err: ErrorFn) ->
        {piece: Piece, next: uint} {
         let parm = parse_parameter(s, i, lim);
         let flags = parse_flags(s, parm.next, lim);
         let width = parse_count(s, flags.next, lim);
         let prec = parse_precision(s, width.next, lim);
-        let ty = parse_type(s, prec.next, lim, error);
+        let ty = parse_type(s, prec.next, lim, err);
         return {piece:
                  PieceConv({param: parm.param,
                              flags: copy flags.flags,
@@ -239,9 +239,9 @@ pub mod ct {
                 }
             } else { {count: CountImplied, next: i} };
     }
-    pub fn parse_type(s: &str, i: uint, lim: uint, error: ErrorFn) ->
+    pub fn parse_type(s: &str, i: uint, lim: uint, err: ErrorFn) ->
        {ty: Ty, next: uint} {
-        if i >= lim { error(~"missing type in conversion"); }
+        if i >= lim { err(~"missing type in conversion"); }
         let tstr = str::slice(s, i, i+1u);
         // FIXME (#2249): Do we really want two signed types here?
         // How important is it to be printf compatible?
@@ -268,7 +268,7 @@ pub mod ct {
                 TyFloat
             } else if tstr == ~"?" {
                 TyPoly
-            } else { error(~"unknown type in conversion: " + tstr) };
+            } else { err(~"unknown type in conversion: " + tstr) };
         return {ty: t, next: i + 1u};
     }
 }
diff --git a/src/libcore/send_map.rs b/src/libcore/send_map.rs
index 58b35b82a31..11de9ab1a7e 100644
--- a/src/libcore/send_map.rs
+++ b/src/libcore/send_map.rs
@@ -35,7 +35,7 @@ pub trait SendMap<K:Eq Hash, V: Copy> {
 
 /// Open addressing with linear probing.
 pub mod linear {
-    const initial_capacity: uint = 32u; // 2^5
+    const INITIAL_CAPACITY: uint = 32u; // 2^5
 
     struct Bucket<K:Eq Hash,V> {
         hash: uint,
@@ -62,7 +62,7 @@ pub mod linear {
     }
 
     pub fn LinearMap<K:Eq Hash,V>() -> LinearMap<K,V> {
-        linear_map_with_capacity(32)
+        linear_map_with_capacity(INITIAL_CAPACITY)
     }
 
     pub fn linear_map_with_capacity<K:Eq Hash,V>(
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs
index f1397006b16..e6fa3f2f953 100644
--- a/src/librustc/lib/llvm.rs
+++ b/src/librustc/lib/llvm.rs
@@ -959,15 +959,15 @@ extern mod llvm {
     /** Opens an object file. */
     fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef;
     /** Closes an object file. */
-    fn LLVMDisposeObjectFile(ObjectFile: ObjectFileRef);
+    fn LLVMDisposeObjectFile(ObjFile: ObjectFileRef);
 
     /** Enumerates the sections in an object file. */
-    fn LLVMGetSections(ObjectFile: ObjectFileRef) -> SectionIteratorRef;
+    fn LLVMGetSections(ObjFile: ObjectFileRef) -> SectionIteratorRef;
     /** Destroys a section iterator. */
     fn LLVMDisposeSectionIterator(SI: SectionIteratorRef);
     /** Returns true if the section iterator is at the end of the section
         list: */
-    fn LLVMIsSectionIteratorAtEnd(ObjectFile: ObjectFileRef,
+    fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef,
                                   SI: SectionIteratorRef) -> Bool;
     /** Moves the section iterator to point to the next section. */
     fn LLVMMoveToNextSection(SI: SectionIteratorRef);
@@ -1228,9 +1228,9 @@ struct object_file_res {
     drop { llvm::LLVMDisposeObjectFile(self.ObjectFile); }
 }
 
-fn object_file_res(ObjectFile: ObjectFileRef) -> object_file_res{
+fn object_file_res(ObjFile: ObjectFileRef) -> object_file_res {
     object_file_res {
-        ObjectFile: ObjectFile
+        ObjectFile: ObjFile
     }
 }
 
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index d63f52a4a58..98667a8e041 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -570,7 +570,20 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
                 visit::fk_anon(*) | visit::fk_fn_block(*) |
                 visit::fk_method(*) | visit::fk_item_fn(*) |
                 visit::fk_dtor(*) => {
-                    self.fn_args = @decl.inputs.map(|i| i.id );
+                    let mut fn_args = ~[];
+                    for decl.inputs.each |input| {
+                        // For the purposes of purity, only consider function-
+                        // typed bindings in trivial patterns to be function
+                        // arguments. For example, do not allow `f` and `g` in
+                        // (f, g): (&fn(), &fn()) to be called.
+                        match input.pat.node {
+                            ast::pat_ident(_, _, None) => {
+                                fn_args.push(input.pat.id);
+                            }
+                            _ => {} // Ignore this argument.
+                        }
+                    }
+                    self.fn_args = @move fn_args;
                 }
             }
 
diff --git a/src/librustc/middle/check_alt.rs b/src/librustc/middle/check_alt.rs
index 5b35ed98a83..1c2899fe0be 100644
--- a/src/librustc/middle/check_alt.rs
+++ b/src/librustc/middle/check_alt.rs
@@ -15,6 +15,8 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
     visit::visit_crate(*crate, (), visit::mk_vt(@{
         visit_expr: |a,b,c| check_expr(tcx, a, b, c),
         visit_local: |a,b,c| check_local(tcx, a, b, c),
+        visit_fn: |kind, decl, body, sp, id, e, v|
+            check_fn(tcx, kind, decl, body, sp, id, e, v),
         .. *visit::default_visitor::<()>()
     }));
     tcx.sess.abort_if_errors();
@@ -372,8 +374,8 @@ fn specialize(tcx: ty::ctxt, r: ~[@pat], ctor_id: ctor, arity: uint,
             ty::ty_rec(flds) => flds,
             _ => fail ~"bad type for pat_rec"
         };
-        let args = vec::map(ty_flds, |ty_f| {
-            match vec::find(flds, |f| f.ident == ty_f.ident ) {
+        let args = vec::map(ty_flds, |ty_fld| {
+            match vec::find(flds, |f| f.ident == ty_fld.ident ) {
               Some(f) => f.pat,
               _ => wild()
             }
@@ -386,8 +388,8 @@ fn specialize(tcx: ty::ctxt, r: ~[@pat], ctor_id: ctor, arity: uint,
             def_variant(_, variant_id) => {
                 if variant(variant_id) == ctor_id {
                     // XXX: Is this right? --pcw
-                    let args = flds.map(|ty_f| {
-                        match vec::find(flds, |f| f.ident == ty_f.ident) {
+                    let args = flds.map(|ty_field| {
+                        match vec::find(flds, |f| f.ident == ty_field.ident) {
                             Some(f) => f.pat,
                             _ => wild()
                         }
@@ -465,6 +467,23 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) {
     }
 }
 
+fn check_fn(tcx: ty::ctxt,
+            kind: visit::fn_kind,
+            decl: fn_decl,
+            body: blk,
+            sp: span,
+            id: node_id,
+            &&s: (),
+            v: visit::vt<()>) {
+    visit::visit_fn(kind, decl, body, sp, id, s, v);
+    for decl.inputs.each |input| {
+        if is_refutable(tcx, input.pat) {
+            tcx.sess.span_err(input.pat.span,
+                              ~"refutable pattern in function argument");
+        }
+    }
+}
+
 fn is_refutable(tcx: ty::ctxt, pat: &pat) -> bool {
     match tcx.def_map.find(pat.id) {
       Some(def_variant(enum_id, _)) => {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index baf083b191b..ec7c2ffc6f1 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -414,9 +414,13 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
     debug!("creating fn_maps: %x", ptr::addr_of(&(*fn_maps)) as uint);
 
     for decl.inputs.each |arg| {
-        debug!("adding argument %d", arg.id);
         let mode = ty::resolved_mode(self.tcx, arg.mode);
-        (*fn_maps).add_variable(Arg(arg.id, arg.ident, mode));
+        do pat_util::pat_bindings(self.tcx.def_map, arg.pat)
+                |_bm, arg_id, _x, path| {
+            debug!("adding argument %d", arg_id);
+            let ident = ast_util::path_to_ident(path);
+            (*fn_maps).add_variable(Arg(arg_id, ident, mode));
+        }
     };
 
     // gather up the various local variables, significant expressions,
@@ -447,7 +451,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
     });
     check_vt.visit_block(body, lsets, check_vt);
     lsets.check_ret(id, sp, fk, entry_ln);
-    lsets.warn_about_unused_args(sp, decl, entry_ln);
+    lsets.warn_about_unused_args(decl, entry_ln);
 }
 
 fn visit_local(local: @local, &&self: @IrMaps, vt: vt<@IrMaps>) {
@@ -937,8 +941,11 @@ impl Liveness {
                 // the end.  This will prevent us from moving out of
                 // such variables but also prevent us from registering
                 // last uses and so forth.
-                let var = self.variable(arg.id, blk.span);
-                self.acc(self.s.exit_ln, var, ACC_READ);
+                do pat_util::pat_bindings(self.tcx.def_map, arg.pat)
+                        |_bm, arg_id, _sp, _path| {
+                    let var = self.variable(arg_id, blk.span);
+                    self.acc(self.s.exit_ln, var, ACC_READ);
+                }
               }
               by_move | by_copy => {
                 // These are owned modes.  If we don't use the
@@ -1791,10 +1798,13 @@ impl @Liveness {
         if name[0] == ('_' as u8) {None} else {Some(name)}
     }
 
-    fn warn_about_unused_args(sp: span, decl: fn_decl, entry_ln: LiveNode) {
+    fn warn_about_unused_args(decl: fn_decl, entry_ln: LiveNode) {
         for decl.inputs.each |arg| {
-            let var = self.variable(arg.id, arg.ty.span);
-            self.warn_about_unused(sp, entry_ln, var);
+            do pat_util::pat_bindings(self.tcx.def_map, arg.pat)
+                    |_bm, p_id, sp, _n| {
+                let var = self.variable(p_id, sp);
+                self.warn_about_unused(sp, entry_ln, var);
+            }
         }
     }
 
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index b915086c551..66b75d5f1cd 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -28,8 +28,8 @@ use syntax::ast::{foreign_item, foreign_item_const, foreign_item_fn, ge};
 use syntax::ast::{gt, ident, impure_fn, inherited, item, item_class};
 use syntax::ast::{item_const, item_enum, item_fn, item_foreign_mod};
 use syntax::ast::{item_impl, item_mac, item_mod, item_trait, item_ty, le};
-use syntax::ast::{local, local_crate, lt, method, module_ns, mul, ne, neg};
-use syntax::ast::{node_id, pat, pat_enum, pat_ident, path, prim_ty};
+use syntax::ast::{local, local_crate, lt, method, mode, module_ns, mul, ne};
+use syntax::ast::{neg, node_id, pat, pat_enum, pat_ident, path, prim_ty};
 use syntax::ast::{pat_box, pat_lit, pat_range, pat_rec, pat_struct};
 use syntax::ast::{pat_tup, pat_uniq, pat_wild, private, provided, public};
 use syntax::ast::{required, rem, self_ty_, shl, shr, stmt_decl};
@@ -103,12 +103,32 @@ struct Export2 {
 
 enum PatternBindingMode {
     RefutableMode,
-    IrrefutableMode
+    LocalIrrefutableMode,
+    ArgumentIrrefutableMode(mode)
 }
 
 impl PatternBindingMode : cmp::Eq {
     pure fn eq(other: &PatternBindingMode) -> bool {
-        (self as uint) == ((*other) as uint)
+        match self {
+            RefutableMode => {
+                match *other {
+                    RefutableMode => true,
+                    _ => false
+                }
+            }
+            LocalIrrefutableMode => {
+                match *other {
+                    LocalIrrefutableMode => true,
+                    _ => false
+                }
+            }
+            ArgumentIrrefutableMode(mode_a) => {
+                match *other {
+                    ArgumentIrrefutableMode(mode_b) => mode_a == mode_b,
+                    _ => false
+                }
+            }
+        }
     }
     pure fn ne(other: &PatternBindingMode) -> bool { !self.eq(other) }
 }
@@ -3770,15 +3790,17 @@ impl Resolver {
                 }
                 Some(declaration) => {
                     for declaration.inputs.each |argument| {
-                        let name = argument.ident;
-                        let def_like = dl_def(def_arg(argument.id,
-                                                      argument.mode));
-                        (*function_value_rib).bindings.insert(name, def_like);
+                        let binding_mode =
+                            ArgumentIrrefutableMode(argument.mode);
+                        self.resolve_pattern(argument.pat,
+                                             binding_mode,
+                                             Immutable,
+                                             None,
+                                             visitor);
 
                         self.resolve_type(argument.ty, visitor);
 
-                        debug!("(resolving function) recorded argument `%s`",
-                               self.session.str_of(name));
+                        debug!("(resolving function) recorded argument");
                     }
 
                     self.resolve_type(declaration.output, visitor);
@@ -4013,7 +4035,7 @@ impl Resolver {
         }
 
         // Resolve the pattern.
-        self.resolve_pattern(local.node.pat, IrrefutableMode, mutability,
+        self.resolve_pattern(local.node.pat, LocalIrrefutableMode, mutability,
                              None, visitor);
     }
 
@@ -4249,10 +4271,14 @@ impl Resolver {
 
                                     def_binding(pattern.id, binding_mode)
                                 }
-                                IrrefutableMode => {
+                                LocalIrrefutableMode => {
                                     // But for locals, we use `def_local`.
                                     def_local(pattern.id, is_mutable)
                                 }
+                                ArgumentIrrefutableMode(argument_mode) => {
+                                    // And for function arguments, `def_arg`.
+                                    def_arg(pattern.id, argument_mode)
+                                }
                             };
 
                             // Record the definition so that later passes
diff --git a/src/librustc/middle/trans/alt.rs b/src/librustc/middle/trans/alt.rs
index 0908eae34dc..d3a69a88947 100644
--- a/src/librustc/middle/trans/alt.rs
+++ b/src/librustc/middle/trans/alt.rs
@@ -1410,18 +1410,29 @@ fn trans_alt_inner(scope_cx: block,
     return controlflow::join_blocks(scope_cx, dvec::unwrap(move arm_cxs));
 
     fn mk_fail(bcx: block, sp: span, msg: ~str,
-               done: @mut Option<BasicBlockRef>) -> BasicBlockRef {
-        match *done { Some(bb) => return bb, _ => () }
+               finished: @mut Option<BasicBlockRef>) -> BasicBlockRef {
+        match *finished { Some(bb) => return bb, _ => () }
         let fail_cx = sub_block(bcx, ~"case_fallthrough");
         controlflow::trans_fail(fail_cx, Some(sp), msg);
-        *done = Some(fail_cx.llbb);
+        *finished = Some(fail_cx.llbb);
         return fail_cx.llbb;
     }
 }
 
+enum IrrefutablePatternBindingMode {
+    // Stores the association between node ID and LLVM value in `lllocals`.
+    BindLocal,
+    // Stores the association between node ID and LLVM value in `llargs`.
+    BindArgument
+}
+
 // Not alt-related, but similar to the pattern-munging code above
-fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
-                        make_copy: bool) -> block {
+fn bind_irrefutable_pat(bcx: block,
+                        pat: @ast::pat,
+                        val: ValueRef,
+                        make_copy: bool,
+                        binding_mode: IrrefutablePatternBindingMode)
+                     -> block {
     let _icx = bcx.insn_ctxt("alt::bind_irrefutable_pat");
     let ccx = bcx.fcx.ccx;
     let mut bcx = bcx;
@@ -1439,14 +1450,31 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
                                    mode: ByRef, source: FromRvalue};
                 let scratch = scratch_datum(bcx, binding_ty, false);
                 datum.copy_to_datum(bcx, INIT, scratch);
-                bcx.fcx.lllocals.insert(pat.id, local_mem(scratch.val));
+                match binding_mode {
+                    BindLocal => {
+                        bcx.fcx.lllocals.insert(pat.id,
+                                                local_mem(scratch.val));
+                    }
+                    BindArgument => {
+                        bcx.fcx.llargs.insert(pat.id,
+                                              local_mem(scratch.val));
+                    }
+                }
                 add_clean(bcx, scratch.val, binding_ty);
             } else {
-                bcx.fcx.lllocals.insert(pat.id, local_mem(val));
+                match binding_mode {
+                    BindLocal => {
+                        bcx.fcx.lllocals.insert(pat.id, local_mem(val));
+                    }
+                    BindArgument => {
+                        bcx.fcx.llargs.insert(pat.id, local_mem(val));
+                    }
+                }
             }
 
             for inner.each |inner_pat| {
-                bcx = bind_irrefutable_pat(bcx, *inner_pat, val, true);
+                bcx = bind_irrefutable_pat(
+                    bcx, *inner_pat, val, true, binding_mode);
             }
         }
         ast::pat_enum(_, sub_pats) => {
@@ -1460,7 +1488,8 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
                             bcx = bind_irrefutable_pat(bcx,
                                                        sub_pat[i],
                                                        *argval,
-                                                       make_copy);
+                                                       make_copy,
+                                                       binding_mode);
                         }
                     }
                 }
@@ -1473,8 +1502,11 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
                             // This is the tuple variant case.
                             for vec::eachi(elems) |i, elem| {
                                 let fldptr = GEPi(bcx, val, struct_field(i));
-                                bcx = bind_irrefutable_pat(bcx, *elem, fldptr,
-                                                           make_copy);
+                                bcx = bind_irrefutable_pat(bcx,
+                                                           *elem,
+                                                           fldptr,
+                                                           make_copy,
+                                                           binding_mode);
                             }
                         }
                     }
@@ -1491,24 +1523,40 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
                 for vec::each(fields) |f| {
                     let ix = ty::field_idx_strict(tcx, f.ident, field_tys);
                     let fldptr = GEPi(bcx, val, struct_field(ix));
-                    bcx = bind_irrefutable_pat(bcx, f.pat, fldptr, make_copy);
+                    bcx = bind_irrefutable_pat(bcx,
+                                               f.pat,
+                                               fldptr,
+                                               make_copy,
+                                               binding_mode);
                 }
             }
         }
         ast::pat_tup(elems) => {
             for vec::eachi(elems) |i, elem| {
                 let fldptr = GEPi(bcx, val, [0u, i]);
-                bcx = bind_irrefutable_pat(bcx, *elem, fldptr, make_copy);
+                bcx = bind_irrefutable_pat(bcx,
+                                           *elem,
+                                           fldptr,
+                                           make_copy,
+                                           binding_mode);
             }
         }
         ast::pat_box(inner) | ast::pat_uniq(inner) => {
             let llbox = Load(bcx, val);
             let unboxed = GEPi(bcx, llbox, [0u, abi::box_field_body]);
-            bcx = bind_irrefutable_pat(bcx, inner, unboxed, true);
+            bcx = bind_irrefutable_pat(bcx,
+                                       inner,
+                                       unboxed,
+                                       true,
+                                       binding_mode);
         }
         ast::pat_region(inner) => {
             let loaded_val = Load(bcx, val);
-            bcx = bind_irrefutable_pat(bcx, inner, loaded_val, true);
+            bcx = bind_irrefutable_pat(bcx,
+                                       inner,
+                                       loaded_val,
+                                       true,
+                                       binding_mode);
         }
         ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) => ()
     }
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index a2d74dc92df..7a163afafcc 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -991,7 +991,11 @@ fn init_local(bcx: block, local: @ast::local) -> block {
            bcx.to_str());
     add_clean(bcx, llptr, ty);
 
-    return alt::bind_irrefutable_pat(bcx, local.node.pat, llptr, false);
+    return alt::bind_irrefutable_pat(bcx,
+                                     local.node.pat,
+                                     llptr,
+                                     false,
+                                     alt::BindLocal);
 }
 
 fn trans_stmt(cx: block, s: ast::stmt) -> block {
@@ -1529,6 +1533,12 @@ fn copy_args_to_allocas(fcx: fn_ctxt,
             }
         }
 
+        bcx = alt::bind_irrefutable_pat(bcx,
+                                        args[arg_n].pat,
+                                        llarg,
+                                        false,
+                                        alt::BindArgument);
+
         fcx.llargs.insert(arg_id, local_mem(llarg));
 
         if fcx.ccx.sess.opts.extra_debuginfo {
@@ -1658,7 +1668,9 @@ fn trans_enum_variant(ccx: @crate_ctxt,
     let fn_args = vec::map(args, |varg|
         {mode: ast::expl(ast::by_copy),
          ty: varg.ty,
-         ident: special_idents::arg,
+         pat: ast_util::ident_to_pat(ccx.tcx.sess.next_node_id(),
+                                     ast_util::dummy_sp(),
+                                     special_idents::arg),
          id: varg.id});
     let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, variant.node.id, None,
                                param_substs, None);
@@ -1714,7 +1726,9 @@ fn trans_tuple_struct(ccx: @crate_ctxt,
         {
             mode: ast::expl(ast::by_copy),
             ty: field.node.ty,
-            ident: special_idents::arg,
+            pat: ast_util::ident_to_pat(ccx.tcx.sess.next_node_id(),
+                                        ast_util::dummy_sp(),
+                                        special_idents::arg),
             id: field.node.id
         }
     };
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 36d6bb9258b..8badf672e81 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -320,9 +320,9 @@ impl cleantype : cmp::Eq {
 type cleanup_path = {target: Option<BasicBlockRef>,
                      dest: BasicBlockRef};
 
-fn scope_clean_changed(info: scope_info) {
-    if info.cleanup_paths.len() > 0u { info.cleanup_paths = ~[]; }
-    info.landing_pad = None;
+fn scope_clean_changed(scope_info: scope_info) {
+    if scope_info.cleanup_paths.len() > 0u { scope_info.cleanup_paths = ~[]; }
+    scope_info.landing_pad = None;
 }
 
 fn cleanup_type(cx: ty::ctxt, ty: ty::t) -> cleantype {
@@ -361,11 +361,11 @@ fn add_clean(bcx: block, val: ValueRef, t: ty::t) {
            ty_to_str(bcx.ccx().tcx, t));
     let {root, rooted} = root_for_cleanup(bcx, val, t);
     let cleanup_type = cleanup_type(bcx.tcx(), t);
-    do in_scope_cx(bcx) |info| {
-        info.cleanups.push(
+    do in_scope_cx(bcx) |scope_info| {
+        scope_info.cleanups.push(
             clean(|a| glue::drop_ty_root(a, root, rooted, t),
                   cleanup_type));
-        scope_clean_changed(info);
+        scope_clean_changed(scope_info);
     }
 }
 
@@ -375,11 +375,11 @@ fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) {
            cx.to_str(), val_str(cx.ccx().tn, val),
            ty_to_str(cx.ccx().tcx, ty));
     let cleanup_type = cleanup_type(cx.tcx(), ty);
-    do in_scope_cx(cx) |info| {
-        info.cleanups.push(
+    do in_scope_cx(cx) |scope_info| {
+        scope_info.cleanups.push(
             clean_temp(val, |a| glue::drop_ty_immediate(a, val, ty),
                        cleanup_type));
-        scope_clean_changed(info);
+        scope_clean_changed(scope_info);
     }
 }
 fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) {
@@ -389,11 +389,11 @@ fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) {
            ty_to_str(bcx.ccx().tcx, t));
     let {root, rooted} = root_for_cleanup(bcx, val, t);
     let cleanup_type = cleanup_type(bcx.tcx(), t);
-    do in_scope_cx(bcx) |info| {
-        info.cleanups.push(
+    do in_scope_cx(bcx) |scope_info| {
+        scope_info.cleanups.push(
             clean_temp(val, |a| glue::drop_ty_root(a, root, rooted, t),
                        cleanup_type));
-        scope_clean_changed(info);
+        scope_clean_changed(scope_info);
     }
 }
 fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) {
@@ -401,10 +401,10 @@ fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) {
       heap_shared => |a| glue::trans_free(a, ptr),
       heap_exchange => |a| glue::trans_unique_free(a, ptr)
     };
-    do in_scope_cx(cx) |info| {
-        info.cleanups.push(clean_temp(ptr, free_fn,
+    do in_scope_cx(cx) |scope_info| {
+        scope_info.cleanups.push(clean_temp(ptr, free_fn,
                                       normal_exit_and_unwind));
-        scope_clean_changed(info);
+        scope_clean_changed(scope_info);
     }
 }
 
@@ -413,20 +413,20 @@ fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) {
 // this will be more involved. For now, we simply zero out the local, and the
 // drop glue checks whether it is zero.
 fn revoke_clean(cx: block, val: ValueRef) {
-    do in_scope_cx(cx) |info| {
+    do in_scope_cx(cx) |scope_info| {
         let cleanup_pos = vec::position(
-            info.cleanups,
+            scope_info.cleanups,
             |cu| match *cu {
                 clean_temp(v, _, _) if v == val => true,
                 _ => false
             });
         for cleanup_pos.each |i| {
-            info.cleanups =
-                vec::append(vec::slice(info.cleanups, 0u, *i),
-                            vec::view(info.cleanups,
+            scope_info.cleanups =
+                vec::append(vec::slice(scope_info.cleanups, 0u, *i),
+                            vec::view(scope_info.cleanups,
                                       *i + 1u,
-                                      info.cleanups.len()));
-            scope_clean_changed(info);
+                                      scope_info.cleanups.len()));
+            scope_clean_changed(scope_info);
         }
     }
 }
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 2db0dd59cf9..fd18aaaf58e 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -664,13 +664,13 @@ fn create_local_var(bcx: block, local: @ast::local)
 }
 
 fn create_arg(bcx: block, arg: ast::arg, sp: span)
-    -> @metadata<argument_md> unsafe {
+    -> Option<@metadata<argument_md>> unsafe {
     let fcx = bcx.fcx, cx = fcx.ccx;
     let cache = get_cache(cx);
     let tg = ArgVariableTag;
     match cached_metadata::<@metadata<argument_md>>(
         cache, ArgVariableTag, |md| md.data.id == arg.id) {
-      option::Some(md) => return md,
+      option::Some(md) => return Some(md),
       option::None => ()
     }
 
@@ -680,18 +680,32 @@ fn create_arg(bcx: block, arg: ast::arg, sp: span)
     let tymd = create_ty(cx, ty, arg.ty);
     let filemd = create_file(cx, loc.file.name);
     let context = create_function(bcx.fcx);
-    let mdnode = create_var(tg, context.node, cx.sess.str_of(arg.ident),
-                            filemd.node, loc.line as int, tymd.node);
-    let mdval = @{node: mdnode, data: {id: arg.id}};
-    update_cache(cache, tg, argument_metadata(mdval));
 
-    let llptr = match fcx.llargs.get(arg.id) {
-      local_mem(v) | local_imm(v) => v,
-    };
-    let declargs = ~[llmdnode(~[llptr]), mdnode];
-    trans::build::Call(bcx, cx.intrinsics.get(~"llvm.dbg.declare"),
-                       declargs);
-    return mdval;
+    match arg.pat.node {
+        ast::pat_ident(_, path, _) => {
+            // XXX: This is wrong; it should work for multiple bindings.
+            let mdnode = create_var(tg,
+                                    context.node,
+                                    cx.sess.str_of(path.idents.last()),
+                                    filemd.node,
+                                    loc.line as int,
+                                    tymd.node);
+
+            let mdval = @{node: mdnode, data: {id: arg.id}};
+            update_cache(cache, tg, argument_metadata(mdval));
+
+            let llptr = match fcx.llargs.get(arg.id) {
+              local_mem(v) | local_imm(v) => v,
+            };
+            let declargs = ~[llmdnode(~[llptr]), mdnode];
+            trans::build::Call(bcx, cx.intrinsics.get(~"llvm.dbg.declare"),
+                               declargs);
+            return Some(mdval);
+        }
+        _ => {
+            return None;
+        }
+    }
 }
 
 fn update_source_pos(cx: block, s: span) {
diff --git a/src/librustc/middle/trans/deriving.rs b/src/librustc/middle/trans/deriving.rs
index bc398bf753d..e2749db74aa 100644
--- a/src/librustc/middle/trans/deriving.rs
+++ b/src/librustc/middle/trans/deriving.rs
@@ -261,9 +261,9 @@ fn call_substructure_method(bcx: block,
                                                         vtable_result);
     let llfn = fn_data.llfn;
 
-    let cb: &fn(block) -> Callee = |block| {
+    let cb: &fn(block) -> Callee = |bloc| {
         Callee {
-            bcx: block,
+            bcx: bloc,
             data: Method(MethodData {
                 llfn: llfn,
                 llself: llselfval,
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 5e1bccb6c9d..52f05eb44de 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -2532,18 +2532,19 @@ fn type_param(ty: t) -> Option<uint> {
 
 // Returns the type and mutability of *t.
 //
-// The parameter `expl` indicates if this is an *explicit* dereference.  Some
-// types---notably unsafe ptrs---can only be dereferenced explicitly.
-fn deref(cx: ctxt, t: t, expl: bool) -> Option<mt> {
-    deref_sty(cx, &get(t).sty, expl)
+// The parameter `explicit` indicates if this is an *explicit* dereference.
+// Some types---notably unsafe ptrs---can only be dereferenced explicitly.
+fn deref(cx: ctxt, t: t, explicit: bool) -> Option<mt> {
+    deref_sty(cx, &get(t).sty, explicit)
 }
-fn deref_sty(cx: ctxt, sty: &sty, expl: bool) -> Option<mt> {
+
+fn deref_sty(cx: ctxt, sty: &sty, explicit: bool) -> Option<mt> {
     match *sty {
       ty_rptr(_, mt) | ty_box(mt) | ty_uniq(mt) => {
         Some(mt)
       }
 
-      ty_ptr(mt) if expl => {
+      ty_ptr(mt) if explicit => {
         Some(mt)
       }
 
@@ -3443,7 +3444,7 @@ fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] {
                                   id))
         }
     } else {
-        csearch::get_provided_trait_methods(cx, id).map(|info| info.ty.ident)
+        csearch::get_provided_trait_methods(cx, id).map(|ifo| ifo.ty.ident)
     }
 }
 
diff --git a/src/librustc/middle/typeck/check.rs b/src/librustc/middle/typeck/check.rs
index 3de99554554..d9ab7306ac3 100644
--- a/src/librustc/middle/typeck/check.rs
+++ b/src/librustc/middle/typeck/check.rs
@@ -267,7 +267,7 @@ fn check_fn(ccx: @crate_ctxt,
         } else { None };
 
         @fn_ctxt {
-            self_impl_def_id: self_info.map(|info| info.def_id),
+            self_impl_def_id: self_info.map(|self_info| self_info.def_id),
             ret_ty: ret_ty,
             indirect_ret_ty: indirect_ret_ty,
             purity: purity,
@@ -280,16 +280,16 @@ fn check_fn(ccx: @crate_ctxt,
 
     // Update the self_info to contain an accurate self type (taking
     // into account explicit self).
-    let self_info = do self_info.chain_ref |info| {
+    let self_info = do self_info.chain_ref |self_info| {
         // If the self type is sty_static, we don't have a self ty.
-        if info.explicit_self.node == ast::sty_static {
+        if self_info.explicit_self.node == ast::sty_static {
             None
         } else  {
             let self_region = fcx.in_scope_regions.find(ty::br_self);
             let ty = method::transform_self_type_for_method(
                 fcx.tcx(), self_region,
-                info.self_ty, info.explicit_self.node);
-            Some({self_ty: ty,.. *info})
+                self_info.self_ty, self_info.explicit_self.node);
+            Some({self_ty: ty,.. *self_info})
         }
     };
 
@@ -306,8 +306,8 @@ fn check_fn(ccx: @crate_ctxt,
       None => ()
     }
 
-    for self_info.each |info| {
-        fcx.write_ty(info.self_id, info.self_ty);
+    for self_info.each |self_info| {
+        fcx.write_ty(self_info.self_id, self_info.self_ty);
     }
     for vec::each2(decl.inputs, arg_tys) |input, arg| {
         fcx.write_ty(input.id, *arg);
@@ -344,19 +344,31 @@ fn check_fn(ccx: @crate_ctxt,
         };
 
         // Add the self parameter
-        for self_info.each |info| {
-            assign(info.explicit_self.span,
-                   info.self_id, Some(info.self_ty));
+        for self_info.each |self_info| {
+            assign(self_info.explicit_self.span,
+                   self_info.self_id,
+                   Some(self_info.self_ty));
             debug!("self is assigned to %s",
-                   fcx.inh.locals.get(info.self_id).to_str());
+                   fcx.inh.locals.get(self_info.self_id).to_str());
         }
 
         // Add formal parameters.
         for vec::each2(arg_tys, decl.inputs) |arg_ty, input| {
-            assign(input.ty.span, input.id, Some(*arg_ty));
-            debug!("Argument %s is assigned to %s",
-                   tcx.sess.str_of(input.ident),
-                   fcx.inh.locals.get(input.id).to_str());
+            // Create type variables for each argument.
+            do pat_util::pat_bindings(tcx.def_map, input.pat)
+                    |_bm, pat_id, _sp, _path| {
+                assign(input.ty.span, pat_id, None);
+            }
+
+            // Check the pattern.
+            let region = fcx.block_region();
+            let pcx = {
+                fcx: fcx,
+                map: pat_id_map(tcx.def_map, input.pat),
+                alt_region: region,
+                block_region: region,
+            };
+            alt::check_pat(pcx, input.pat, *arg_ty);
         }
 
         // Add explicitly-declared locals.
diff --git a/src/librustc/middle/typeck/check/alt.rs b/src/librustc/middle/typeck/check/alt.rs
index 41be34a713c..d7bee357b66 100644
--- a/src/librustc/middle/typeck/check/alt.rs
+++ b/src/librustc/middle/typeck/check/alt.rs
@@ -428,6 +428,9 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
             demand::eqtype(fcx, pat.span, ct, typ);
         }
         fcx.write_ty(pat.id, typ);
+
+        debug!("(checking alt) writing type for pat id %d", pat.id);
+
         match sub {
           Some(p) => check_pat(pcx, p, expected),
           _ => ()
diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs
index 33a26c8daf4..8000d2f7331 100644
--- a/src/librustc/middle/typeck/check/writeback.rs
+++ b/src/librustc/middle/typeck/check/writeback.rs
@@ -234,7 +234,10 @@ fn resolve_type_vars_in_fn(fcx: @fn_ctxt,
                                    self_info.self_id);
     }
     for decl.inputs.each |arg| {
-        resolve_type_vars_for_node(wbcx, arg.ty.span, arg.id);
+        do pat_util::pat_bindings(fcx.tcx().def_map, arg.pat)
+                |_bm, pat_id, span, _path| {
+            resolve_type_vars_for_node(wbcx, span, pat_id);
+        }
     }
     return wbcx.success;
 }
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index c1bffef3f31..5ad3b27e619 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -856,8 +856,8 @@ impl CoherenceChecker {
 
         debug!("(adding default methods for trait) processing trait");
 
-        for csearch::get_provided_trait_methods(tcx,
-                                                trait_def_id).each |info| {
+        for csearch::get_provided_trait_methods(tcx, trait_def_id).each
+                                                |trait_method_info| {
             debug!("(adding default methods for trait) found default method");
 
             // Create a new def ID for this provided method.
@@ -868,11 +868,11 @@ impl CoherenceChecker {
                 @ProvidedMethodInfo {
                     method_info: @{
                         did: new_did,
-                        n_tps: info.ty.tps.len(),
-                        ident: info.ty.ident,
-                        self_type: info.ty.self_ty
+                        n_tps: trait_method_info.ty.tps.len(),
+                        ident: trait_method_info.ty.ident,
+                        self_type: trait_method_info.ty.self_ty
                     },
-                    trait_method_def_id: info.def_id
+                    trait_method_def_id: trait_method_info.def_id
                 };
 
             let method_infos = @DVec();
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 8fcb9300b52..7452e41fac3 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -662,8 +662,8 @@ type expr = {id: node_id, callee_id: node_id, node: expr_, span: span};
 
 #[auto_serialize]
 #[auto_deserialize]
-enum log_level { error, debug, other }
-// 0 = error, 1 = debug, 2 = other
+enum log_level { error, debug, log_other }
+// 0 = error, 1 = debug, 2 = log_other
 
 #[auto_serialize]
 #[auto_deserialize]
@@ -1137,7 +1137,7 @@ impl Ty : to_bytes::IterBytes {
 
 #[auto_serialize]
 #[auto_deserialize]
-type arg = {mode: mode, ty: @Ty, ident: ident, id: node_id};
+type arg = {mode: mode, ty: @Ty, pat: @pat, id: node_id};
 
 #[auto_serialize]
 #[auto_deserialize]
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index ea49cce5047..d3b879da7dd 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -274,6 +274,12 @@ fn ident_to_path(s: span, +i: ident) -> @path {
       rp: None, types: ~[]}
 }
 
+fn ident_to_pat(id: node_id, s: span, +i: ident) -> @pat {
+    @{id: id,
+      node: pat_ident(bind_by_value, ident_to_path(s, i), None),
+      span: s}
+}
+
 pure fn is_unguarded(a: &arm) -> bool {
     match a.guard {
       None => true,
diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs
index 707787e78b9..39e94291d8b 100644
--- a/src/libsyntax/ext/auto_serialize.rs
+++ b/src/libsyntax/ext/auto_serialize.rs
@@ -515,7 +515,12 @@ fn mk_ser_method(
     let ser_inputs = ~[{
         mode: ast::infer(cx.next_id()),
         ty: ty_s,
-        ident: cx.ident_of(~"__s"),
+        pat: @{id: cx.next_id(),
+               node: ast::pat_ident(
+                    ast::bind_by_value,
+                    ast_util::ident_to_path(span, cx.ident_of(~"__s")),
+                    None),
+               span: span},
         id: cx.next_id(),
     }];
 
@@ -570,7 +575,12 @@ fn mk_deser_method(
     let deser_inputs = ~[{
         mode: ast::infer(cx.next_id()),
         ty: ty_d,
-        ident: cx.ident_of(~"__d"),
+        pat: @{id: cx.next_id(),
+               node: ast::pat_ident(
+                    ast::bind_by_value,
+                    ast_util::ident_to_path(span, cx.ident_of(~"__d")),
+                    None),
+               span: span},
         id: cx.next_id(),
     }];
 
@@ -1087,7 +1097,13 @@ fn mk_enum_deser_body(
                         node: ast::ty_infer,
                         span: span
                     },
-                    ident: cx.ident_of(~"i"),
+                    pat: @{id: cx.next_id(),
+                           node: ast::pat_ident(
+                                ast::bind_by_value,
+                                ast_util::ident_to_path(span,
+                                                        cx.ident_of(~"i")),
+                                None),
+                           span: span},
                     id: cx.next_id(),
                 }],
                 output: @{
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 5b4cc23ce09..ddf58ce0fef 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -234,24 +234,27 @@ fn mk_ctxt(parse_sess: parse::parse_sess,
     move ((move imp) as ext_ctxt)
 }
 
-fn expr_to_str(cx: ext_ctxt, expr: @ast::expr, error: ~str) -> ~str {
+fn expr_to_str(cx: ext_ctxt, expr: @ast::expr, err_msg: ~str) -> ~str {
     match expr.node {
       ast::expr_lit(l) => match l.node {
         ast::lit_str(s) => return *s,
-        _ => cx.span_fatal(l.span, error)
+        _ => cx.span_fatal(l.span, err_msg)
       },
-      _ => cx.span_fatal(expr.span, error)
+      _ => cx.span_fatal(expr.span, err_msg)
     }
 }
 
-fn expr_to_ident(cx: ext_ctxt, expr: @ast::expr, error: ~str) -> ast::ident {
+fn expr_to_ident(cx: ext_ctxt,
+                 expr: @ast::expr,
+                 err_msg: ~str) -> ast::ident {
     match expr.node {
       ast::expr_path(p) => {
         if vec::len(p.types) > 0u || vec::len(p.idents) != 1u {
-            cx.span_fatal(expr.span, error);
-        } else { return p.idents[0]; }
+            cx.span_fatal(expr.span, err_msg);
+        }
+        return p.idents[0];
       }
-      _ => cx.span_fatal(expr.span, error)
+      _ => cx.span_fatal(expr.span, err_msg)
     }
 }
 
diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs
index 632b3b93af9..f03adb90f0b 100644
--- a/src/libsyntax/ext/pipes/ast_builder.rs
+++ b/src/libsyntax/ext/pipes/ast_builder.rs
@@ -4,7 +4,7 @@
 // something smarter.
 
 use ast::{ident, node_id};
-use ast_util::respan;
+use ast_util::{ident_to_path, respan};
 use codemap::span;
 use ext::base::mk_ctxt;
 
@@ -178,7 +178,12 @@ impl ext_ctxt: ext_ctxt_ast_builder {
     fn arg(name: ident, ty: @ast::Ty) -> ast::arg {
         {mode: ast::infer(self.next_id()),
          ty: ty,
-         ident: name,
+         pat: @{id: self.next_id(),
+                node: ast::pat_ident(
+                    ast::bind_by_value,
+                    ast_util::ident_to_path(self.empty_span(), name),
+                    None),
+                span: self.empty_span()},
          id: self.next_id()}
     }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 3879e70cb28..8609124126c 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -105,9 +105,9 @@ fn fold_attribute_(at: attribute, fld: ast_fold) ->
 //used in noop_fold_foreign_item and noop_fold_fn_decl
 fn fold_arg_(a: arg, fld: ast_fold) -> arg {
     return {mode: a.mode,
-         ty: fld.fold_ty(a.ty),
-         ident: fld.fold_ident(a.ident),
-         id: fld.new_id(a.id)};
+            ty: fld.fold_ty(a.ty),
+            pat: fld.fold_pat(a.pat),
+            id: fld.new_id(a.id)};
 }
 //used in noop_fold_expr, and possibly elsewhere in the future
 fn fold_mac_(m: mac, fld: ast_fold) -> mac {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index db3f6abbf7b..2b42dcc0ed0 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -696,19 +696,21 @@ impl Parser {
     // identifier names.
     fn parse_arg_general(require_name: bool) -> arg {
         let mut m;
-        let i = if require_name || self.is_named_argument() {
+        let pat = if require_name || self.is_named_argument() {
             m = self.parse_arg_mode();
-            let name = self.parse_value_ident();
+            let pat = self.parse_pat(false);
             self.expect(token::COLON);
-            name
+            pat
         } else {
             m = infer(self.get_id());
-            special_idents::invalid
+            ast_util::ident_to_pat(self.get_id(),
+                                   copy self.last_span,
+                                   special_idents::invalid)
         };
 
         let t = self.parse_ty(false);
 
-        {mode: m, ty: t, ident: i, id: self.get_id()}
+        {mode: m, ty: t, pat: pat, id: self.get_id()}
     }
 
     fn parse_arg() -> arg_or_capture_item {
@@ -722,7 +724,7 @@ impl Parser {
     fn parse_fn_block_arg() -> arg_or_capture_item {
         do self.parse_capture_item_or |p| {
             let m = p.parse_arg_mode();
-            let i = p.parse_value_ident();
+            let pat = p.parse_pat(false);
             let t = if p.eat(token::COLON) {
                 p.parse_ty(false)
             } else {
@@ -730,7 +732,7 @@ impl Parser {
                   node: ty_infer,
                   span: mk_sp(p.span.lo, p.span.hi)}
             };
-            either::Left({mode: m, ty: t, ident: i, id: p.get_id()})
+            either::Left({mode: m, ty: t, pat: pat, id: p.get_id()})
         }
     }
 
@@ -1042,7 +1044,7 @@ impl Parser {
             let lvl = self.parse_expr();
             self.expect(token::COMMA);
             let e = self.parse_expr();
-            ex = expr_log(ast::other, lvl, e);
+            ex = expr_log(ast::log_other, lvl, e);
             hi = self.span.hi;
             self.expect(token::RPAREN);
         } else if self.eat_keyword(~"assert") {
@@ -2708,6 +2710,11 @@ impl Parser {
          }
     }
 
+    fn ident_to_path(i: ident) -> @path {
+        @{span: self.last_span, global: false, idents: ~[i],
+          rp: None, types: ~[]}
+    }
+
     fn parse_trait_ref() -> @trait_ref {
         @{path: self.parse_path_with_tps(false),
           ref_id: self.get_id(), impl_id: self.get_id()}
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index ed64d02cea3..0418f6776de 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1386,7 +1386,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
         match lvl {
           ast::debug => { word_nbsp(s, ~"log"); print_expr(s, expr); }
           ast::error => { word_nbsp(s, ~"log_err"); print_expr(s, expr); }
-          ast::other => {
+          ast::log_other => {
             word_nbsp(s, ~"log");
             popen(s);
             print_expr(s, lexp);
@@ -1820,12 +1820,19 @@ fn print_arg(s: ps, input: ast::arg) {
     ibox(s, indent_unit);
     print_arg_mode(s, input.mode);
     match input.ty.node {
-      ast::ty_infer => print_ident(s, input.ident),
+      ast::ty_infer => print_pat(s, input.pat),
       _ => {
-        if input.ident != parse::token::special_idents::invalid {
-            print_ident(s, input.ident);
-            word(s.s, ~":");
-            space(s.s);
+        match input.pat.node {
+            ast::pat_ident(_, path, _) if
+                path.idents.len() == 1 &&
+                path.idents[0] == parse::token::special_idents::invalid => {
+                // Do nothing.
+            }
+            _ => {
+                print_pat(s, input.pat);
+                word(s.s, ~":");
+                space(s.s);
+            }
         }
         print_type(s, input.ty);
       }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 97cc52bd35a..42b869b6c34 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -277,7 +277,10 @@ fn visit_ty_params<E>(tps: ~[ty_param], e: E, v: vt<E>) {
 }
 
 fn visit_fn_decl<E>(fd: fn_decl, e: E, v: vt<E>) {
-    for fd.inputs.each |a| { v.visit_ty(a.ty, e, v); }
+    for fd.inputs.each |a| {
+        v.visit_pat(a.pat, e, v);
+        v.visit_ty(a.ty, e, v);
+    }
     v.visit_ty(fd.output, e, v);
 }
 
diff --git a/src/test/compile-fail/macro-2.rs b/src/test/compile-fail/macro-2.rs
index bb54685f752..41be88168f2 100644
--- a/src/test/compile-fail/macro-2.rs
+++ b/src/test/compile-fail/macro-2.rs
@@ -1,4 +1,4 @@
-//error-pattern:is an expr, expected an identifier
+//error-pattern:is an expr, expected a path
 fn main() {
     #macro[[#mylambda[x, body],
             {
diff --git a/src/test/compile-fail/nontrivial-fn-arg-pattern-in-pure-fn.rs b/src/test/compile-fail/nontrivial-fn-arg-pattern-in-pure-fn.rs
new file mode 100644
index 00000000000..daf8b06bc31
--- /dev/null
+++ b/src/test/compile-fail/nontrivial-fn-arg-pattern-in-pure-fn.rs
@@ -0,0 +1,6 @@
+pure fn call_first((x, _y): (&fn(), &fn())) {
+    x();    //~ ERROR access to impure function prohibited in pure context
+}
+
+fn main() {}
+
diff --git a/src/test/compile-fail/refutable-pattern-in-fn-arg.rs b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs
new file mode 100644
index 00000000000..5299d6a87c3
--- /dev/null
+++ b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let f = |3: int| io::println("hello");  //~ ERROR refutable pattern
+    f(4);
+}
+
diff --git a/src/test/compile-fail/regions-glb-free-free.rs b/src/test/compile-fail/regions-glb-free-free.rs
index e4913f7056e..223665381da 100644
--- a/src/test/compile-fail/regions-glb-free-free.rs
+++ b/src/test/compile-fail/regions-glb-free-free.rs
@@ -19,7 +19,7 @@ mod argparse {
         fn set_desc(self, s: &str) -> Flag {
             Flag { //~ ERROR cannot infer an appropriate lifetime
                 name: self.name,
-                desc: s, //~ ERROR cannot infer an appropriate lifetime
+                desc: s,
                 max_count: self.max_count,
                 value: self.value
             }
diff --git a/src/test/run-pass/pattern-in-closure.rs b/src/test/run-pass/pattern-in-closure.rs
new file mode 100644
index 00000000000..ce5acb14944
--- /dev/null
+++ b/src/test/run-pass/pattern-in-closure.rs
@@ -0,0 +1,12 @@
+struct Foo {
+    x: int,
+    y: int
+}
+
+fn main() {
+    let f = |(x, _): (int, int)| io::println((x + 1).to_str());
+    let g = |Foo { x: x, y: y }: Foo| io::println((x + 1).to_str());
+    f((2, 3));
+    g(Foo { x: 1, y: 2 });
+}
+