Skip to content

Commit bf6c007

Browse files
committed
Change & pat to only work with &T, and &mut with &mut T.
This implements RFC 179 by making the pattern `&<pat>` require matching against a variable of type `&T`, and introducing the pattern `&mut <pat>` which only works with variables of type `&mut T`. The pattern `&mut x` currently parses as `&(mut x)` i.e. a pattern match through a `&T` or a `&mut T` that binds the variable `x` to have type `T` and to be mutable. This should be rewritten as follows, for example, for &mut x in slice.iter() { becomes for &x in slice.iter() { let mut x = x; Due to this, this is a [breaking-change] Closes #20496.
1 parent 5773bde commit bf6c007

File tree

19 files changed

+91
-25
lines changed

19 files changed

+91
-25
lines changed

src/doc/reference.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3484,8 +3484,9 @@ fn main() {
34843484
34853485
```
34863486

3487-
Patterns can also dereference pointers by using the `&`, `box` symbols,
3488-
as appropriate. For example, these two matches on `x: &int` are equivalent:
3487+
Patterns can also dereference pointers by using the `&`, `&mut` and `box`
3488+
symbols, as appropriate. For example, these two matches on `x: &int` are
3489+
equivalent:
34893490

34903491
```
34913492
# let x = &3i;

src/libcore/str/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ impl<F> CharEq for F where F: FnMut(char) -> bool {
230230
impl<'a> CharEq for &'a [char] {
231231
#[inline]
232232
fn matches(&mut self, c: char) -> bool {
233-
self.iter().any(|&mut m| m.matches(c))
233+
self.iter().any(|&m| { let mut m = m; m.matches(c) })
234234
}
235235

236236
#[inline]

src/librustc/middle/cfg/construct.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
119119
}
120120

121121
ast::PatBox(ref subpat) |
122-
ast::PatRegion(ref subpat) |
122+
ast::PatRegion(ref subpat, _) |
123123
ast::PatIdent(_, _, Some(ref subpat)) => {
124124
let subpat_exit = self.pat(&**subpat, pred);
125125
self.add_node(pat.id, &[subpat_exit])

src/librustc/middle/check_match.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor,
473473
}
474474
}
475475

476-
ty::ty_rptr(_, ty::mt { ty, .. }) => {
476+
ty::ty_rptr(_, ty::mt { ty, mutbl }) => {
477477
match ty.sty {
478478
ty::ty_vec(_, Some(n)) => match ctor {
479479
&Single => {
@@ -493,7 +493,7 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor,
493493

494494
_ => {
495495
assert_eq!(pats_len, 1);
496-
ast::PatRegion(pats.nth(0).unwrap())
496+
ast::PatRegion(pats.nth(0).unwrap(), mutbl)
497497
}
498498
}
499499
}
@@ -860,7 +860,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
860860
ast::PatTup(ref args) =>
861861
Some(args.iter().map(|p| &**p).collect()),
862862

863-
ast::PatBox(ref inner) | ast::PatRegion(ref inner) =>
863+
ast::PatBox(ref inner) | ast::PatRegion(ref inner, _) =>
864864
Some(vec![&**inner]),
865865

866866
ast::PatLit(ref expr) => {

src/librustc/middle/mem_categorization.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,8 +1262,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
12621262
}
12631263
}
12641264

1265-
ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => {
1266-
// @p1, ~p1, ref p1
1265+
ast::PatBox(ref subpat) | ast::PatRegion(ref subpat, _) => {
1266+
// box p1, &p1, &mut p1. we can ignore the mutability of
1267+
// PatRegion since that information is already contained
1268+
// in the type.
12671269
let subcmt = try!(self.cat_deref(pat, cmt, 0, false));
12681270
try!(self.cat_pattern_(subcmt, &**subpat, op));
12691271
}

src/librustc_trans/trans/_match.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ fn any_uniq_pat(m: &[Match], col: uint) -> bool {
683683
}
684684

685685
fn any_region_pat(m: &[Match], col: uint) -> bool {
686-
any_pat!(m, col, ast::PatRegion(_))
686+
any_pat!(m, col, ast::PatRegion(..))
687687
}
688688

689689
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>,
17251725
let llbox = Load(bcx, val);
17261726
bcx = bind_irrefutable_pat(bcx, &**inner, llbox, cleanup_scope);
17271727
}
1728-
ast::PatRegion(ref inner) => {
1728+
ast::PatRegion(ref inner, _) => {
17291729
let loaded_val = Load(bcx, val);
17301730
bcx = bind_irrefutable_pat(bcx, &**inner, loaded_val, cleanup_scope);
17311731
}

src/librustc_trans/trans/debuginfo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3472,7 +3472,7 @@ fn create_scope_map(cx: &CrateContext,
34723472
}
34733473
}
34743474

3475-
ast::PatBox(ref sub_pat) | ast::PatRegion(ref sub_pat) => {
3475+
ast::PatBox(ref sub_pat) | ast::PatRegion(ref sub_pat, _) => {
34763476
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
34773477
walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
34783478
}

src/librustc_typeck/check/_match.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,16 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
146146
check_pat(pcx, &**inner, tcx.types.err);
147147
}
148148
}
149-
ast::PatRegion(ref inner) => {
149+
ast::PatRegion(ref inner, mutbl) => {
150150
let inner_ty = fcx.infcx().next_ty_var();
151151

152-
let mutbl =
152+
// SNAP c894171 remove this `if`-`else` entirely after next snapshot
153+
let mutbl = if mutbl == ast::MutImmutable {
153154
ty::deref(fcx.infcx().shallow_resolve(expected), true)
154-
.map_or(ast::MutImmutable, |mt| mt.mutbl);
155+
.map_or(ast::MutImmutable, |mt| mt.mutbl)
156+
} else {
157+
mutbl
158+
};
155159

156160
let mt = ty::mt { ty: inner_ty, mutbl: mutbl };
157161
let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));

src/librustdoc/clean/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2235,7 +2235,7 @@ fn name_from_pat(p: &ast::Pat) -> String {
22352235
PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
22362236
.collect::<Vec<String>>().connect(", ")),
22372237
PatBox(ref p) => name_from_pat(&**p),
2238-
PatRegion(ref p) => name_from_pat(&**p),
2238+
PatRegion(ref p, _) => name_from_pat(&**p),
22392239
PatLit(..) => {
22402240
warn!("tried to get argument name from PatLit, \
22412241
which is silly in function arguments");

src/libsyntax/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ pub enum Pat_ {
556556
PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
557557
PatTup(Vec<P<Pat>>),
558558
PatBox(P<Pat>),
559-
PatRegion(P<Pat>), // reference pattern
559+
PatRegion(P<Pat>, Mutability), // reference pattern
560560
PatLit(P<Expr>),
561561
PatRange(P<Expr>, P<Expr>),
562562
/// [a, b, ..i, y, z] is represented as:

src/libsyntax/ast_util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool {
633633
PatEnum(_, Some(ref s)) | PatTup(ref s) => {
634634
s.iter().all(|p| walk_pat_(&**p, it))
635635
}
636-
PatBox(ref s) | PatRegion(ref s) => {
636+
PatBox(ref s) | PatRegion(ref s, _) => {
637637
walk_pat_(&**s, it)
638638
}
639639
PatVec(ref before, ref slice, ref after) => {

src/libsyntax/ext/deriving/generic/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ impl<'a> MethodDef<'a> {
940940
&**variant,
941941
self_arg_name,
942942
ast::MutImmutable);
943-
(cx.pat(sp, ast::PatRegion(p)), idents)
943+
(cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents)
944944
};
945945

946946
// A single arm has form (&VariantK, &VariantK, ...) => BodyK

src/libsyntax/fold.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1267,7 +1267,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
12671267
}
12681268
PatTup(elts) => PatTup(elts.move_map(|x| folder.fold_pat(x))),
12691269
PatBox(inner) => PatBox(folder.fold_pat(inner)),
1270-
PatRegion(inner) => PatRegion(folder.fold_pat(inner)),
1270+
PatRegion(inner, mutbl) => PatRegion(folder.fold_pat(inner), mutbl),
12711271
PatRange(e1, e2) => {
12721272
PatRange(folder.fold_expr(e1), folder.fold_expr(e2))
12731273
},

src/libsyntax/parse/parser.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3357,11 +3357,16 @@ impl<'a> Parser<'a> {
33573357
})
33583358
}
33593359
token::BinOp(token::And) | token::AndAnd => {
3360-
// parse &pat
3360+
// parse &pat and &mut pat
33613361
let lo = self.span.lo;
33623362
self.expect_and();
3363+
let mutability = if self.eat_keyword(keywords::Mut) {
3364+
ast::MutMutable
3365+
} else {
3366+
ast::MutImmutable
3367+
};
33633368
let sub = self.parse_pat();
3364-
pat = PatRegion(sub);
3369+
pat = PatRegion(sub, mutability);
33653370
hi = self.last_span.hi;
33663371
return P(ast::Pat {
33673372
id: ast::DUMMY_NODE_ID,

src/libsyntax/print/pprust.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2092,8 +2092,11 @@ impl<'a> State<'a> {
20922092
try!(word(&mut self.s, "box "));
20932093
try!(self.print_pat(&**inner));
20942094
}
2095-
ast::PatRegion(ref inner) => {
2095+
ast::PatRegion(ref inner, mutbl) => {
20962096
try!(word(&mut self.s, "&"));
2097+
if mutbl == ast::MutMutable {
2098+
try!(word(&mut self.s, "mut "));
2099+
}
20972100
try!(self.print_pat(&**inner));
20982101
}
20992102
ast::PatLit(ref e) => try!(self.print_expr(&**e)),

src/libsyntax/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
519519
}
520520
}
521521
PatBox(ref subpattern) |
522-
PatRegion(ref subpattern) => {
522+
PatRegion(ref subpattern, _) => {
523523
visitor.visit_pat(&**subpattern)
524524
}
525525
PatIdent(_, ref pth1, ref optional_subpattern) => {

src/libtest/stats.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ impl<T: FloatMath + FromPrimitive> Stats<T> for [T] {
169169
fn sum(&self) -> T {
170170
let mut partials = vec![];
171171

172-
for &mut x in self.iter() {
172+
for &x in self.iter() {
173+
let mut x = x;
173174
let mut j = 0;
174175
// This inner loop applies `hi`/`lo` summation to each
175176
// partial so that the list of partial sums remains exact.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let foo = &mut 1i;
13+
14+
let &mut x = foo;
15+
x += 1; //~ ERROR re-assignment of immutable variable
16+
17+
// explicitly mut-ify internals
18+
let &mut mut x = foo;
19+
x += 1;
20+
21+
// check borrowing is detected successfully
22+
let &mut ref x = foo;
23+
*foo += 1; //~ ERROR cannot assign to `*foo` because it is borrowed
24+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let foo = &mut 1i;
13+
14+
// (separate lines to ensure the spans are accurate)
15+
16+
// SNAP c894171 uncomment this after the next snapshot
17+
// NOTE(stage0) just in case tidy doesn't check SNAP's in tests
18+
// let &_ // ~ ERROR expected `&mut int`, found `&_`
19+
// = foo;
20+
let &mut _ = foo;
21+
22+
let bar = &1i;
23+
let &_ = bar;
24+
let &mut _ //~ ERROR expected `&int`, found `&mut _`
25+
= bar;
26+
}

0 commit comments

Comments
 (0)