about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-10-27 09:51:21 -0700
committerbors <bors@rust-lang.org>2013-10-27 09:51:21 -0700
commit16b8a41531bb0054f05be7a19e0867b8174c83b1 (patch)
tree6f41d27ea27c9b34e54a58875131e6a19c16e7cb /src
parent950add4e49cc2ac5d60abd6da969392123ddcce0 (diff)
parent523a28decc9b165cccded3db754f645ce10c2040 (diff)
downloadrust-16b8a41531bb0054f05be7a19e0867b8174c83b1.tar.gz
rust-16b8a41531bb0054f05be7a19e0867b8174c83b1.zip
auto merge of #10026 : luqmana/rust/mut-pat, r=pcwalton
Fixes #9792.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/borrowck/gather_loans/mod.rs2
-rw-r--r--src/librustc/middle/check_match.rs2
-rw-r--r--src/librustc/middle/kind.rs12
-rw-r--r--src/librustc/middle/lint.rs60
-rw-r--r--src/librustc/middle/liveness.rs14
-rw-r--r--src/librustc/middle/mem_categorization.rs36
-rw-r--r--src/librustc/middle/moves.rs2
-rw-r--r--src/librustc/middle/resolve.rs19
-rw-r--r--src/librustc/middle/trans/_match.rs6
-rw-r--r--src/librustc/middle/trans/base.rs1
-rw-r--r--src/librustc/middle/typeck/check/_match.rs2
-rw-r--r--src/libsyntax/ast.rs8
-rw-r--r--src/libsyntax/ast_util.rs2
-rw-r--r--src/libsyntax/ext/build.rs17
-rw-r--r--src/libsyntax/ext/deriving/generic.rs4
-rw-r--r--src/libsyntax/ext/expand.rs15
-rw-r--r--src/libsyntax/fold.rs2
-rw-r--r--src/libsyntax/parse/mod.rs5
-rw-r--r--src/libsyntax/parse/obsolete.rs6
-rw-r--r--src/libsyntax/parse/parser.rs50
-rw-r--r--src/libsyntax/print/pprust.rs12
-rw-r--r--src/test/compile-fail/lint-unused-mut-variables.rs19
-rw-r--r--src/test/compile-fail/mut-patterns.rs16
-rw-r--r--src/test/run-pass/mut-in-ident-patterns.rs80
24 files changed, 224 insertions, 168 deletions
diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs
index b5523c2ca5d..36a49de8778 100644
--- a/src/librustc/middle/borrowck/gather_loans/mod.rs
+++ b/src/librustc/middle/borrowck/gather_loans/mod.rs
@@ -730,7 +730,7 @@ impl<'self> GatherLoanCtxt<'self> {
                                          loan_mutability,
                                          scope_r);
                   }
-                  ast::BindInfer => {
+                  ast::BindByValue(_) => {
                       // No borrows here, but there may be moves
                       if self.bccx.is_move(pat.id) {
                           gather_moves::gather_move_from_pat(
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index de5e00d241e..482ba43ae25 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -884,7 +884,7 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
                 BindByRef(_) => {
                     by_ref_span = Some(span);
                 }
-                BindInfer => {
+                BindByValue(_) => {
                     if cx.moves_map.contains(&id) {
                         any_by_move = true;
                     }
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index 5737039f83c..fd5114889fd 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -432,14 +432,12 @@ fn is_nullary_variant(cx: &Context, ex: @Expr) -> bool {
 
 fn check_imm_free_var(cx: &Context, def: Def, sp: Span) {
     match def {
-        DefLocal(_, is_mutbl) => {
-            if is_mutbl {
-                cx.tcx.sess.span_err(
-                    sp,
-                    "mutable variables cannot be implicitly captured");
-            }
+        DefLocal(_, BindByValue(MutMutable)) => {
+            cx.tcx.sess.span_err(
+                sp,
+                "mutable variables cannot be implicitly captured");
         }
-        DefArg(*) => { /* ok */ }
+        DefLocal(*) | DefArg(*) => { /* ok */ }
         DefUpvar(_, def1, _, _) => { check_imm_free_var(cx, *def1, sp); }
         DefBinding(*) | DefSelf(*) => { /*ok*/ }
         _ => {
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index b0cdd53de92..1ac14dfc4b1 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -813,27 +813,24 @@ fn check_unused_unsafe(cx: &Context, e: &ast::Expr) {
 }
 
 fn check_unused_mut_pat(cx: &Context, p: @ast::Pat) {
-    let mut used = false;
-    let mut bindings = 0;
-    do pat_util::pat_bindings(cx.tcx.def_map, p) |_, id, _, _| {
-        used = used || cx.tcx.used_mut_nodes.contains(&id);
-        bindings += 1;
-    }
-    if !used {
-        let msg = if bindings == 1 {
-            "variable does not need to be mutable"
-        } else {
-            "variables do not need to be mutable"
-        };
-        cx.span_lint(unused_mut, p.span, msg);
-    }
-}
-
-fn check_unused_mut_fn_decl(cx: &Context, fd: &ast::fn_decl) {
-    for arg in fd.inputs.iter() {
-        if arg.is_mutbl {
-            check_unused_mut_pat(cx, arg.pat);
+    match p.node {
+        ast::PatIdent(ast::BindByValue(ast::MutMutable), _, _) => {
+            let mut used = false;
+            let mut bindings = 0;
+            do pat_util::pat_bindings(cx.tcx.def_map, p) |_, id, _, _| {
+                used = used || cx.tcx.used_mut_nodes.contains(&id);
+                bindings += 1;
+            }
+            if !used {
+                let msg = if bindings == 1 {
+                    "variable does not need to be mutable"
+                } else {
+                    "variables do not need to be mutable"
+                };
+                cx.span_lint(unused_mut, p.span, msg);
+            }
         }
+        _ => ()
     }
 }
 
@@ -1075,6 +1072,8 @@ impl Visitor<()> for Context {
 
     fn visit_pat(&mut self, p: @ast::Pat, _: ()) {
         check_pat_non_uppercase_statics(self, p);
+        check_unused_mut_pat(self, p);
+
         visit::walk_pat(self, p, ());
     }
 
@@ -1095,30 +1094,9 @@ impl Visitor<()> for Context {
         visit::walk_stmt(self, s, ());
     }
 
-    fn visit_ty_method(&mut self, tm: &ast::TypeMethod, _: ()) {
-        check_unused_mut_fn_decl(self, &tm.decl);
-        visit::walk_ty_method(self, tm, ());
-    }
-
-    fn visit_trait_method(&mut self, tm: &ast::trait_method, _: ()) {
-        match *tm {
-            ast::required(ref m) => check_unused_mut_fn_decl(self, &m.decl),
-            ast::provided(ref m) => check_unused_mut_fn_decl(self, &m.decl)
-        }
-        visit::walk_trait_method(self, tm, ());
-    }
-
-    fn visit_local(&mut self, l: @ast::Local, _: ()) {
-        if l.is_mutbl {
-            check_unused_mut_pat(self, l.pat);
-        }
-        visit::walk_local(self, l, ());
-    }
-
     fn visit_fn(&mut self, fk: &visit::fn_kind, decl: &ast::fn_decl,
                 body: &ast::Block, span: Span, id: ast::NodeId, _: ()) {
         let recurse = |this: &mut Context| {
-            check_unused_mut_fn_decl(this, decl);
             visit::walk_fn(this, fk, decl, body, span, id, ());
         };
 
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 695f4a6fd13..e9e416124af 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -429,7 +429,7 @@ fn visit_fn(v: &mut LivenessVisitor,
 
 fn visit_local(v: &mut LivenessVisitor, local: @Local, this: @mut IrMaps) {
     let def_map = this.tcx.def_map;
-    do pat_util::pat_bindings(def_map, local.pat) |_bm, p_id, sp, path| {
+    do pat_util::pat_bindings(def_map, local.pat) |bm, p_id, sp, path| {
         debug!("adding local variable {}", p_id);
         let name = ast_util::path_to_ident(path);
         this.add_live_node_for_node(p_id, VarDefNode(sp));
@@ -437,10 +437,14 @@ fn visit_local(v: &mut LivenessVisitor, local: @Local, this: @mut IrMaps) {
           Some(_) => FromLetWithInitializer,
           None => FromLetNoInitializer
         };
+        let mutbl = match bm {
+            BindByValue(MutMutable) => true,
+            _ => false
+        };
         this.add_variable(Local(LocalInfo {
           id: p_id,
           ident: name,
-          is_mutbl: local.is_mutbl,
+          is_mutbl: mutbl,
           kind: kind
         }));
     }
@@ -454,11 +458,15 @@ fn visit_arm(v: &mut LivenessVisitor, arm: &Arm, this: @mut IrMaps) {
             debug!("adding local variable {} from match with bm {:?}",
                    p_id, bm);
             let name = ast_util::path_to_ident(path);
+            let mutbl = match bm {
+                BindByValue(MutMutable) => true,
+                _ => false
+            };
             this.add_live_node_for_node(p_id, VarDefNode(sp));
             this.add_variable(Local(LocalInfo {
                 id: p_id,
                 ident: name,
-                is_mutbl: false,
+                is_mutbl: mutbl,
                 kind: FromMatch(bm)
             }));
         }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index eb03027ad71..5e26201522c 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -473,12 +473,15 @@ impl mem_categorization_ctxt {
               }
           }
 
-          ast::DefArg(vid, mutbl) => {
+          ast::DefArg(vid, binding_mode) => {
             // Idea: make this could be rewritten to model by-ref
             // stuff as `&const` and `&mut`?
 
             // m: mutability of the argument
-            let m = if mutbl {McDeclared} else {McImmutable};
+            let m = match binding_mode {
+                ast::BindByValue(ast::MutMutable) => McDeclared,
+                _ => McImmutable
+            };
             @cmt_ {
                 id: id,
                 span: span,
@@ -548,25 +551,20 @@ impl mem_categorization_ctxt {
               }
           }
 
-          ast::DefLocal(vid, mutbl) => {
-            let m = if mutbl {McDeclared} else {McImmutable};
-            @cmt_ {
-                id:id,
-                span:span,
-                cat:cat_local(vid),
-                mutbl:m,
-                ty:expr_ty
-            }
-          }
-
-          ast::DefBinding(vid, _) => {
+          ast::DefLocal(vid, binding_mode) |
+          ast::DefBinding(vid, binding_mode) => {
             // by-value/by-ref bindings are local variables
+            let m = match binding_mode {
+                ast::BindByValue(ast::MutMutable) => McDeclared,
+                _ => McImmutable
+            };
+
             @cmt_ {
-                id:id,
-                span:span,
-                cat:cat_local(vid),
-                mutbl:McImmutable,
-                ty:expr_ty
+                id: id,
+                span: span,
+                cat: cat_local(vid),
+                mutbl: m,
+                ty: expr_ty
             }
           }
         }
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
index 5001614647a..d4dce789192 100644
--- a/src/librustc/middle/moves.rs
+++ b/src/librustc/middle/moves.rs
@@ -618,7 +618,7 @@ impl VisitContext {
         do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, path| {
             let binding_moves = match bm {
                 BindByRef(_) => false,
-                BindInfer => {
+                BindByValue(_) => {
                     let pat_ty = ty::node_id_to_type(self.tcx, id);
                     debug!("pattern {:?} {} type is {}",
                            id,
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index ee36b807ac7..c16c39b5a09 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -3817,11 +3817,8 @@ impl Resolver {
                 Some(declaration) => {
                     for argument in declaration.inputs.iter() {
                         let binding_mode = ArgumentIrrefutableMode;
-                        let mutability =
-                            if argument.is_mutbl {Mutable} else {Immutable};
                         this.resolve_pattern(argument.pat,
                                              binding_mode,
-                                             mutability,
                                              None);
 
                         this.resolve_type(&argument.ty);
@@ -4036,8 +4033,6 @@ impl Resolver {
     }
 
     fn resolve_local(&mut self, local: @Local) {
-        let mutability = if local.is_mutbl {Mutable} else {Immutable};
-
         // Resolve the type.
         self.resolve_type(&local.ty);
 
@@ -4052,7 +4047,7 @@ impl Resolver {
         }
 
         // Resolve the pattern.
-        self.resolve_pattern(local.pat, LocalIrrefutableMode, mutability, None);
+        self.resolve_pattern(local.pat, LocalIrrefutableMode, None);
     }
 
     // build a map from pattern identifiers to binding-info's.
@@ -4116,8 +4111,7 @@ impl Resolver {
 
         let bindings_list = @mut HashMap::new();
         for pattern in arm.pats.iter() {
-            self.resolve_pattern(*pattern, RefutableMode, Immutable,
-                                 Some(bindings_list));
+            self.resolve_pattern(*pattern, RefutableMode, Some(bindings_list));
         }
 
         // This has to happen *after* we determine which
@@ -4261,7 +4255,6 @@ impl Resolver {
     fn resolve_pattern(&mut self,
                        pattern: @Pat,
                        mode: PatternBindingMode,
-                       mutability: Mutability,
                        // Maps idents to the node ID for the (outermost)
                        // pattern that binds them
                        bindings_list: Option<@mut HashMap<Name,NodeId>>) {
@@ -4324,8 +4317,6 @@ impl Resolver {
                             debug!("(resolving pattern) binding `{}`",
                                    interner_get(renamed));
 
-                            let is_mutable = mutability == Mutable;
-
                             let def = match mode {
                                 RefutableMode => {
                                     // For pattern arms, we must use
@@ -4335,11 +4326,11 @@ impl Resolver {
                                 }
                                 LocalIrrefutableMode => {
                                     // But for locals, we use `def_local`.
-                                    DefLocal(pattern.id, is_mutable)
+                                    DefLocal(pattern.id, binding_mode)
                                 }
                                 ArgumentIrrefutableMode => {
                                     // And for function arguments, `def_arg`.
-                                    DefArg(pattern.id, is_mutable)
+                                    DefArg(pattern.id, binding_mode)
                                 }
                             };
 
@@ -5361,7 +5352,7 @@ impl Resolver {
                                         pat_binding_mode: BindingMode,
                                         descr: &str) {
         match pat_binding_mode {
-            BindInfer => {}
+            BindByValue(_) => {}
             BindByRef(*) => {
                 self.resolve_error(
                     pat.span,
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 6bb41929db1..a36d938052a 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -1842,7 +1842,7 @@ fn create_bindings_map(bcx: @mut Block, pat: @ast::Pat) -> BindingsMap {
         let llmatch;
         let trmode;
         match bm {
-            ast::BindInfer => {
+            ast::BindByValue(_) => {
                 // in this case, the final type of the variable will be T,
                 // but during matching we need to store a *T as explained
                 // above
@@ -2130,7 +2130,7 @@ fn bind_irrefutable_pat(bcx: @mut Block,
                     bcx, pat.id, path, binding_mode,
                     |bcx, variable_ty, llvariable_val| {
                         match pat_binding_mode {
-                            ast::BindInfer => {
+                            ast::BindByValue(_) => {
                                 // By value binding: move the value that `val`
                                 // points at into the binding's stack slot.
                                 let datum = Datum {val: val,
@@ -2241,7 +2241,7 @@ fn bind_irrefutable_pat(bcx: @mut Block,
 
 fn simple_identifier<'a>(pat: &'a ast::Pat) -> Option<&'a ast::Path> {
     match pat.node {
-        ast::PatIdent(ast::BindInfer, ref path, None) => {
+        ast::PatIdent(ast::BindByValue(_), ref path, None) => {
             Some(path)
         }
         _ => {
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 4e3aa2a9893..74f9e2114e1 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2065,7 +2065,6 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
     // Translate variant arguments to function arguments.
     let fn_args = do args.map |varg| {
         ast::arg {
-            is_mutbl: false,
             ty: (*varg.ty()).clone(),
             pat: ast_util::ident_to_pat(
                 ccx.tcx.sess.next_node_id(),
diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs
index 25048d888fa..93c3d94f5dc 100644
--- a/src/librustc/middle/typeck/check/_match.rs
+++ b/src/librustc/middle/typeck/check/_match.rs
@@ -476,7 +476,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::Pat, expected: ty::t) {
             demand::eqtype(fcx, pat.span, region_ty, typ);
           }
           // otherwise the type of x is the expected type T
-          ast::BindInfer => {
+          ast::BindByValue(_) => {
             demand::eqtype(fcx, pat.span, expected, typ);
           }
         }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 372f1950c1d..6647c4c811e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -232,8 +232,8 @@ pub enum Def {
     DefMod(DefId),
     DefForeignMod(DefId),
     DefStatic(DefId, bool /* is_mutbl */),
-    DefArg(NodeId, bool /* is_mutbl */),
-    DefLocal(NodeId, bool /* is_mutbl */),
+    DefArg(NodeId, BindingMode),
+    DefLocal(NodeId, BindingMode),
     DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */),
     DefTy(DefId),
     DefTrait(DefId),
@@ -324,7 +324,7 @@ pub struct FieldPat {
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub enum BindingMode {
     BindByRef(Mutability),
-    BindInfer
+    BindByValue(Mutability),
 }
 
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
@@ -445,7 +445,6 @@ pub enum Stmt_ {
 // a refinement on pat.
 #[deriving(Eq, Encodable, Decodable,IterBytes)]
 pub struct Local {
-    is_mutbl: bool,
     ty: Ty,
     pat: @Pat,
     init: Option<@Expr>,
@@ -880,7 +879,6 @@ pub struct inline_asm {
 
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub struct arg {
-    is_mutbl: bool,
     ty: Ty,
     pat: @Pat,
     id: NodeId,
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 456d344b838..3ec87dbdd26 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -234,7 +234,7 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
 
 pub fn ident_to_pat(id: NodeId, s: Span, i: Ident) -> @Pat {
     @ast::Pat { id: id,
-                node: PatIdent(BindInfer, ident_to_path(s, i), None),
+                node: PatIdent(BindByValue(MutImmutable), ident_to_path(s, i), None),
                 span: s }
 }
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 78cdc3f585b..4c3ab840b44 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -399,9 +399,12 @@ impl AstBuilder for @ExtCtxt {
     }
 
     fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, ex: @ast::Expr) -> @ast::Stmt {
-        let pat = self.pat_ident(sp, ident);
+        let pat = if mutbl {
+            self.pat_ident_binding_mode(sp, ident, ast::BindByValue(ast::MutMutable))
+        } else {
+            self.pat_ident(sp, ident)
+        };
         let local = @ast::Local {
-            is_mutbl: mutbl,
             ty: self.ty_infer(sp),
             pat: pat,
             init: Some(ex),
@@ -419,9 +422,12 @@ impl AstBuilder for @ExtCtxt {
                       typ: ast::Ty,
                       ex: @ast::Expr)
                       -> @ast::Stmt {
-        let pat = self.pat_ident(sp, ident);
+        let pat = if mutbl {
+            self.pat_ident_binding_mode(sp, ident, ast::BindByValue(ast::MutMutable))
+        } else {
+            self.pat_ident(sp, ident)
+        };
         let local = @ast::Local {
-            is_mutbl: mutbl,
             ty: typ,
             pat: pat,
             init: Some(ex),
@@ -624,7 +630,7 @@ impl AstBuilder for @ExtCtxt {
         self.pat(span, ast::PatLit(expr))
     }
     fn pat_ident(&self, span: Span, ident: ast::Ident) -> @ast::Pat {
-        self.pat_ident_binding_mode(span, ident, ast::BindInfer)
+        self.pat_ident_binding_mode(span, ident, ast::BindByValue(ast::MutImmutable))
     }
 
     fn pat_ident_binding_mode(&self,
@@ -710,7 +716,6 @@ impl AstBuilder for @ExtCtxt {
     fn arg(&self, span: Span, ident: ast::Ident, ty: ast::Ty) -> ast::arg {
         let arg_pat = self.pat_ident(span, ident);
         ast::arg {
-            is_mutbl: false,
             ty: ty,
             pat: arg_pat,
             id: ast::DUMMY_NODE_ID
diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs
index c31c609d4e7..82a779546fc 100644
--- a/src/libsyntax/ext/deriving/generic.rs
+++ b/src/libsyntax/ext/deriving/generic.rs
@@ -922,7 +922,7 @@ fn create_struct_pattern(cx: @ExtCtxt,
     if struct_def.fields.is_empty() {
         return (
             cx.pat_ident_binding_mode(
-                span, struct_ident, ast::BindInfer),
+                span, struct_ident, ast::BindByValue(ast::MutImmutable)),
             ~[]);
     }
 
@@ -985,7 +985,7 @@ fn create_enum_variant_pattern(cx: @ExtCtxt,
         ast::tuple_variant_kind(ref variant_args) => {
             if variant_args.is_empty() {
                 return (cx.pat_ident_binding_mode(
-                    span, variant_ident, ast::BindInfer), ~[]);
+                    span, variant_ident, ast::BindByValue(ast::MutImmutable)), ~[]);
             }
 
             let matching_path = cx.path_ident(span, variant_ident);
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 99bcb36eedb..9526357f9ae 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -551,13 +551,13 @@ fn expand_non_macro_stmt(exts: SyntaxEnv, s: &Stmt, fld: &MacroExpander)
             let pending_renames = block_info.pending_renames;
 
             // take it apart:
-            let @Local{is_mutbl:is_mutbl,
-                       ty:_,
-                       pat:pat,
-                       init:init,
-                       id:id,
-                       span:span
-                      } = *local;
+            let @Local {
+                ty: _,
+                pat: pat,
+                init: init,
+                id: id,
+                span: span
+            } = *local;
             // types can't be copied automatically because of the owned ptr in ty_tup...
             let ty = local.ty.clone();
             // expand the pat (it might contain exprs... #:(o)>
@@ -585,7 +585,6 @@ fn expand_non_macro_stmt(exts: SyntaxEnv, s: &Stmt, fld: &MacroExpander)
             let new_init_opt = init.map(|e| fld.fold_expr(e));
             let rewritten_local =
                 @Local {
-                    is_mutbl: is_mutbl,
                     ty: ty,
                     pat: rewritten_pat,
                     init: new_init_opt,
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 37bc00d5827..e9ecb95c545 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -356,7 +356,6 @@ pub trait ast_fold {
 
     fn fold_local(&self, l: @Local) -> @Local {
         @Local {
-            is_mutbl: l.is_mutbl,
             ty: self.fold_ty(&l.ty),
             pat: self.fold_pat(l.pat),
             init: l.init.map(|e| self.fold_expr(e)),
@@ -426,7 +425,6 @@ fn fold_attribute_<T:ast_fold>(at: Attribute, fld: &T) -> Attribute {
 //used in noop_fold_foreign_item and noop_fold_fn_decl
 fn fold_arg_<T:ast_fold>(a: &arg, fld: &T) -> arg {
     ast::arg {
-        is_mutbl: a.is_mutbl,
         ty: fld.fold_ty(&a.ty),
         pat: fld.fold_pat(a.pat),
         id: fld.new_id(a.id),
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index fad9eab7542..0de571978a0 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -639,7 +639,7 @@ mod test {
         assert_eq!(parser.parse_pat(),
                    @ast::Pat{id: ast::DUMMY_NODE_ID,
                              node: ast::PatIdent(
-                                ast::BindInfer,
+                                ast::BindByValue(ast::MutImmutable),
                                 ast::Path {
                                     span:sp(0,1),
                                     global:false,
@@ -666,7 +666,6 @@ mod test {
                             id: ast::DUMMY_NODE_ID,
                             node: ast::item_fn(ast::fn_decl{
                                 inputs: ~[ast::arg{
-                                    is_mutbl: false,
                                     ty: ast::Ty{id: ast::DUMMY_NODE_ID,
                                                 node: ast::ty_path(ast::Path{
                                         span:sp(10,13),
@@ -685,7 +684,7 @@ mod test {
                                     pat: @ast::Pat {
                                         id: ast::DUMMY_NODE_ID,
                                         node: ast::PatIdent(
-                                            ast::BindInfer,
+                                            ast::BindByValue(ast::MutImmutable),
                                             ast::Path {
                                                 span:sp(6,7),
                                                 global:false,
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index 8c26793605c..20ad13dace6 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -34,7 +34,6 @@ pub enum ObsoleteSyntax {
     ObsoleteBareFnType,
     ObsoleteNamedExternModule,
     ObsoleteMultipleLocalDecl,
-    ObsoleteMutWithMultipleBindings,
     ObsoleteUnsafeExternFn,
     ObsoleteTraitFuncVisibility,
     ObsoleteConstPointer,
@@ -91,11 +90,6 @@ impl ParserObsoleteMethods for Parser {
                 "instead of e.g. `let a = 1, b = 2`, write \
                  `let (a, b) = (1, 2)`."
             ),
-            ObsoleteMutWithMultipleBindings => (
-                "`mut` with multiple bindings",
-                "use multiple local declarations instead of e.g. `let mut \
-                 (x, y) = ...`."
-            ),
             ObsoleteUnsafeExternFn => (
                 "unsafe external function",
                 "external functions are always unsafe; remove the `unsafe` \
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 605e259cf0c..5a5e310e56f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -17,7 +17,7 @@ use ast::{CallSugar, NoSugar, DoSugar};
 use ast::{TyBareFn, TyClosure};
 use ast::{RegionTyParamBound, TraitTyParamBound};
 use ast::{provided, public, purity};
-use ast::{_mod, BiAdd, arg, Arm, Attribute, BindByRef, BindInfer};
+use ast::{_mod, BiAdd, arg, Arm, Attribute, BindByRef, BindByValue};
 use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
 use ast::{BlockCheckMode, UnBox};
 use ast::{Crate, CrateConfig, Decl, DeclItem};
@@ -1184,15 +1184,8 @@ impl Parser {
     pub fn is_named_argument(&self) -> bool {
         let offset = match *self.token {
             token::BINOP(token::AND) => 1,
-            token::BINOP(token::MINUS) => 1,
             token::ANDAND => 1,
-            token::BINOP(token::PLUS) => {
-                if self.look_ahead(1, |t| *t == token::BINOP(token::PLUS)) {
-                    2
-                } else {
-                    1
-                }
-            },
+            _ if token::is_keyword(keywords::Mut, self.token) => 1,
             _ => 0
         };
 
@@ -1210,16 +1203,11 @@ impl Parser {
     // This version of parse arg doesn't necessarily require
     // identifier names.
     pub fn parse_arg_general(&self, require_name: bool) -> arg {
-        let is_mutbl = self.eat_keyword(keywords::Mut);
         let pat = if require_name || self.is_named_argument() {
             debug!("parse_arg_general parse_pat (require_name:{:?})",
                    require_name);
             let pat = self.parse_pat();
 
-            if is_mutbl && !ast_util::pat_is_ident(pat) {
-                self.obsolete(*self.span, ObsoleteMutWithMultipleBindings)
-            }
-
             self.expect(&token::COLON);
             pat
         } else {
@@ -1232,7 +1220,6 @@ impl Parser {
         let t = self.parse_ty(false);
 
         ast::arg {
-            is_mutbl: is_mutbl,
             ty: t,
             pat: pat,
             id: ast::DUMMY_NODE_ID,
@@ -1246,7 +1233,6 @@ impl Parser {
 
     // parse an argument in a lambda header e.g. |arg, arg|
     pub fn parse_fn_block_arg(&self) -> arg {
-        let is_mutbl = self.eat_keyword(keywords::Mut);
         let pat = self.parse_pat();
         let t = if self.eat(&token::COLON) {
             self.parse_ty(false)
@@ -1258,7 +1244,6 @@ impl Parser {
             }
         };
         ast::arg {
-            is_mutbl: is_mutbl,
             ty: t,
             pat: pat,
             id: ast::DUMMY_NODE_ID
@@ -1809,7 +1794,7 @@ impl Parser {
                 return self.mk_mac_expr(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT));
             } else if *self.token == token::LBRACE {
                 // This might be a struct literal.
-                if self.looking_at_record_literal() {
+                if self.looking_at_struct_literal() {
                     // It's a struct literal.
                     self.bump();
                     let mut fields = ~[];
@@ -2520,12 +2505,11 @@ impl Parser {
         }
     }
 
-    // For distingishing between record literals and blocks
-    fn looking_at_record_literal(&self) -> bool {
+    // For distingishing between struct literals and blocks
+    fn looking_at_struct_literal(&self) -> bool {
         *self.token == token::LBRACE &&
-            (self.look_ahead(1, |t| token::is_keyword(keywords::Mut, t)) ||
-             (self.look_ahead(1, |t| token::is_plain_ident(t)) &&
-              self.look_ahead(2, |t| *t == token::COLON)))
+        (self.look_ahead(1, |t| token::is_plain_ident(t)) &&
+         self.look_ahead(2, |t| *t == token::COLON))
     }
 
     fn parse_match_expr(&self) -> @Expr {
@@ -2681,7 +2665,7 @@ impl Parser {
             } else {
                 subpat = @ast::Pat {
                     id: ast::DUMMY_NODE_ID,
-                    node: PatIdent(BindInfer, fieldpath, None),
+                    node: PatIdent(BindByValue(MutImmutable), fieldpath, None),
                     span: *self.last_span
                 };
             }
@@ -2863,6 +2847,8 @@ impl Parser {
             } else {
                 pat = PatLit(val);
             }
+        } else if self.eat_keyword(keywords::Mut) {
+            pat = self.parse_pat_ident(BindByValue(MutMutable));
         } else if self.eat_keyword(keywords::Ref) {
             // parse ref pat
             let mutbl = self.parse_mutability();
@@ -2891,7 +2877,7 @@ impl Parser {
                     // or just foo
                     sub = None;
                 }
-                pat = PatIdent(BindInfer, name, sub);
+                pat = PatIdent(BindByValue(MutImmutable), name, sub);
             } else {
                 // parse an enum pat
                 let enum_path = self.parse_path(LifetimeAndTypesWithColons)
@@ -2935,7 +2921,7 @@ impl Parser {
                                   // it could still be either an enum
                                   // or an identifier pattern, resolve
                                   // will sort it out:
-                                  pat = PatIdent(BindInfer,
+                                  pat = PatIdent(BindByValue(MutImmutable),
                                                   enum_path,
                                                   None);
                               } else {
@@ -2989,14 +2975,10 @@ impl Parser {
     }
 
     // parse a local variable declaration
-    fn parse_local(&self, is_mutbl: bool) -> @Local {
+    fn parse_local(&self) -> @Local {
         let lo = self.span.lo;
         let pat = self.parse_pat();
 
-        if is_mutbl && !ast_util::pat_is_ident(pat) {
-            self.obsolete(*self.span, ObsoleteMutWithMultipleBindings)
-        }
-
         let mut ty = Ty {
             id: ast::DUMMY_NODE_ID,
             node: ty_infer,
@@ -3005,7 +2987,6 @@ impl Parser {
         if self.eat(&token::COLON) { ty = self.parse_ty(false); }
         let init = self.parse_initializer();
         @ast::Local {
-            is_mutbl: is_mutbl,
             ty: ty,
             pat: pat,
             init: init,
@@ -3016,11 +2997,10 @@ impl Parser {
 
     // parse a "let" stmt
     fn parse_let(&self) -> @Decl {
-        let is_mutbl = self.eat_keyword(keywords::Mut);
         let lo = self.span.lo;
-        let local = self.parse_local(is_mutbl);
+        let local = self.parse_local();
         while self.eat(&token::COMMA) {
-            let _ = self.parse_local(is_mutbl);
+            let _ = self.parse_local();
             self.obsolete(*self.span, ObsoleteMultipleLocalDecl);
         }
         return @spanned(lo, self.last_span.hi, DeclLocal(local));
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 400ff804485..12193411910 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1476,10 +1476,6 @@ pub fn print_decl(s: @ps, decl: &ast::Decl) {
         ibox(s, indent_unit);
         word_nbsp(s, "let");
 
-        if loc.is_mutbl {
-            word_nbsp(s, "mut");
-        }
-
         fn print_local(s: @ps, loc: &ast::Local) {
             ibox(s, indent_unit);
             print_local_decl(s, loc);
@@ -1589,7 +1585,10 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) {
                   word_nbsp(s, "ref");
                   print_mutability(s, mutbl);
               }
-              ast::BindInfer => {}
+              ast::BindByValue(ast::MutImmutable) => {}
+              ast::BindByValue(ast::MutMutable) => {
+                  word_nbsp(s, "mut");
+              }
           }
           print_path(s, path, true);
           match sub {
@@ -1932,9 +1931,6 @@ pub fn print_mt(s: @ps, mt: &ast::mt) {
 
 pub fn print_arg(s: @ps, input: &ast::arg) {
     ibox(s, indent_unit);
-    if input.is_mutbl {
-        word_space(s, "mut");
-    }
     match input.ty.node {
       ast::ty_infer => print_pat(s, input.pat),
       _ => {
diff --git a/src/test/compile-fail/lint-unused-mut-variables.rs b/src/test/compile-fail/lint-unused-mut-variables.rs
index 9b0249bdc2a..4b382a3116a 100644
--- a/src/test/compile-fail/lint-unused-mut-variables.rs
+++ b/src/test/compile-fail/lint-unused-mut-variables.rs
@@ -20,6 +20,14 @@ fn main() {
     let mut a = 2; //~ ERROR: variable does not need to be mutable
     let mut b = 3; //~ ERROR: variable does not need to be mutable
     let mut a = ~[3]; //~ ERROR: variable does not need to be mutable
+    let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable
+
+    match 30 {
+        mut x => {} //~ ERROR: variable does not need to be mutable
+    }
+
+    let x = |mut y: int| 10; //~ ERROR: variable does not need to be mutable
+    fn what(mut foo: int) {} //~ ERROR: variable does not need to be mutable
 
     // positive cases
     let mut a = 2;
@@ -30,6 +38,17 @@ fn main() {
     do callback {
         a.push(3);
     }
+    let (mut a, b) = (1, 2);
+    a = 34;
+
+    match 30 {
+        mut x => {
+            x = 21;
+        }
+    }
+
+    let x = |mut y: int| y = 32;
+    fn nothing(mut foo: int) { foo = 37; }
 }
 
 fn callback(f: &fn()) {}
diff --git a/src/test/compile-fail/mut-patterns.rs b/src/test/compile-fail/mut-patterns.rs
new file mode 100644
index 00000000000..d9cdae4a499
--- /dev/null
+++ b/src/test/compile-fail/mut-patterns.rs
@@ -0,0 +1,16 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Can't put mut in non-ident pattern
+
+pub fn main() {
+    struct Foo { x: int }
+    let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected `;` but found `{`
+}
diff --git a/src/test/run-pass/mut-in-ident-patterns.rs b/src/test/run-pass/mut-in-ident-patterns.rs
new file mode 100644
index 00000000000..13303e7b108
--- /dev/null
+++ b/src/test/run-pass/mut-in-ident-patterns.rs
@@ -0,0 +1,80 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo {
+    fn foo(&self, mut x: int) -> int {
+        let val = x;
+        x = 37 * x;
+        val + x
+    }
+}
+
+struct X;
+impl Foo for X {}
+
+pub fn main() {
+    let (a, mut b) = (23, 4);
+    assert_eq!(a, 23);
+    assert_eq!(b, 4);
+    b = a + b;
+    assert_eq!(b, 27);
+
+
+    assert_eq!(X.foo(2), 76);
+
+    enum Bar {
+       Foo(int),
+       Baz(f32, u8)
+    }
+
+    let (x, mut y) = (32, Foo(21));
+
+    match x {
+        mut z @ 32 => {
+            assert_eq!(z, 32);
+            z = 34;
+            assert_eq!(z, 34);
+        }
+        _ => {}
+    }
+
+    check_bar(&y);
+    y = Baz(10.0, 3);
+    check_bar(&y);
+
+    fn check_bar(y: &Bar) {
+        match y {
+            &Foo(a) => {
+                assert_eq!(a, 21);
+            }
+            &Baz(a, b) => {
+                assert_eq!(a, 10.0);
+                assert_eq!(b, 3);
+            }
+        }
+    }
+
+    fn foo1((x, mut y): (f64, int), mut z: int) -> int {
+        y = 2 * 6;
+        z = y + (x as int);
+        y - z
+    }
+
+    struct A {
+        x: int
+    }
+    let A { x: mut x } = A { x: 10 };
+    assert_eq!(x, 10);
+    x = 30;
+    assert_eq!(x, 30);
+
+    (|A { x: mut t }: A| { t = t+1; t })(A { x: 34 });
+
+}