From 9f414a44a747edc7dc229e0eaf6fbda5e6ea10e1 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sat, 13 Feb 2016 15:51:27 +0300
Subject: [PATCH] Split ast::PatKind::Enum into tuple struct and path patterns

---
 src/librustc_front/lowering.rs |  5 ++++-
 src/librustc_trans/save/mod.rs |  3 ++-
 src/libsyntax/ast.rs           | 26 ++++++++++++++++----------
 src/libsyntax/ext/build.rs     |  6 +++++-
 src/libsyntax/fold.rs          |  7 +++++--
 src/libsyntax/parse/parser.rs  |  6 +++---
 src/libsyntax/print/pprust.rs  | 15 ++++++++-------
 src/libsyntax/visit.rs         |  5 ++++-
 8 files changed, 47 insertions(+), 26 deletions(-)

diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs
index 9be88a391ec..bb113a7ad6a 100644
--- a/src/librustc_front/lowering.rs
+++ b/src/librustc_front/lowering.rs
@@ -920,11 +920,14 @@ pub fn lower_pat(lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> {
                               sub.as_ref().map(|x| lower_pat(lctx, x)))
             }
             PatKind::Lit(ref e) => hir::PatLit(lower_expr(lctx, e)),
-            PatKind::Enum(ref pth, ref pats) => {
+            PatKind::TupleStruct(ref pth, ref pats) => {
                 hir::PatEnum(lower_path(lctx, pth),
                              pats.as_ref()
                                  .map(|pats| pats.iter().map(|x| lower_pat(lctx, x)).collect()))
             }
+            PatKind::Path(ref pth) => {
+                hir::PatEnum(lower_path(lctx, pth), Some(hir::HirVec::new()))
+            }
             PatKind::QPath(ref qself, ref pth) => {
                 let qself = hir::QSelf {
                     ty: lower_ty(lctx, &qself.ty),
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 6a486501c6b..9c529ccbe00 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -762,7 +762,8 @@ impl<'v> Visitor<'v> for PathCollector {
                 self.collected_paths.push((p.id, path.clone(),
                                            ast::Mutability::Mutable, recorder::TypeRef));
             }
-            PatKind::Enum(ref path, _) |
+            PatKind::TupleStruct(ref path, _) |
+            PatKind::Path(ref path) |
             PatKind::QPath(_, ref path) => {
                 self.collected_paths.push((p.id, path.clone(),
                                            ast::Mutability::Mutable, recorder::VarRef));
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 0a208082e55..cb79c609c1b 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -555,18 +555,27 @@ pub enum PatKind {
     /// Represents a wildcard pattern (`_`)
     Wild,
 
-    /// A PatKind::Ident may either be a new bound variable,
-    /// or a nullary enum (in which case the third field
-    /// is None).
+    /// A `PatKind::Ident` may either be a new bound variable,
+    /// or a unit struct/variant pattern, or a const pattern (in the last two cases
+    /// the third field must be `None`).
     ///
-    /// In the nullary enum case, the parser can't determine
+    /// In the unit or const pattern case, the parser can't determine
     /// which it is. The resolver determines this, and
-    /// records this pattern's NodeId in an auxiliary
-    /// set (of "PatIdents that refer to nullary enums")
+    /// records this pattern's `NodeId` in an auxiliary
+    /// set (of "PatIdents that refer to unit patterns or constants").
     Ident(BindingMode, SpannedIdent, Option<P<Pat>>),
 
+    /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
+    /// 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.
-    Enum(Path, Option<Vec<P<Pat>>>),
+    TupleStruct(Path, Option<Vec<P<Pat>>>),
+
+    /// A path pattern.
+    /// Such pattern can be resolved to a unit struct/variant or a constant.
+    Path(Path),
 
     /// An associated const named using the qualified path `<T>::CONST` or
     /// `<T as Trait>::CONST`. Associated consts from inherent impls can be
@@ -574,9 +583,6 @@ pub enum PatKind {
     /// PatKind::Enum, and the resolver will have to sort that out.
     QPath(QSelf, Path),
 
-    /// Destructuring of a struct, e.g. `Foo {x, y, ..}`
-    /// The `bool` is `true` in the presence of a `..`
-    Struct(Path, Vec<Spanned<FieldPat>>, bool),
     /// A tuple pattern `(a, b)`
     Tup(Vec<P<Pat>>),
     /// A `box` pattern
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 312154e5a8d..0eb42f17f68 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -827,7 +827,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.pat(span, pat)
     }
     fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
-        let pat = PatKind::Enum(path, Some(subpats));
+        let pat = if subpats.is_empty() {
+            PatKind::Path(path)
+        } else {
+            PatKind::TupleStruct(path, Some(subpats))
+        };
         self.pat(span, pat)
     }
     fn pat_struct(&self, span: Span,
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 548d883d93f..d75e8f796ae 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1127,10 +1127,13 @@ 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::Enum(pth, pats) => {
-                PatKind::Enum(folder.fold_path(pth),
+            PatKind::TupleStruct(pth, pats) => {
+                PatKind::TupleStruct(folder.fold_path(pth),
                         pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
             }
+            PatKind::Path(pth) => {
+                PatKind::Path(folder.fold_path(pth))
+            }
             PatKind::QPath(qself, pth) => {
                 let qself = QSelf {ty: folder.fold_ty(qself.ty), .. qself};
                 PatKind::QPath(qself, folder.fold_path(pth))
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index f1de30b373f..a8d35783c6f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3534,14 +3534,14 @@ impl<'a> Parser<'a> {
                             self.bump();
                             self.bump();
                             try!(self.expect(&token::CloseDelim(token::Paren)));
-                            pat = PatKind::Enum(path, None);
+                            pat = PatKind::TupleStruct(path, None);
                         } else {
                             let args = try!(self.parse_enum_variant_seq(
                                     &token::OpenDelim(token::Paren),
                                     &token::CloseDelim(token::Paren),
                                     seq_sep_trailing_allowed(token::Comma),
                                     |p| p.parse_pat()));
-                            pat = PatKind::Enum(path, Some(args));
+                            pat = PatKind::TupleStruct(path, Some(args));
                         }
                       }
                       _ => {
@@ -3549,7 +3549,7 @@ impl<'a> Parser<'a> {
                             // Parse qualified path
                             Some(qself) => PatKind::QPath(qself, path),
                             // Parse nullary enum
-                            None => PatKind::Enum(path, Some(vec![]))
+                            None => PatKind::Path(path)
                         };
                       }
                     }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 5a1a581bc43..b4e08d65a0a 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2478,20 +2478,21 @@ impl<'a> State<'a> {
                     None => ()
                 }
             }
-            PatKind::Enum(ref path, ref args_) => {
+            PatKind::TupleStruct(ref path, ref args_) => {
                 try!(self.print_path(path, true, 0));
                 match *args_ {
                     None => try!(word(&mut self.s, "(..)")),
                     Some(ref args) => {
-                        if !args.is_empty() {
-                            try!(self.popen());
-                            try!(self.commasep(Inconsistent, &args[..],
-                                              |s, p| s.print_pat(&p)));
-                            try!(self.pclose());
-                        }
+                        try!(self.popen());
+                        try!(self.commasep(Inconsistent, &args[..],
+                                          |s, p| s.print_pat(&p)));
+                        try!(self.pclose());
                     }
                 }
             }
+            PatKind::Path(ref path) => {
+                try!(self.print_path(path, true, 0));
+            }
             PatKind::QPath(ref qself, ref path) => {
                 try!(self.print_qpath(path, qself, false));
             }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index bd4e8b70231..f26610b8b8d 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -419,12 +419,15 @@ 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::Enum(ref path, ref opt_children) => {
+        PatKind::TupleStruct(ref path, ref opt_children) => {
             visitor.visit_path(path, pattern.id);
             if let Some(ref children) = *opt_children {
                 walk_list!(visitor, visit_pat, children);
             }
         }
+        PatKind::Path(ref path) => {
+            visitor.visit_path(path, pattern.id);
+        }
         PatKind::QPath(ref qself, ref path) => {
             visitor.visit_ty(&qself.ty);
             visitor.visit_path(path, pattern.id)