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.
This commit is contained in:
bors 2015-01-19 19:40:51 +00:00
commit 4032b85aec
3 changed files with 87 additions and 26 deletions

View File

@ -3255,39 +3255,48 @@ fn parse_pat_fields(&mut self) -> (Vec<codemap::Spanned<ast::FieldPat>> , bool)
break;
}
let bind_type = if self.eat_keyword(keywords::Mut) {
BindByValue(MutMutable)
} else if self.eat_keyword(keywords::Ref) {
BindByRef(self.parse_mutability())
} else {
BindByValue(MutImmutable)
};
let fieldname = self.parse_ident();
let (subpat, is_shorthand) = if self.check(&token::Colon) {
match bind_type {
BindByRef(..) | BindByValue(MutMutable) => {
let token_str = self.this_token_to_string();
self.fatal(&format!("unexpected `{}`",
token_str)[])
}
_ => {}
}
// Check if a colon exists one ahead. This means we're parsing a fieldname.
let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
// Parsing a pattern of the form "fieldname: pat"
let fieldname = self.parse_ident();
self.bump();
let pat = self.parse_pat();
hi = pat.span.hi;
(pat, false)
(pat, fieldname, false)
} else {
// Parsing a pattern of the form "(box) (ref) (mut) fieldname"
let is_box = self.eat_keyword(keywords::Box);
let boxed_span_lo = self.span.lo;
let is_ref = self.eat_keyword(keywords::Ref);
let is_mut = self.eat_keyword(keywords::Mut);
let fieldname = self.parse_ident();
hi = self.last_span.hi;
let fieldpath = codemap::Spanned{span:self.last_span, node: fieldname};
(P(ast::Pat {
let bind_type = match (is_ref, is_mut) {
(true, true) => BindByRef(MutMutable),
(true, false) => BindByRef(MutImmutable),
(false, true) => BindByValue(MutMutable),
(false, false) => BindByValue(MutImmutable),
};
let fieldpath = codemap::Spanned{span:self.last_span, node:fieldname};
let fieldpat = P(ast::Pat{
id: ast::DUMMY_NODE_ID,
node: PatIdent(bind_type, fieldpath, None),
span: self.last_span
}), true)
span: mk_sp(boxed_span_lo, hi),
});
let subpat = if is_box {
P(ast::Pat{
id: ast::DUMMY_NODE_ID,
node: PatBox(fieldpat),
span: mk_sp(lo, hi),
})
} else {
fieldpat
};
(subpat, fieldname, true)
};
fields.push(codemap::Spanned { span: mk_sp(lo, hi),
node: ast::FieldPat { ident: fieldname,
pat: subpat,

View File

@ -11,7 +11,7 @@
fn main() {
struct Foo { x: isize }
match (Foo { x: 10 }) {
Foo { ref x: ref x } => {}, //~ ERROR unexpected `:`
Foo { ref x: ref x } => {}, //~ ERROR expected `,`, found `:`
_ => {}
}
}

View File

@ -0,0 +1,52 @@
// 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 <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.
#![feature(box_syntax)]
enum E {
StructVar { boxed: Box<i32> }
}
fn main() {
// Test matching each shorthand notation for field patterns.
let mut a = E::StructVar { boxed: box 3 };
match a {
E::StructVar { box boxed } => { }
}
match a {
E::StructVar { box ref boxed } => { }
}
match a {
E::StructVar { box mut boxed } => { }
}
match a {
E::StructVar { box ref mut boxed } => { }
}
match a {
E::StructVar { ref boxed } => { }
}
match a {
E::StructVar { ref mut boxed } => { }
}
match a {
E::StructVar { mut boxed } => { }
}
// Test matching non shorthand notation. Recreate a since last test
// moved `boxed`
let mut a = E::StructVar { boxed: box 3 };
match a {
E::StructVar { boxed: box ref mut num } => { }
}
match a {
E::StructVar { boxed: ref mut num } => { }
}
}