From d69aeaf662c637b454e8c7a5ddbd69b4978ec211 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: Implement `..` in tuple (struct) patterns --- src/libsyntax/ast.rs | 16 ++++++----- src/libsyntax/ext/build.rs | 4 +-- src/libsyntax/feature_gate.rs | 24 ++++++++++++++-- src/libsyntax/fold.rs | 8 ++++-- src/libsyntax/parse/parser.rs | 65 +++++++++++++++---------------------------- src/libsyntax/print/pprust.rs | 44 +++++++++++++++++++---------- src/libsyntax/visit.rs | 8 ++---- 7 files changed, 93 insertions(+), 76 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d9409d3bbd9..6eb588767c4 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>, 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>>), + /// A tuple struct/variant pattern `Variant(x, y, .., z)`. + /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// 0 <= position <= subpats.len() + TupleStruct(Path, Vec>, Option), /// 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>), + /// A tuple pattern `(a, b)`. + /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// 0 <= position <= subpats.len() + Tuple(Vec>, Option), /// A `box` pattern Box(P), /// 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 { - self.pat(span, PatKind::Tup(pats)) + self.pat(span, PatKind::Tuple(pats, None)) } fn pat_some(&self, span: Span, pat: P) -> P { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index acef98f2afc..b5bab09c70e 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)] @@ -1021,6 +1023,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 2c325080c0c..c9d23427657 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1115,9 +1115,9 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { 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(p: P, folder: &mut T) -> P { }); 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 fc62cee92fd..a4f12769b5c 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(&mut self, - bra: &token::Token, - ket: &token::Token, - sep: SeqSep, - f: F) - -> PResult<'a, Vec> 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(&mut self, @@ -3433,21 +3414,29 @@ impl<'a> Parser<'a> { }; } - fn parse_pat_tuple_elements(&mut self) -> PResult<'a, Vec>> { + fn parse_pat_tuple_elements(&mut self, unary_needs_comma: bool) + -> PResult<'a, (Vec>, Option)> { 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 { + 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( @@ -3626,9 +3615,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 @@ -3713,20 +3702,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 ebb4927d69c..6c3f3e28727 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 f50a480e5e5..d41d170c084 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -423,11 +423,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); @@ -443,7 +441,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) | -- cgit 1.4.1-3-g733a5 From c038b454239a30cb8a734bcb2ff8a7e5e543939a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: 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 (limited to 'src/libsyntax') 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>, bool), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() TupleStruct(Path, HirVec>, Option), @@ -554,7 +554,7 @@ pub enum PatKind { QPath(QSelf, Path), /// A tuple pattern `(a, b)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() Tuple(HirVec>, Option), /// 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; #[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) -> AjustPos { - AjustPos { +pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option) -> 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>, bool), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() TupleStruct(Path, Vec>, Option), @@ -646,7 +646,7 @@ pub enum PatKind { QPath(QSelf, Path), /// A tuple pattern `(a, b)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() Tuple(Vec>, Option), /// 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license -// , 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(); -} -- cgit 1.4.1-3-g733a5