Skip to content

Commit 4032b85

Browse files
committed
Auto merge of #21278 - thchittenden:issue-21033-struct-var-pattern-fix, r=alexcrichton
Closes #21033. The new strategy for parsing a field pattern is to look 1 token ahead and if it's a colon, parse as "fieldname: pat", otherwise parse the shorthand form "(box) (ref) (mut) fieldname)". The previous strategy was to parse "(ref) (mut) fieldname" then if we encounter a colon, throw an error if either "ref" or "mut" were encountered.
2 parents 54c9a46 + d837213 commit 4032b85

File tree

3 files changed

+87
-26
lines changed

3 files changed

+87
-26
lines changed

src/libsyntax/parse/parser.rs

+34-25
Original file line numberDiff line numberDiff line change
@@ -3255,39 +3255,48 @@ impl<'a> Parser<'a> {
32553255
break;
32563256
}
32573257

3258-
let bind_type = if self.eat_keyword(keywords::Mut) {
3259-
BindByValue(MutMutable)
3260-
} else if self.eat_keyword(keywords::Ref) {
3261-
BindByRef(self.parse_mutability())
3262-
} else {
3263-
BindByValue(MutImmutable)
3264-
};
3265-
3266-
let fieldname = self.parse_ident();
3267-
3268-
let (subpat, is_shorthand) = if self.check(&token::Colon) {
3269-
match bind_type {
3270-
BindByRef(..) | BindByValue(MutMutable) => {
3271-
let token_str = self.this_token_to_string();
3272-
self.fatal(&format!("unexpected `{}`",
3273-
token_str)[])
3274-
}
3275-
_ => {}
3276-
}
3277-
3258+
// Check if a colon exists one ahead. This means we're parsing a fieldname.
3259+
let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
3260+
// Parsing a pattern of the form "fieldname: pat"
3261+
let fieldname = self.parse_ident();
32783262
self.bump();
32793263
let pat = self.parse_pat();
32803264
hi = pat.span.hi;
3281-
(pat, false)
3265+
(pat, fieldname, false)
32823266
} else {
3267+
// Parsing a pattern of the form "(box) (ref) (mut) fieldname"
3268+
let is_box = self.eat_keyword(keywords::Box);
3269+
let boxed_span_lo = self.span.lo;
3270+
let is_ref = self.eat_keyword(keywords::Ref);
3271+
let is_mut = self.eat_keyword(keywords::Mut);
3272+
let fieldname = self.parse_ident();
32833273
hi = self.last_span.hi;
3284-
let fieldpath = codemap::Spanned{span:self.last_span, node: fieldname};
3285-
(P(ast::Pat {
3274+
3275+
let bind_type = match (is_ref, is_mut) {
3276+
(true, true) => BindByRef(MutMutable),
3277+
(true, false) => BindByRef(MutImmutable),
3278+
(false, true) => BindByValue(MutMutable),
3279+
(false, false) => BindByValue(MutImmutable),
3280+
};
3281+
let fieldpath = codemap::Spanned{span:self.last_span, node:fieldname};
3282+
let fieldpat = P(ast::Pat{
32863283
id: ast::DUMMY_NODE_ID,
32873284
node: PatIdent(bind_type, fieldpath, None),
3288-
span: self.last_span
3289-
}), true)
3285+
span: mk_sp(boxed_span_lo, hi),
3286+
});
3287+
3288+
let subpat = if is_box {
3289+
P(ast::Pat{
3290+
id: ast::DUMMY_NODE_ID,
3291+
node: PatBox(fieldpat),
3292+
span: mk_sp(lo, hi),
3293+
})
3294+
} else {
3295+
fieldpat
3296+
};
3297+
(subpat, fieldname, true)
32903298
};
3299+
32913300
fields.push(codemap::Spanned { span: mk_sp(lo, hi),
32923301
node: ast::FieldPat { ident: fieldname,
32933302
pat: subpat,

src/test/compile-fail/bind-struct-early-modifiers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
fn main() {
1212
struct Foo { x: isize }
1313
match (Foo { x: 10 }) {
14-
Foo { ref x: ref x } => {}, //~ ERROR unexpected `:`
14+
Foo { ref x: ref x } => {}, //~ ERROR expected `,`, found `:`
1515
_ => {}
1616
}
1717
}

src/test/run-pass/issue-21033.rs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
#![feature(box_syntax)]
11+
12+
enum E {
13+
StructVar { boxed: Box<i32> }
14+
}
15+
16+
fn main() {
17+
18+
// Test matching each shorthand notation for field patterns.
19+
let mut a = E::StructVar { boxed: box 3 };
20+
match a {
21+
E::StructVar { box boxed } => { }
22+
}
23+
match a {
24+
E::StructVar { box ref boxed } => { }
25+
}
26+
match a {
27+
E::StructVar { box mut boxed } => { }
28+
}
29+
match a {
30+
E::StructVar { box ref mut boxed } => { }
31+
}
32+
match a {
33+
E::StructVar { ref boxed } => { }
34+
}
35+
match a {
36+
E::StructVar { ref mut boxed } => { }
37+
}
38+
match a {
39+
E::StructVar { mut boxed } => { }
40+
}
41+
42+
// Test matching non shorthand notation. Recreate a since last test
43+
// moved `boxed`
44+
let mut a = E::StructVar { boxed: box 3 };
45+
match a {
46+
E::StructVar { boxed: box ref mut num } => { }
47+
}
48+
match a {
49+
E::StructVar { boxed: ref mut num } => { }
50+
}
51+
52+
}

0 commit comments

Comments
 (0)