about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-01-19 19:40:51 +0000
committerbors <bors@rust-lang.org>2015-01-19 19:40:51 +0000
commit4032b85aec962486af7f205e72e93efc8a0bc434 (patch)
treeb51c26c95b0f384bdfa7e7c446918a5e01d5f63e
parent54c9a4655b8c662b5ce3a7ad8a47a4d4d12e78b7 (diff)
parentd8372139a7972cf090d8df29148105fc82a0fc2c (diff)
downloadrust-4032b85aec962486af7f205e72e93efc8a0bc434.tar.gz
rust-4032b85aec962486af7f205e72e93efc8a0bc434.zip
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. 
-rw-r--r--src/libsyntax/parse/parser.rs59
-rw-r--r--src/test/compile-fail/bind-struct-early-modifiers.rs2
-rw-r--r--src/test/run-pass/issue-21033.rs52
3 files changed, 87 insertions, 26 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index b2f6938f513..83a7504bc49 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3255,39 +3255,48 @@ impl<'a> Parser<'a> {
                 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,
diff --git a/src/test/compile-fail/bind-struct-early-modifiers.rs b/src/test/compile-fail/bind-struct-early-modifiers.rs
index 375f6c5d047..c358a21d125 100644
--- a/src/test/compile-fail/bind-struct-early-modifiers.rs
+++ b/src/test/compile-fail/bind-struct-early-modifiers.rs
@@ -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 `:`
         _ => {}
     }
 }
diff --git a/src/test/run-pass/issue-21033.rs b/src/test/run-pass/issue-21033.rs
new file mode 100644
index 00000000000..5dcf1d904d0
--- /dev/null
+++ b/src/test/run-pass/issue-21033.rs
@@ -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 } => { }
+    }
+
+}