From c038b454239a30cb8a734bcb2ff8a7e5e543939a Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sun, 6 Mar 2016 15:54:44 +0300
Subject: [PATCH] Address review comments

---
 src/librustc/hir/mod.rs            |   4 +-
 src/librustc/hir/pat_util.rs       |   8 +-
 src/libsyntax/ast.rs               |   4 +-
 src/libsyntax/parse/parser.rs      |   4 +
 src/test/parse-fail/pat-tuple-3.rs |   2 +-
 src/test/run-pass/pat-tuple-1.rs   | 104 +++++++++++++++
 src/test/run-pass/pat-tuple-2.rs   |  34 +++++
 src/test/run-pass/pat-tuple-3.rs   |  40 ++++++
 src/test/run-pass/pat-tuple-4.rs   |  68 ++++++++++
 src/test/run-pass/pat-tuple-5.rs   |  40 ++++++
 src/test/run-pass/pat-tuple-6.rs   |  56 ++++++++
 src/test/run-pass/pat-tuple.rs     | 202 -----------------------------
 12 files changed, 355 insertions(+), 211 deletions(-)
 create mode 100644 src/test/run-pass/pat-tuple-1.rs
 create mode 100644 src/test/run-pass/pat-tuple-2.rs
 create mode 100644 src/test/run-pass/pat-tuple-3.rs
 create mode 100644 src/test/run-pass/pat-tuple-4.rs
 create mode 100644 src/test/run-pass/pat-tuple-5.rs
 create mode 100644 src/test/run-pass/pat-tuple-6.rs
 delete mode 100644 src/test/run-pass/pat-tuple.rs

diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 961885d1b86..dff17d8c17b 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -539,7 +539,7 @@ pub enum PatKind {
     Struct(Path, HirVec<Spanned<FieldPat>>, bool),
 
     /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
-    /// If the `..` pattern fragment presents, then `Option<usize>` denotes its position.
+    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
     /// 0 <= position <= subpats.len()
     TupleStruct(Path, HirVec<P<Pat>>, Option<usize>),
 
@@ -554,7 +554,7 @@ pub enum PatKind {
     QPath(QSelf, Path),
 
     /// A tuple pattern `(a, b)`.
-    /// If the `..` pattern fragment presents, then `Option<usize>` denotes its position.
+    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
     /// 0 <= position <= subpats.len()
     Tuple(HirVec<P<Pat>>, Option<usize>),
     /// A `box` pattern
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index f41c4b0840d..cf4842a25d6 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -22,12 +22,12 @@ use std::cell::RefCell;
 pub type PatIdMap = FnvHashMap<ast::Name, ast::NodeId>;
 
 #[derive(Clone, Copy)]
-pub struct AjustPos {
+pub struct AdjustPos {
     gap_pos: usize,
     gap_len: usize,
 }
 
-impl FnOnce<(usize,)> for AjustPos {
+impl FnOnce<(usize,)> for AdjustPos {
     type Output = usize;
     extern "rust-call" fn call_once(self, (i,): (usize,)) -> usize {
         if i < self.gap_pos { i } else { i + self.gap_len }
@@ -36,8 +36,8 @@ impl FnOnce<(usize,)> for AjustPos {
 
 // Returns a functional object used to adjust tuple pattern indexes. Example: for 5-tuple and
 // pattern (a, b, .., c) expected_len is 5, actual_len is 3 and gap_pos is Some(2).
-pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option<usize>) -> AjustPos {
-    AjustPos {
+pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option<usize>) -> AdjustPos {
+    AdjustPos {
         gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len },
         gap_len: expected_len - actual_len,
     }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 6eb588767c4..7c3c33c28f6 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -631,7 +631,7 @@ pub enum PatKind {
     Struct(Path, Vec<Spanned<FieldPat>>, bool),
 
     /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
-    /// If the `..` pattern fragment presents, then `Option<usize>` denotes its position.
+    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
     /// 0 <= position <= subpats.len()
     TupleStruct(Path, Vec<P<Pat>>, Option<usize>),
 
@@ -646,7 +646,7 @@ pub enum PatKind {
     QPath(QSelf, Path),
 
     /// A tuple pattern `(a, b)`.
-    /// If the `..` pattern fragment presents, then `Option<usize>` denotes its position.
+    /// 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
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index a4f12769b5c..943910b1570 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3426,6 +3426,10 @@ impl<'a> Parser<'a> {
                     // `..` 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()?);
             }
diff --git a/src/test/parse-fail/pat-tuple-3.rs b/src/test/parse-fail/pat-tuple-3.rs
index 95e44ae134c..029dc7a2956 100644
--- a/src/test/parse-fail/pat-tuple-3.rs
+++ b/src/test/parse-fail/pat-tuple-3.rs
@@ -12,6 +12,6 @@
 
 fn main() {
     match 0 {
-        (.., pat, ..) => {} //~ ERROR expected pattern, found `..`
+        (.., pat, ..) => {} //~ ERROR `..` can only be used once per tuple or tuple struct pattern
     }
 }
diff --git a/src/test/run-pass/pat-tuple-1.rs b/src/test/run-pass/pat-tuple-1.rs
new file mode 100644
index 00000000000..c3796210a8e
--- /dev/null
+++ b/src/test/run-pass/pat-tuple-1.rs
@@ -0,0 +1,104 @@
+// Copyright 2016 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(dotdot_in_tuple_patterns)]
+
+fn tuple() {
+    let x = (1, 2, 3);
+    match x {
+        (a, b, ..) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+        }
+    }
+    match x {
+        (.., b, c) => {
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+        }
+    }
+    match x {
+        (a, .., c) => {
+            assert_eq!(a, 1);
+            assert_eq!(c, 3);
+        }
+    }
+    match x {
+        (a, b, c) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+        }
+    }
+    match x {
+        (a, b, c, ..) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+        }
+    }
+    match x {
+        (.., a, b, c) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+        }
+    }
+}
+
+fn tuple_struct() {
+    struct S(u8, u8, u8);
+
+    let x = S(1, 2, 3);
+    match x {
+        S(a, b, ..) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+        }
+    }
+    match x {
+        S(.., b, c) => {
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+        }
+    }
+    match x {
+        S(a, .., c) => {
+            assert_eq!(a, 1);
+            assert_eq!(c, 3);
+        }
+    }
+    match x {
+        S(a, b, c) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+        }
+    }
+    match x {
+        S(a, b, c, ..) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+        }
+    }
+    match x {
+        S(.., a, b, c) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+        }
+    }
+}
+
+fn main() {
+    tuple();
+    tuple_struct();
+}
diff --git a/src/test/run-pass/pat-tuple-2.rs b/src/test/run-pass/pat-tuple-2.rs
new file mode 100644
index 00000000000..881e96a9d78
--- /dev/null
+++ b/src/test/run-pass/pat-tuple-2.rs
@@ -0,0 +1,34 @@
+// Copyright 2016 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(dotdot_in_tuple_patterns)]
+
+fn tuple() {
+    let x = (1,);
+    match x {
+        (2, ..) => panic!(),
+        (..) => ()
+    }
+}
+
+fn tuple_struct() {
+    struct S(u8);
+
+    let x = S(1);
+    match x {
+        S(2, ..) => panic!(),
+        S(..) => ()
+    }
+}
+
+fn main() {
+    tuple();
+    tuple_struct();
+}
diff --git a/src/test/run-pass/pat-tuple-3.rs b/src/test/run-pass/pat-tuple-3.rs
new file mode 100644
index 00000000000..94d33d41899
--- /dev/null
+++ b/src/test/run-pass/pat-tuple-3.rs
@@ -0,0 +1,40 @@
+// Copyright 2016 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(dotdot_in_tuple_patterns)]
+
+fn tuple() {
+    let x = (1, 2, 3);
+    let branch = match x {
+        (1, 1, ..) => 0,
+        (1, 2, 3, ..) => 1,
+        (1, 2, ..) => 2,
+        _ => 3
+    };
+    assert_eq!(branch, 1);
+}
+
+fn tuple_struct() {
+    struct S(u8, u8, u8);
+
+    let x = S(1, 2, 3);
+    let branch = match x {
+        S(1, 1, ..) => 0,
+        S(1, 2, 3, ..) => 1,
+        S(1, 2, ..) => 2,
+        _ => 3
+    };
+    assert_eq!(branch, 1);
+}
+
+fn main() {
+    tuple();
+    tuple_struct();
+}
diff --git a/src/test/run-pass/pat-tuple-4.rs b/src/test/run-pass/pat-tuple-4.rs
new file mode 100644
index 00000000000..ffd82fea996
--- /dev/null
+++ b/src/test/run-pass/pat-tuple-4.rs
@@ -0,0 +1,68 @@
+// Copyright 2016 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(dotdot_in_tuple_patterns)]
+
+fn tuple() {
+    let x = (1, 2, 3);
+    match x {
+        (1, 2, 4) => unreachable!(),
+        (0, 2, 3, ..) => unreachable!(),
+        (0, .., 3) => unreachable!(),
+        (0, ..) => unreachable!(),
+        (1, 2, 3) => (),
+        (_, _, _) => unreachable!(),
+    }
+    match x {
+        (..) => (),
+    }
+    match x {
+        (_, _, _, ..) => (),
+    }
+    match x {
+        (a, b, c) => {
+            assert_eq!(1, a);
+            assert_eq!(2, b);
+            assert_eq!(3, c);
+        }
+    }
+}
+
+fn tuple_struct() {
+    struct S(u8, u8, u8);
+
+    let x = S(1, 2, 3);
+    match x {
+        S(1, 2, 4) => unreachable!(),
+        S(0, 2, 3, ..) => unreachable!(),
+        S(0, .., 3) => unreachable!(),
+        S(0, ..) => unreachable!(),
+        S(1, 2, 3) => (),
+        S(_, _, _) => unreachable!(),
+    }
+    match x {
+        S(..) => (),
+    }
+    match x {
+        S(_, _, _, ..) => (),
+    }
+    match x {
+        S(a, b, c) => {
+            assert_eq!(1, a);
+            assert_eq!(2, b);
+            assert_eq!(3, c);
+        }
+    }
+}
+
+fn main() {
+    tuple();
+    tuple_struct();
+}
diff --git a/src/test/run-pass/pat-tuple-5.rs b/src/test/run-pass/pat-tuple-5.rs
new file mode 100644
index 00000000000..41c4d02abcb
--- /dev/null
+++ b/src/test/run-pass/pat-tuple-5.rs
@@ -0,0 +1,40 @@
+// Copyright 2016 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(dotdot_in_tuple_patterns)]
+
+fn tuple() {
+    struct S;
+    struct Z;
+    struct W;
+    let x = (S, Z, W);
+    match x { (S, ..) => {} }
+    match x { (.., W) => {} }
+    match x { (S, .., W) => {} }
+    match x { (.., Z, _) => {} }
+}
+
+fn tuple_struct() {
+    struct SS(S, Z, W);
+
+    struct S;
+    struct Z;
+    struct W;
+    let x = SS(S, Z, W);
+    match x { SS(S, ..) => {} }
+    match x { SS(.., W) => {} }
+    match x { SS(S, .., W) => {} }
+    match x { SS(.., Z, _) => {} }
+}
+
+fn main() {
+    tuple();
+    tuple_struct();
+}
diff --git a/src/test/run-pass/pat-tuple-6.rs b/src/test/run-pass/pat-tuple-6.rs
new file mode 100644
index 00000000000..6f3f2b3aed5
--- /dev/null
+++ b/src/test/run-pass/pat-tuple-6.rs
@@ -0,0 +1,56 @@
+// Copyright 2016 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(dotdot_in_tuple_patterns)]
+
+fn tuple() {
+    let x = (1, 2, 3, 4, 5);
+    match x {
+        (a, .., b, c) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 4);
+            assert_eq!(c, 5);
+        }
+    }
+    match x {
+        (a, b, c, .., d) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+            assert_eq!(d, 5);
+        }
+    }
+}
+
+fn tuple_struct() {
+    struct S(u8, u8, u8, u8, u8);
+
+    let x = S(1, 2, 3, 4, 5);
+    match x {
+        S(a, .., b, c) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 4);
+            assert_eq!(c, 5);
+        }
+    }
+    match x {
+        S(a, b, c, .., d) => {
+            assert_eq!(a, 1);
+            assert_eq!(b, 2);
+            assert_eq!(c, 3);
+            assert_eq!(d, 5);
+        }
+    }
+}
+
+fn main() {
+    tuple();
+    tuple_struct();
+}
diff --git a/src/test/run-pass/pat-tuple.rs b/src/test/run-pass/pat-tuple.rs
deleted file mode 100644
index ccea068f715..00000000000
--- a/src/test/run-pass/pat-tuple.rs
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright 2016 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(dotdot_in_tuple_patterns)]
-
-fn b() {
-    let x = (1, 2, 3);
-    match x {
-        (a, b, ..) => {
-            assert_eq!(a, 1);
-            assert_eq!(b, 2);
-        }
-    }
-    match x {
-        (.., b, c) => {
-            assert_eq!(b, 2);
-            assert_eq!(c, 3);
-        }
-    }
-    match x {
-        (a, .., c) => {
-            assert_eq!(a, 1);
-            assert_eq!(c, 3);
-        }
-    }
-    match x {
-        (a, b, c) => {
-            assert_eq!(a, 1);
-            assert_eq!(b, 2);
-            assert_eq!(c, 3);
-        }
-    }
-}
-
-fn bs() {
-    struct S(u8, u8, u8);
-
-    let x = S(1, 2, 3);
-    match x {
-        S(a, b, ..) => {
-            assert_eq!(a, 1);
-            assert_eq!(b, 2);
-        }
-    }
-    match x {
-        S(.., b, c) => {
-            assert_eq!(b, 2);
-            assert_eq!(c, 3);
-        }
-    }
-    match x {
-        S(a, .., c) => {
-            assert_eq!(a, 1);
-            assert_eq!(c, 3);
-        }
-    }
-    match x {
-        S(a, b, c) => {
-            assert_eq!(a, 1);
-            assert_eq!(b, 2);
-            assert_eq!(c, 3);
-        }
-    }
-}
-
-fn c() {
-    let x = (1,);
-    match x {
-        (2, ..) => panic!(),
-        (..) => ()
-    }
-}
-
-fn cs() {
-    struct S(u8);
-
-    let x = S(1);
-    match x {
-        S(2, ..) => panic!(),
-        S(..) => ()
-    }
-}
-
-fn d() {
-    let x = (1, 2, 3);
-    let branch = match x {
-        (1, 1, ..) => 0,
-        (1, 2, 3, ..) => 1,
-        (1, 2, ..) => 2,
-        _ => 3
-    };
-    assert_eq!(branch, 1);
-}
-
-fn ds() {
-    struct S(u8, u8, u8);
-
-    let x = S(1, 2, 3);
-    let branch = match x {
-        S(1, 1, ..) => 0,
-        S(1, 2, 3, ..) => 1,
-        S(1, 2, ..) => 2,
-        _ => 3
-    };
-    assert_eq!(branch, 1);
-}
-
-fn f() {
-    let x = (1, 2, 3);
-    match x {
-        (1, 2, 4) => unreachable!(),
-        (0, 2, 3, ..) => unreachable!(),
-        (0, .., 3) => unreachable!(),
-        (0, ..) => unreachable!(),
-        (1, 2, 3) => (),
-        (_, _, _) => unreachable!(),
-    }
-    match x {
-        (..) => (),
-    }
-    match x {
-        (_, _, _, ..) => (),
-    }
-    match x {
-        (a, b, c) => {
-            assert_eq!(1, a);
-            assert_eq!(2, b);
-            assert_eq!(3, c);
-        }
-    }
-}
-
-fn fs() {
-    struct S(u8, u8, u8);
-
-    let x = S(1, 2, 3);
-    match x {
-        S(1, 2, 4) => unreachable!(),
-        S(0, 2, 3, ..) => unreachable!(),
-        S(0, .., 3) => unreachable!(),
-        S(0, ..) => unreachable!(),
-        S(1, 2, 3) => (),
-        S(_, _, _) => unreachable!(),
-    }
-    match x {
-        S(..) => (),
-    }
-    match x {
-        S(_, _, _, ..) => (),
-    }
-    match x {
-        S(a, b, c) => {
-            assert_eq!(1, a);
-            assert_eq!(2, b);
-            assert_eq!(3, c);
-        }
-    }
-}
-
-fn g() {
-    struct S;
-    struct Z;
-    struct W;
-    let x = (S, Z, W);
-    match x { (S, ..) => {} }
-    match x { (.., W) => {} }
-    match x { (S, .., W) => {} }
-    match x { (.., Z, _) => {} }
-}
-
-fn gs() {
-    struct SS(S, Z, W);
-
-    struct S;
-    struct Z;
-    struct W;
-    let x = SS(S, Z, W);
-    match x { SS(S, ..) => {} }
-    match x { SS(.., W) => {} }
-    match x { SS(S, .., W) => {} }
-    match x { SS(.., Z, _) => {} }
-}
-
-fn main() {
-    b();
-    bs();
-    c();
-    cs();
-    d();
-    ds();
-    f();
-    fs();
-    g();
-    gs();
-}