about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2016-05-27 09:57:00 +0530
committerManish Goregaokar <manishsmail@gmail.com>2016-05-27 09:57:00 +0530
commit35785712cd5e1acbfebd168c045b2e184ae979cc (patch)
tree2a26d66185c4570f3ab6055860c7f8ce1efad57a /src/libsyntax
parenta70880fea967715e964f459746a77aa9e93dc35f (diff)
parent0ca9bf394006fe635a4a76ca6fa78a70633666f0 (diff)
downloadrust-35785712cd5e1acbfebd168c045b2e184ae979cc.tar.gz
rust-35785712cd5e1acbfebd168c045b2e184ae979cc.zip
Rollup merge of #33639 - petrochenkov:dotdot, r=nmatsakis
 cc https://github.com/rust-lang/rust/issues/33627
r? @nikomatsakis

plugin-[breaking-change] cc https://github.com/rust-lang/rust/issues/31645 @Manishearth
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs16
-rw-r--r--src/libsyntax/ext/build.rs4
-rw-r--r--src/libsyntax/feature_gate.rs24
-rw-r--r--src/libsyntax/fold.rs8
-rw-r--r--src/libsyntax/parse/parser.rs69
-rw-r--r--src/libsyntax/print/pprust.rs44
-rw-r--r--src/libsyntax/visit.rs8
7 files changed, 97 insertions, 76 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 4a94d8b01a3..757b92993cd 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -567,7 +567,7 @@ impl Pat {
             PatKind::Struct(_, ref fields, _) => {
                 fields.iter().all(|field| field.node.pat.walk(it))
             }
-            PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => {
+            PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
                 s.iter().all(|p| p.walk(it))
             }
             PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
@@ -582,7 +582,6 @@ impl Pat {
             PatKind::Lit(_) |
             PatKind::Range(_, _) |
             PatKind::Ident(_, _, _) |
-            PatKind::TupleStruct(..) |
             PatKind::Path(..) |
             PatKind::QPath(_, _) |
             PatKind::Mac(_) => {
@@ -631,9 +630,10 @@ pub enum PatKind {
     /// The `bool` is `true` in the presence of a `..`.
     Struct(Path, Vec<Spanned<FieldPat>>, bool),
 
-    /// A tuple struct/variant pattern `Variant(x, y, z)`.
-    /// "None" means a `Variant(..)` pattern where we don't bind the fields to names.
-    TupleStruct(Path, Option<Vec<P<Pat>>>),
+    /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
+    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
+    /// 0 <= position <= subpats.len()
+    TupleStruct(Path, Vec<P<Pat>>, Option<usize>),
 
     /// A path pattern.
     /// Such pattern can be resolved to a unit struct/variant or a constant.
@@ -645,8 +645,10 @@ pub enum PatKind {
     /// PatKind::Path, and the resolver will have to sort that out.
     QPath(QSelf, Path),
 
-    /// A tuple pattern `(a, b)`
-    Tup(Vec<P<Pat>>),
+    /// A tuple pattern `(a, b)`.
+    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
+    /// 0 <= position <= subpats.len()
+    Tuple(Vec<P<Pat>>, Option<usize>),
     /// A `box` pattern
     Box(P<Pat>),
     /// A reference pattern, e.g. `&mut (a, b)`
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 7958162986c..3a1cdae9bfb 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -832,7 +832,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         let pat = if subpats.is_empty() {
             PatKind::Path(path)
         } else {
-            PatKind::TupleStruct(path, Some(subpats))
+            PatKind::TupleStruct(path, subpats, None)
         };
         self.pat(span, pat)
     }
@@ -842,7 +842,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.pat(span, pat)
     }
     fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
-        self.pat(span, PatKind::Tup(pats))
+        self.pat(span, PatKind::Tuple(pats, None))
     }
 
     fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index dbef06f7aa4..5687099b27c 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -274,7 +274,10 @@ declare_features! (
     (active, drop_types_in_const, "1.9.0", Some(33156)),
 
     // Allows cfg(target_has_atomic = "...").
-    (active, cfg_target_has_atomic, "1.9.0", Some(32976))
+    (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
+
+    // Allows `..` in tuple (struct) patterns
+    (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627))
 );
 
 declare_features! (
@@ -315,7 +318,6 @@ declare_features! (
     // Allows `#[deprecated]` attribute
     (accepted, deprecated, "1.9.0", Some(29935))
 );
-
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
 #[derive(PartialEq, Copy, Clone, Debug)]
@@ -1024,6 +1026,24 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
                                   pattern.span,
                                   "box pattern syntax is experimental");
             }
+            PatKind::Tuple(_, ddpos)
+                    if ddpos.is_some() => {
+                gate_feature_post!(&self, dotdot_in_tuple_patterns,
+                                  pattern.span,
+                                  "`..` in tuple patterns is experimental");
+            }
+            PatKind::TupleStruct(_, ref fields, ddpos)
+                    if ddpos.is_some() && !fields.is_empty() => {
+                gate_feature_post!(&self, dotdot_in_tuple_patterns,
+                                  pattern.span,
+                                  "`..` in tuple struct patterns is experimental");
+            }
+            PatKind::TupleStruct(_, ref fields, ddpos)
+                    if ddpos.is_none() && fields.is_empty() => {
+                self.context.span_handler.struct_span_err(pattern.span,
+                                                          "nullary enum variants are written with \
+                                                           no trailing `( )`").emit();
+            }
             _ => {}
         }
         visit::walk_pat(self, pattern)
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index f25be190537..be43bf5cde2 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1115,9 +1115,9 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
                         sub.map(|x| folder.fold_pat(x)))
             }
             PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)),
-            PatKind::TupleStruct(pth, pats) => {
+            PatKind::TupleStruct(pth, pats, ddpos) => {
                 PatKind::TupleStruct(folder.fold_path(pth),
-                        pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
+                        pats.move_map(|x| folder.fold_pat(x)), ddpos)
             }
             PatKind::Path(pth) => {
                 PatKind::Path(folder.fold_path(pth))
@@ -1138,7 +1138,9 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
                 });
                 PatKind::Struct(pth, fs, etc)
             }
-            PatKind::Tup(elts) => PatKind::Tup(elts.move_map(|x| folder.fold_pat(x))),
+            PatKind::Tuple(elts, ddpos) => {
+                PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos)
+            }
             PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
             PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
             PatKind::Range(e1, e2) => {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index b616b9db9c3..e23c211e687 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -954,25 +954,6 @@ impl<'a> Parser<'a> {
         Ok(result)
     }
 
-    /// Parse a sequence parameter of enum variant. For consistency purposes,
-    /// these should not be empty.
-    pub fn parse_enum_variant_seq<T, F>(&mut self,
-                                        bra: &token::Token,
-                                        ket: &token::Token,
-                                        sep: SeqSep,
-                                        f: F)
-                                        -> PResult<'a, Vec<T>> where
-        F: FnMut(&mut Parser<'a>) -> PResult<'a,  T>,
-    {
-        let result = self.parse_unspanned_seq(bra, ket, sep, f)?;
-        if result.is_empty() {
-            let last_span = self.last_span;
-            self.span_err(last_span,
-            "nullary enum variants are written with no trailing `( )`");
-        }
-        Ok(result)
-    }
-
     // NB: Do not use this function unless you actually plan to place the
     // spanned list in the AST.
     pub fn parse_seq<T, F>(&mut self,
@@ -3434,21 +3415,33 @@ impl<'a> Parser<'a> {
         };
     }
 
-    fn parse_pat_tuple_elements(&mut self) -> PResult<'a, Vec<P<Pat>>> {
+    fn parse_pat_tuple_elements(&mut self, unary_needs_comma: bool)
+                                -> PResult<'a, (Vec<P<Pat>>, Option<usize>)> {
         let mut fields = vec![];
-        if !self.check(&token::CloseDelim(token::Paren)) {
-            fields.push(self.parse_pat()?);
-            if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) {
-                while self.eat(&token::Comma) &&
-                      !self.check(&token::CloseDelim(token::Paren)) {
+        let mut ddpos = None;
+
+        while !self.check(&token::CloseDelim(token::Paren)) {
+            if ddpos.is_none() && self.eat(&token::DotDot) {
+                ddpos = Some(fields.len());
+                if self.eat(&token::Comma) {
+                    // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
                     fields.push(self.parse_pat()?);
                 }
+            } else if ddpos.is_some() && self.eat(&token::DotDot) {
+                // Emit a friendly error, ignore `..` and continue parsing
+                self.span_err(self.last_span, "`..` can only be used once per \
+                                               tuple or tuple struct pattern");
+            } else {
+                fields.push(self.parse_pat()?);
             }
-            if fields.len() == 1 {
+
+            if !self.check(&token::CloseDelim(token::Paren)) ||
+                    (unary_needs_comma && fields.len() == 1 && ddpos.is_none()) {
                 self.expect(&token::Comma)?;
             }
         }
-        Ok(fields)
+
+        Ok((fields, ddpos))
     }
 
     fn parse_pat_vec_elements(
@@ -3627,9 +3620,9 @@ impl<'a> Parser<'a> {
           token::OpenDelim(token::Paren) => {
             // Parse (pat,pat,pat,...) as tuple pattern
             self.bump();
-            let fields = self.parse_pat_tuple_elements()?;
+            let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
             self.expect(&token::CloseDelim(token::Paren))?;
-            pat = PatKind::Tup(fields);
+            pat = PatKind::Tuple(fields, ddpos);
           }
           token::OpenDelim(token::Bracket) => {
             // Parse [pat,pat,...] as slice pattern
@@ -3714,20 +3707,10 @@ impl<'a> Parser<'a> {
                             return Err(self.fatal("unexpected `(` after qualified path"));
                         }
                         // Parse tuple struct or enum pattern
-                        if self.look_ahead(1, |t| *t == token::DotDot) {
-                            // This is a "top constructor only" pat
-                            self.bump();
-                            self.bump();
-                            self.expect(&token::CloseDelim(token::Paren))?;
-                            pat = PatKind::TupleStruct(path, None);
-                        } else {
-                            let args = self.parse_enum_variant_seq(
-                                &token::OpenDelim(token::Paren),
-                                &token::CloseDelim(token::Paren),
-                                SeqSep::trailing_allowed(token::Comma),
-                                |p| p.parse_pat())?;
-                            pat = PatKind::TupleStruct(path, Some(args));
-                        }
+                        self.bump();
+                        let (fields, ddpos) = self.parse_pat_tuple_elements(false)?;
+                        self.expect(&token::CloseDelim(token::Paren))?;
+                        pat = PatKind::TupleStruct(path, fields, ddpos)
                       }
                       _ => {
                         pat = match qself {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index fec84e912d4..647378174fa 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2472,17 +2472,23 @@ impl<'a> State<'a> {
                     None => ()
                 }
             }
-            PatKind::TupleStruct(ref path, ref args_) => {
+            PatKind::TupleStruct(ref path, ref elts, ddpos) => {
                 self.print_path(path, true, 0)?;
-                match *args_ {
-                    None => word(&mut self.s, "(..)")?,
-                    Some(ref args) => {
-                        self.popen()?;
-                        self.commasep(Inconsistent, &args[..],
-                                          |s, p| s.print_pat(&p))?;
-                        self.pclose()?;
+                self.popen()?;
+                if let Some(ddpos) = ddpos {
+                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
+                    if ddpos != 0 {
+                        self.word_space(",")?;
+                    }
+                    word(&mut self.s, "..")?;
+                    if ddpos != elts.len() {
+                        word(&mut self.s, ",")?;
+                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
                     }
+                } else {
+                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
                 }
+                self.pclose()?;
             }
             PatKind::Path(ref path) => {
                 self.print_path(path, true, 0)?;
@@ -2513,13 +2519,23 @@ impl<'a> State<'a> {
                 space(&mut self.s)?;
                 word(&mut self.s, "}")?;
             }
-            PatKind::Tup(ref elts) => {
+            PatKind::Tuple(ref elts, ddpos) => {
                 self.popen()?;
-                self.commasep(Inconsistent,
-                                   &elts[..],
-                                   |s, p| s.print_pat(&p))?;
-                if elts.len() == 1 {
-                    word(&mut self.s, ",")?;
+                if let Some(ddpos) = ddpos {
+                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
+                    if ddpos != 0 {
+                        self.word_space(",")?;
+                    }
+                    word(&mut self.s, "..")?;
+                    if ddpos != elts.len() {
+                        word(&mut self.s, ",")?;
+                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
+                    }
+                } else {
+                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
+                    if elts.len() == 1 {
+                        word(&mut self.s, ",")?;
+                    }
                 }
                 self.pclose()?;
             }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 3bd300a8e8c..98e0322cb6d 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -430,11 +430,9 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
 
 pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
     match pattern.node {
-        PatKind::TupleStruct(ref path, ref opt_children) => {
+        PatKind::TupleStruct(ref path, ref children, _) => {
             visitor.visit_path(path, pattern.id);
-            if let Some(ref children) = *opt_children {
-                walk_list!(visitor, visit_pat, children);
-            }
+            walk_list!(visitor, visit_pat, children);
         }
         PatKind::Path(ref path) => {
             visitor.visit_path(path, pattern.id);
@@ -450,7 +448,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
                 visitor.visit_pat(&field.node.pat)
             }
         }
-        PatKind::Tup(ref tuple_elements) => {
+        PatKind::Tuple(ref tuple_elements, _) => {
             walk_list!(visitor, visit_pat, tuple_elements);
         }
         PatKind::Box(ref subpattern) |