From 35e6c0252422b178cc3b21f7f1510c80bcd064c8 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 1 Nov 2013 18:02:30 -0700 Subject: [PATCH 1/2] Use '..' as multi-field wildcard in enums and structs. --- src/libsyntax/parse/obsolete.rs | 10 +++++ src/libsyntax/parse/parser.rs | 17 ++++++++- src/test/run-pass/ignore-all-the-things.rs | 44 ++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/ignore-all-the-things.rs diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 20ad13dace6..8fb96a3e07a 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -39,6 +39,8 @@ pub enum ObsoleteSyntax { ObsoleteConstPointer, ObsoleteEmptyImpl, ObsoleteLoopAsContinue, + ObsoleteEnumWildcard, + ObsoleteStructWildcard } impl to_bytes::IterBytes for ObsoleteSyntax { @@ -113,6 +115,14 @@ impl ParserObsoleteMethods for Parser { "`loop` is now only used for loops and `continue` is used for \ skipping iterations" ), + ObsoleteEnumWildcard => ( + "enum wildcard", + "use `..` instead of `*` for matching all enum fields" + ), + ObsoleteStructWildcard => ( + "struct wildcard", + "use `..` instead of `_` for matching trailing struct fields" + ), }; self.report(sp, kind, kind_str, desc); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ad5da0b9289..ea861305d9f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2755,7 +2755,12 @@ impl Parser { if first { first = false; } else { self.expect(&token::COMMA); } + etc = *self.token == token::UNDERSCORE || *self.token == token::DOTDOT; if *self.token == token::UNDERSCORE { + // FIXME #5830 activate after snapshot + // self.obsolete(*self.span, ObsoleteStructWildcard); + } + if etc { self.bump(); if *self.token != token::RBRACE { self.fatal( @@ -3016,9 +3021,19 @@ impl Parser { _ => false, } }; - if is_star { + let is_dotdot = do self.look_ahead(1) |t| { + match *t { + token::DOTDOT => true, + _ => false, + } + }; + if is_star | is_dotdot { // This is a "top constructor only" pat self.bump(); + if is_star { + // FIXME #5830 activate after snapshot + // self.obsolete(*self.span, ObsoleteEnumWildcard); + } self.bump(); self.expect(&token::RPAREN); pat = PatEnum(enum_path, None); diff --git a/src/test/run-pass/ignore-all-the-things.rs b/src/test/run-pass/ignore-all-the-things.rs new file mode 100644 index 00000000000..b71f139c684 --- /dev/null +++ b/src/test/run-pass/ignore-all-the-things.rs @@ -0,0 +1,44 @@ +// Copyright 2012 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. + +struct Foo(int, int, int, int); +struct Bar{a: int, b: int, c: int, d: int} + +pub fn main() { + let Foo(..) = Foo(5, 5, 5, 5); + let Foo(*) = Foo(5, 5, 5, 5); + let Bar{..} = Bar{a: 5, b: 5, c: 5, d: 5}; + let Bar{_} = Bar{a: 5, b: 5, c: 5, d: 5}; + //let (..) = (5, 5, 5, 5); + //let Foo(a, b, ..) = Foo(5, 5, 5, 5); + //let Foo(.., d) = Foo(5, 5, 5, 5); + //let (a, b, ..) = (5, 5, 5, 5); + //let (.., c, d) = (5, 5, 5, 5); + let Bar{b: b, ..} = Bar{a: 5, b: 5, c: 5, d: 5}; + let Bar{b: b, _} = Bar{a: 5, b: 5, c: 5, d: 5}; + /*match [5, 5, 5, 5] { + [a, ..] => { } + }*/ + /*match [5, 5, 5, 5] { + [.., b] => { } + }*/ + /*match [5, 5, 5, 5] { + [a, .., b] => { } + }*/ + match [5, 5, 5] { + [a, .._] => { } + } + match [5, 5, 5] { + [.._, a] => { } + } + match [5, 5, 5] { + [a, .._, b] => { } + } +} From 85f107d8cba0560e1edce8ad7158024f2489ca3b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 7 Nov 2013 19:25:39 -0800 Subject: [PATCH 2/2] Use '..' as slice wildcard in vectors --- src/librustc/middle/cfg/construct.rs | 2 +- src/librustc/middle/check_match.rs | 13 +++++-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/pat_util.rs | 2 +- src/librustc/middle/trans/_match.rs | 4 +- src/librustc/middle/trans/debuginfo.rs | 2 +- src/librustc/middle/typeck/check/_match.rs | 2 +- src/librustc/middle/typeck/check/regionck.rs | 2 +- src/librustdoc/clean.rs | 1 + src/libsyntax/ast.rs | 1 + src/libsyntax/ast_util.rs | 2 +- src/libsyntax/fold.rs | 1 + src/libsyntax/parse/obsolete.rs | 7 +++- src/libsyntax/parse/parser.rs | 40 ++++++++++++++------ src/libsyntax/print/pprust.rs | 8 +++- src/libsyntax/visit.rs | 2 +- src/test/run-pass/ignore-all-the-things.rs | 18 ++++++--- 17 files changed, 77 insertions(+), 32 deletions(-) diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index fce318f173e..e014f41edcd 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -97,7 +97,7 @@ impl CFGBuilder { ast::PatEnum(_, None) | ast::PatLit(*) | ast::PatRange(*) | - ast::PatWild => { + ast::PatWild | ast::PatWildMulti => { self.add_node(pat.id, [pred]) } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 482ba43ae25..3885ebfc4b6 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -333,7 +333,7 @@ fn is_useful_specialized(cx: &MatchCheckCtxt, fn pat_ctor_id(cx: &MatchCheckCtxt, p: @Pat) -> Option { let pat = raw_pat(p); match pat.node { - PatWild => { None } + PatWild | PatWildMulti => { None } PatIdent(_, _, _) | PatEnum(_, _) => { match cx.tcx.def_map.find(&pat.id) { Some(&DefVariant(_, id, _)) => Some(variant(id)), @@ -369,7 +369,7 @@ fn pat_ctor_id(cx: &MatchCheckCtxt, p: @Pat) -> Option { fn is_wild(cx: &MatchCheckCtxt, p: @Pat) -> bool { let pat = raw_pat(p); match pat.node { - PatWild => { true } + PatWild | PatWildMulti => { true } PatIdent(_, _, _) => { match cx.tcx.def_map.find(&pat.id) { Some(&DefVariant(_, _, _)) | Some(&DefStatic(*)) => { false } @@ -532,6 +532,10 @@ fn wild() -> @Pat { @Pat {id: 0, node: PatWild, span: dummy_sp()} } +fn wild_multi() -> @Pat { + @Pat {id: 0, node: PatWildMulti, span: dummy_sp()} +} + fn specialize(cx: &MatchCheckCtxt, r: &[@Pat], ctor_id: &ctor, @@ -546,6 +550,9 @@ fn specialize(cx: &MatchCheckCtxt, PatWild => { Some(vec::append(vec::from_elem(arity, wild()), r.tail())) } + PatWildMulti => { + Some(vec::append(vec::from_elem(arity, wild_multi()), r.tail())) + } PatIdent(_, _, _) => { match cx.tcx.def_map.find(&pat_id) { Some(&DefVariant(_, id, _)) => { @@ -849,7 +856,7 @@ fn is_refutable(cx: &MatchCheckCtxt, pat: &Pat) -> bool { PatIdent(_, _, Some(sub)) => { is_refutable(cx, sub) } - PatWild | PatIdent(_, _, None) => { false } + PatWild | PatWildMulti | PatIdent(_, _, None) => { false } PatLit(@Expr {node: ExprLit(@Spanned { node: lit_nil, _}), _}) => { // "()" false diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index bd2f69a1d03..d8f66419379 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -876,7 +876,7 @@ impl mem_categorization_ctxt { op(cmt, pat); match pat.node { - ast::PatWild => { + ast::PatWild | ast::PatWildMulti => { // _ } diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index acdadacc083..878f0876918 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -65,7 +65,7 @@ pub fn pat_is_binding(dm: resolve::DefMap, pat: @Pat) -> bool { pub fn pat_is_binding_or_wild(dm: resolve::DefMap, pat: @Pat) -> bool { match pat.node { PatIdent(*) => pat_is_binding(dm, pat), - PatWild => true, + PatWild | PatWildMulti => true, _ => false } } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 9dddf96e34d..b48260de766 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -545,7 +545,7 @@ fn enter_default<'r>(bcx: @mut Block, // Collect all of the matches that can match against anything. let matches = do enter_match(bcx, dm, m, col, val) |p| { match p.node { - ast::PatWild | ast::PatTup(_) => Some(~[]), + ast::PatWild | ast::PatWildMulti | ast::PatTup(_) => Some(~[]), ast::PatIdent(_, _, None) if pat_is_binding(dm, p) => Some(~[]), _ => None } @@ -2234,7 +2234,7 @@ fn bind_irrefutable_pat(bcx: @mut Block, pat.span, format!("vector patterns are never irrefutable!")); } - ast::PatWild | ast::PatLit(_) | ast::PatRange(_, _) => () + ast::PatWild | ast::PatWildMulti | ast::PatLit(_) | ast::PatRange(_, _) => () } return bcx; } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index c6a33864620..6c010e4f85b 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -2418,7 +2418,7 @@ fn populate_scope_map(cx: &mut CrateContext, } } - ast::PatWild => { + ast::PatWild | ast::PatWildMulti => { scope_map.insert(pat.id, scope_stack.last().scope_metadata); } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 93c3d94f5dc..63f439e43e3 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -414,7 +414,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::Pat, expected: ty::t) { let tcx = pcx.fcx.ccx.tcx; match pat.node { - ast::PatWild => { + ast::PatWild | ast::PatWildMulti => { fcx.write_ty(pat.id, expected); } ast::PatLit(lt) => { diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index b21d36777c2..c3827037f15 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -1219,7 +1219,7 @@ pub mod guarantor { rcx.fcx.pat_to_str(pat), guarantor); match pat.node { - ast::PatWild => {} + ast::PatWild | ast::PatWildMulti => {} ast::PatIdent(ast::BindByRef(_), _, opt_p) => { link(rcx, pat.span, pat.id, guarantor); diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index f48ad25712d..f0f2ca2db33 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -1137,6 +1137,7 @@ fn name_from_pat(p: &ast::Pat) -> ~str { use syntax::ast::*; match p.node { PatWild => ~"_", + PatWildMulti => ~"..", PatIdent(_, ref p, _) => path_to_str(p), PatEnum(ref p, _) => path_to_str(p), PatStruct(*) => fail!("tried to get argument name from pat_struct, \ diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 88a8bbf7cf2..79cf52d8da7 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -337,6 +337,7 @@ pub enum BindingMode { #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] pub enum Pat_ { PatWild, + PatWildMulti, // A pat_ident may either be a new bound variable, // or a nullary enum (in which case the second field // is None). diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index ccae25dc012..fb50a890c43 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -657,7 +657,7 @@ pub fn walk_pat(pat: @Pat, it: &fn(@Pat) -> bool) -> bool { slice.iter().advance(|&p| walk_pat(p, |p| it(p))) && after.iter().advance(|&p| walk_pat(p, |p| it(p))) } - PatWild | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) | + PatWild | PatWildMulti | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) | PatEnum(_, _) => { true } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index ea0ab95a451..bd99f58cde9 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -174,6 +174,7 @@ pub trait ast_fold { fn fold_pat(&self, p: @Pat) -> @Pat { let node = match p.node { PatWild => PatWild, + PatWildMulti => PatWildMulti, PatIdent(binding_mode, ref pth, ref sub) => { PatIdent(binding_mode, self.fold_path(pth), diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 8fb96a3e07a..2af6d141aa1 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -40,7 +40,8 @@ pub enum ObsoleteSyntax { ObsoleteEmptyImpl, ObsoleteLoopAsContinue, ObsoleteEnumWildcard, - ObsoleteStructWildcard + ObsoleteStructWildcard, + ObsoleteVecDotDotWildcard } impl to_bytes::IterBytes for ObsoleteSyntax { @@ -123,6 +124,10 @@ impl ParserObsoleteMethods for Parser { "struct wildcard", "use `..` instead of `_` for matching trailing struct fields" ), + ObsoleteVecDotDotWildcard => ( + "vec slice wildcard", + "use `..` instead of `.._` for matching slices" + ), }; self.report(sp, kind, kind_str, desc); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ea861305d9f..1b2e18f3ca5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,7 +43,7 @@ use ast::{MutImmutable, MutMutable, mac_, mac_invoc_tt, matcher, match_nontermin use ast::{match_seq, match_tok, method, mt, BiMul, Mutability}; use ast::{named_field, UnNeg, noreturn, UnNot, Pat, PatBox, PatEnum}; use ast::{PatIdent, PatLit, PatRange, PatRegion, PatStruct}; -use ast::{PatTup, PatUniq, PatWild, private}; +use ast::{PatTup, PatUniq, PatWild, PatWildMulti, private}; use ast::{BiRem, required}; use ast::{ret_style, return_val, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, struct_def, struct_field}; @@ -2724,17 +2724,35 @@ impl Parser { } } - let subpat = self.parse_pat(); if is_slice { - match subpat { - @ast::Pat { node: PatWild, _ } => (), - @ast::Pat { node: PatIdent(_, _, _), _ } => (), - @ast::Pat { span, _ } => self.span_fatal( - span, "expected an identifier or `_`" - ) + if *self.token == token::COMMA || *self.token == token::RBRACKET { + slice = Some(@ast::Pat { + id: ast::DUMMY_NODE_ID, + node: PatWildMulti, + span: *self.span, + }) + } else { + let subpat = self.parse_pat(); + match subpat { + @ast::Pat { id, node: PatWild, span } => { + // NOTE #5830 activate after snapshot + // self.obsolete(*self.span, ObsoleteVecDotDotWildcard); + slice = Some(@ast::Pat { + id: id, + node: PatWildMulti, + span: span + }) + }, + @ast::Pat { node: PatIdent(_, _, _), _ } => { + slice = Some(subpat); + } + @ast::Pat { span, _ } => self.span_fatal( + span, "expected an identifier or nothing" + ) + } } - slice = Some(subpat); } else { + let subpat = self.parse_pat(); if before_slice { before.push(subpat); } else { @@ -2757,7 +2775,7 @@ impl Parser { etc = *self.token == token::UNDERSCORE || *self.token == token::DOTDOT; if *self.token == token::UNDERSCORE { - // FIXME #5830 activate after snapshot + // NOTE #5830 activate after snapshot // self.obsolete(*self.span, ObsoleteStructWildcard); } if etc { @@ -3031,7 +3049,7 @@ impl Parser { // This is a "top constructor only" pat self.bump(); if is_star { - // FIXME #5830 activate after snapshot + // NOTE #5830 activate after snapshot // self.obsolete(*self.span, ObsoleteEnumWildcard); } self.bump(); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 9c4803474d9..68af73d4a01 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1613,6 +1613,7 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) { is that it doesn't matter */ match pat.node { ast::PatWild => word(s.s, "_"), + ast::PatWildMulti => word(s.s, ".."), ast::PatIdent(binding_mode, ref path, sub) => { match binding_mode { ast::BindByRef(mutbl) => { @@ -1701,7 +1702,12 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) { } for &p in slice.iter() { if !before.is_empty() { word_space(s, ","); } - word(s.s, ".."); + match p { + @ast::Pat { node: ast::PatWildMulti, _ } => { + // this case is handled by print_pat + } + _ => word(s.s, ".."), + } print_pat(s, p); if !after.is_empty() { word_space(s, ","); } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a195bfb7717..aa712cae502 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -375,7 +375,7 @@ pub fn walk_pat>(visitor: &mut V, pattern: &Pat, env: E) { visitor.visit_expr(lower_bound, env.clone()); visitor.visit_expr(upper_bound, env) } - PatWild => (), + PatWild | PatWildMulti => (), PatVec(ref prepattern, ref slice_pattern, ref postpatterns) => { for prepattern in prepattern.iter() { visitor.visit_pat(*prepattern, env.clone()) diff --git a/src/test/run-pass/ignore-all-the-things.rs b/src/test/run-pass/ignore-all-the-things.rs index b71f139c684..b3b93c768d1 100644 --- a/src/test/run-pass/ignore-all-the-things.rs +++ b/src/test/run-pass/ignore-all-the-things.rs @@ -23,15 +23,21 @@ pub fn main() { //let (.., c, d) = (5, 5, 5, 5); let Bar{b: b, ..} = Bar{a: 5, b: 5, c: 5, d: 5}; let Bar{b: b, _} = Bar{a: 5, b: 5, c: 5, d: 5}; - /*match [5, 5, 5, 5] { + match [5, 5, 5, 5] { + [..] => { } + } + match [5, 5, 5, 5] { [a, ..] => { } - }*/ - /*match [5, 5, 5, 5] { + } + match [5, 5, 5, 5] { [.., b] => { } - }*/ - /*match [5, 5, 5, 5] { + } + match [5, 5, 5, 5] { [a, .., b] => { } - }*/ + } + match [5, 5, 5] { + [.._] => { } + } match [5, 5, 5] { [a, .._] => { } }