diff --git a/src/doc/reference.md b/src/doc/reference.md index 016cf12985e..635e216831f 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3484,8 +3484,9 @@ fn main() { ``` -Patterns can also dereference pointers by using the `&`, `box` symbols, -as appropriate. For example, these two matches on `x: &int` are equivalent: +Patterns can also dereference pointers by using the `&`, `&mut` and `box` +symbols, as appropriate. For example, these two matches on `x: &int` are +equivalent: ``` # let x = &3i; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 8fdd66f83ce..f93a5114dcf 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -230,7 +230,7 @@ impl CharEq for F where F: FnMut(char) -> bool { impl<'a> CharEq for &'a [char] { #[inline] fn matches(&mut self, c: char) -> bool { - self.iter().any(|&mut m| m.matches(c)) + self.iter().any(|&m| { let mut m = m; m.matches(c) }) } #[inline] diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index de81f307c4d..3c672d0fdb6 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -119,7 +119,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } ast::PatBox(ref subpat) | - ast::PatRegion(ref subpat) | + ast::PatRegion(ref subpat, _) | ast::PatIdent(_, _, Some(ref subpat)) => { let subpat_exit = self.pat(&**subpat, pred); self.add_node(pat.id, &[subpat_exit]) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 2d9284846ac..f2b9ecb5ec4 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -473,7 +473,7 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, } } - ty::ty_rptr(_, ty::mt { ty, .. }) => { + ty::ty_rptr(_, ty::mt { ty, mutbl }) => { match ty.sty { ty::ty_vec(_, Some(n)) => match ctor { &Single => { @@ -493,7 +493,7 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, _ => { assert_eq!(pats_len, 1); - ast::PatRegion(pats.nth(0).unwrap()) + ast::PatRegion(pats.nth(0).unwrap(), mutbl) } } } @@ -860,7 +860,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], ast::PatTup(ref args) => Some(args.iter().map(|p| &**p).collect()), - ast::PatBox(ref inner) | ast::PatRegion(ref inner) => + ast::PatBox(ref inner) | ast::PatRegion(ref inner, _) => Some(vec![&**inner]), ast::PatLit(ref expr) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index dd61db4270c..2b8c9b532e5 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1235,8 +1235,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } } - ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => { - // @p1, ~p1, ref p1 + ast::PatBox(ref subpat) | ast::PatRegion(ref subpat, _) => { + // box p1, &p1, &mut p1. we can ignore the mutability of + // PatRegion since that information is already contained + // in the type. let subcmt = try!(self.cat_deref(pat, cmt, 0, false)); try!(self.cat_pattern_(subcmt, &**subpat, op)); } diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 50cbe664b90..fed0931cab7 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -683,7 +683,7 @@ fn any_uniq_pat(m: &[Match], col: uint) -> bool { } fn any_region_pat(m: &[Match], col: uint) -> bool { - any_pat!(m, col, ast::PatRegion(_)) + any_pat!(m, col, ast::PatRegion(..)) } fn any_irrefutable_adt_pat(tcx: &ty::ctxt, m: &[Match], col: uint) -> bool { @@ -1725,7 +1725,7 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llbox = Load(bcx, val); bcx = bind_irrefutable_pat(bcx, &**inner, llbox, cleanup_scope); } - ast::PatRegion(ref inner) => { + ast::PatRegion(ref inner, _) => { let loaded_val = Load(bcx, val); bcx = bind_irrefutable_pat(bcx, &**inner, loaded_val, cleanup_scope); } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index f6c09629f31..3f0f7fd9bd3 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3442,7 +3442,7 @@ fn create_scope_map(cx: &CrateContext, } } - ast::PatBox(ref sub_pat) | ast::PatRegion(ref sub_pat) => { + ast::PatBox(ref sub_pat) | ast::PatRegion(ref sub_pat, _) => { scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); walk_pattern(cx, &**sub_pat, scope_stack, scope_map); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index aef856b2b2b..c5b5325e9d4 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -192,12 +192,16 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, check_pat(pcx, &**inner, tcx.types.err); } } - ast::PatRegion(ref inner) => { + ast::PatRegion(ref inner, mutbl) => { let inner_ty = fcx.infcx().next_ty_var(); - let mutbl = - ty::deref(fcx.infcx().shallow_resolve(expected), true).map(|mt| mt.mutbl) - .unwrap_or(ast::MutImmutable); + // SNAP c894171 remove this `if`-`else` entirely after next snapshot + let mutbl = if mutbl == ast::MutImmutable { + ty::deref(fcx.infcx().shallow_resolve(expected), true) + .map(|mt| mt.mutbl).unwrap_or(ast::MutImmutable); + } else { + mutbl + }; let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e01dbac68ee..bb9a9ac4303 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2220,7 +2220,7 @@ fn name_from_pat(p: &ast::Pat) -> String { PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) .collect::>().connect(", ")), PatBox(ref p) => name_from_pat(&**p), - PatRegion(ref p) => name_from_pat(&**p), + PatRegion(ref p, _) => name_from_pat(&**p), PatLit(..) => { warn!("tried to get argument name from PatLit, \ which is silly in function arguments"); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e779821342a..727f4157c1e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -572,7 +572,7 @@ pub enum Pat_ { PatStruct(Path, Vec>, bool), PatTup(Vec>), PatBox(P), - PatRegion(P), // reference pattern + PatRegion(P, Mutability), // reference pattern PatLit(P), PatRange(P, P), /// [a, b, ..i, y, z] is represented as: diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 4026da6cf8e..5e03afec16c 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -633,7 +633,7 @@ pub fn walk_pat(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool { PatEnum(_, Some(ref s)) | PatTup(ref s) => { s.iter().all(|p| walk_pat_(&**p, it)) } - PatBox(ref s) | PatRegion(ref s) => { + PatBox(ref s) | PatRegion(ref s, _) => { walk_pat_(&**s, it) } PatVec(ref before, ref slice, ref after) => { diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 1fb8189c63c..1aa430c4a08 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -937,7 +937,7 @@ impl<'a> MethodDef<'a> { &**variant, self_arg_name, ast::MutImmutable); - (cx.pat(sp, ast::PatRegion(p)), idents) + (cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents) }; // A single arm has form (&VariantK, &VariantK, ...) => BodyK diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 396b0033b81..2999ef7ee86 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1257,7 +1257,7 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { } PatTup(elts) => PatTup(elts.move_map(|x| folder.fold_pat(x))), PatBox(inner) => PatBox(folder.fold_pat(inner)), - PatRegion(inner) => PatRegion(folder.fold_pat(inner)), + PatRegion(inner, mutbl) => PatRegion(folder.fold_pat(inner), mutbl), PatRange(e1, e2) => { PatRange(folder.fold_expr(e1), folder.fold_expr(e2)) }, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8e4a385923a..9b3df744317 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3351,11 +3351,16 @@ impl<'a> Parser<'a> { }) } token::BinOp(token::And) | token::AndAnd => { - // parse &pat + // parse &pat and &mut pat let lo = self.span.lo; self.expect_and(); + let mutability = if self.eat_keyword(keywords::Mut) { + ast::MutMutable + } else { + ast::MutImmutable + }; let sub = self.parse_pat(); - pat = PatRegion(sub); + pat = PatRegion(sub, mutability); hi = self.last_span.hi; return P(ast::Pat { id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index effd6e8218d..553e717f692 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2082,8 +2082,11 @@ impl<'a> State<'a> { try!(word(&mut self.s, "box ")); try!(self.print_pat(&**inner)); } - ast::PatRegion(ref inner) => { + ast::PatRegion(ref inner, mutbl) => { try!(word(&mut self.s, "&")); + if mutbl == ast::MutMutable { + try!(word(&mut self.s, "mut ")); + } try!(self.print_pat(&**inner)); } ast::PatLit(ref e) => try!(self.print_expr(&**e)), diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 737f1b73b32..cc71bafbbe5 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -511,7 +511,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { } } PatBox(ref subpattern) | - PatRegion(ref subpattern) => { + PatRegion(ref subpattern, _) => { visitor.visit_pat(&**subpattern) } PatIdent(_, ref pth1, ref optional_subpattern) => { diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 7e7f36f6e83..9f9a24d2426 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -169,7 +169,8 @@ impl Stats for [T] { fn sum(&self) -> T { let mut partials = vec![]; - for &mut x in self.iter() { + for &x in self.iter() { + let mut x = x; let mut j = 0; // This inner loop applies `hi`/`lo` summation to each // partial so that the list of partial sums remains exact. diff --git a/src/test/compile-fail/mut-pattern-internal-mutability.rs b/src/test/compile-fail/mut-pattern-internal-mutability.rs new file mode 100644 index 00000000000..05c6c4a9655 --- /dev/null +++ b/src/test/compile-fail/mut-pattern-internal-mutability.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let foo = &mut 1i; + + let &mut x = foo; + x += 1; //~ ERROR re-assignment of immutable variable + + // explicitly mut-ify internals + let &mut mut x = foo; + x += 1; + + // check borrowing is detected successfully + let &mut ref x = foo; + *foo += 1; //~ ERROR cannot assign to `*foo` because it is borrowed +} diff --git a/src/test/compile-fail/mut-pattern-mismatched.rs b/src/test/compile-fail/mut-pattern-mismatched.rs new file mode 100644 index 00000000000..74e6141a2b3 --- /dev/null +++ b/src/test/compile-fail/mut-pattern-mismatched.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let foo = &mut 1i; + + // (separate lines to ensure the spans are accurate) + + // SNAP c894171 uncomment this after the next snapshot + // NOTE(stage0) just in case tidy doesn't check SNAP's in tests + // let &_ // ~ ERROR expected `&mut int`, found `&_` + // = foo; + let &mut _ = foo; + + let bar = &1i; + let &_ = bar; + let &mut _ //~ ERROR expected `&int`, found `&mut _` + = bar; +}