Auto merge of #61708 - dlrobertson:or-patterns-0, r=centril
Initial implementation of or-patterns An incomplete implementation of or-patterns (e.g. `Some(0 | 1)` as a pattern). This patch set aims to implement initial parsing of `or-patterns`. Related to: #54883 CC @alexreg @varkor r? @Centril
This commit is contained in:
commit
fc8765d6d8
30 changed files with 241 additions and 51 deletions
|
|
@ -572,9 +572,10 @@ impl Pat {
|
|||
match &self.node {
|
||||
PatKind::Ident(_, _, Some(p)) => p.walk(it),
|
||||
PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk(it)),
|
||||
PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => {
|
||||
s.iter().all(|p| p.walk(it))
|
||||
}
|
||||
PatKind::TupleStruct(_, s)
|
||||
| PatKind::Tuple(s)
|
||||
| PatKind::Slice(s)
|
||||
| PatKind::Or(s) => s.iter().all(|p| p.walk(it)),
|
||||
PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
|
||||
PatKind::Wild
|
||||
| PatKind::Rest
|
||||
|
|
@ -648,6 +649,10 @@ pub enum PatKind {
|
|||
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
|
||||
TupleStruct(Path, Vec<P<Pat>>),
|
||||
|
||||
/// An or-pattern `A | B | C`.
|
||||
/// Invariant: `pats.len() >= 2`.
|
||||
Or(Vec<P<Pat>>),
|
||||
|
||||
/// A possibly qualified path pattern.
|
||||
/// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
|
||||
/// or associated constants. Qualified path patterns `<A>::B::C`/`<A as Trait>::B::C` can
|
||||
|
|
|
|||
|
|
@ -559,6 +559,9 @@ declare_features! (
|
|||
// Allows `impl Trait` to be used inside type aliases (RFC 2515).
|
||||
(active, type_alias_impl_trait, "1.38.0", Some(63063), None),
|
||||
|
||||
// Allows the use of or-patterns, e.g. `0 | 1`.
|
||||
(active, or_patterns, "1.38.0", Some(54883), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
@ -571,6 +574,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
|
|||
sym::impl_trait_in_bindings,
|
||||
sym::generic_associated_types,
|
||||
sym::const_generics,
|
||||
sym::or_patterns,
|
||||
sym::let_chains,
|
||||
];
|
||||
|
||||
|
|
@ -2443,6 +2447,7 @@ pub fn check_crate(krate: &ast::Crate,
|
|||
gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental");
|
||||
gate_all!(async_closure_spans, async_closure, "async closures are unstable");
|
||||
gate_all!(yield_spans, generators, "yield syntax is experimental");
|
||||
gate_all!(or_pattern_spans, or_patterns, "or-patterns syntax is experimental");
|
||||
|
||||
let visitor = &mut PostExpansionVisitor {
|
||||
context: &ctx,
|
||||
|
|
|
|||
|
|
@ -1050,7 +1050,6 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
|||
vis.visit_span(span);
|
||||
};
|
||||
}
|
||||
PatKind::Tuple(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
|
||||
PatKind::Box(inner) => vis.visit_pat(inner),
|
||||
PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
|
||||
PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
|
||||
|
|
@ -1058,7 +1057,9 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
|||
vis.visit_expr(e2);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
|
||||
PatKind::Tuple(elems)
|
||||
| PatKind::Slice(elems)
|
||||
| PatKind::Or(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
|
||||
PatKind::Paren(inner) => vis.visit_pat(inner),
|
||||
PatKind::Mac(mac) => vis.visit_mac(mac),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ pub struct ParseSess {
|
|||
// Places where `yield e?` exprs were used and should be feature gated.
|
||||
pub yield_spans: Lock<Vec<Span>>,
|
||||
pub injected_crate_name: Once<Symbol>,
|
||||
// Places where or-patterns e.g. `Some(Foo | Bar)` were used and should be feature gated.
|
||||
pub or_pattern_spans: Lock<Vec<Span>>,
|
||||
}
|
||||
|
||||
impl ParseSess {
|
||||
|
|
@ -96,6 +98,7 @@ impl ParseSess {
|
|||
async_closure_spans: Lock::new(Vec::new()),
|
||||
yield_spans: Lock::new(Vec::new()),
|
||||
injected_crate_name: Once::new(),
|
||||
or_pattern_spans: Lock::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@ use errors::{Applicability, DiagnosticBuilder};
|
|||
|
||||
impl<'a> Parser<'a> {
|
||||
/// Parses a pattern.
|
||||
pub fn parse_pat(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
|
||||
pub fn parse_pat(
|
||||
&mut self,
|
||||
expected: Option<&'static str>
|
||||
) -> PResult<'a, P<Pat>> {
|
||||
self.parse_pat_with_range_pat(true, expected)
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +100,34 @@ impl<'a> Parser<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`).
|
||||
fn parse_pat_with_or(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
|
||||
// Parse the first pattern.
|
||||
let first_pat = self.parse_pat(expected)?;
|
||||
|
||||
// If the next token is not a `|`, this is not an or-pattern and
|
||||
// we should exit here.
|
||||
if !self.check(&token::BinOp(token::Or)) {
|
||||
return Ok(first_pat)
|
||||
}
|
||||
|
||||
let lo = first_pat.span;
|
||||
|
||||
let mut pats = vec![first_pat];
|
||||
|
||||
while self.eat(&token::BinOp(token::Or)) {
|
||||
pats.push(self.parse_pat_with_range_pat(
|
||||
true, expected
|
||||
)?);
|
||||
}
|
||||
|
||||
let or_pattern_span = lo.to(self.prev_span);
|
||||
|
||||
self.sess.or_pattern_spans.borrow_mut().push(or_pattern_span);
|
||||
|
||||
Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats)))
|
||||
}
|
||||
|
||||
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
|
||||
/// allowed).
|
||||
fn parse_pat_with_range_pat(
|
||||
|
|
@ -240,7 +271,9 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parse a tuple or parenthesis pattern.
|
||||
fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
|
||||
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
|
||||
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
|
||||
p.parse_pat_with_or(None)
|
||||
})?;
|
||||
|
||||
// Here, `(pat,)` is a tuple pattern.
|
||||
// For backward compatibility, `(..)` is a tuple pattern as well.
|
||||
|
|
@ -483,7 +516,7 @@ impl<'a> Parser<'a> {
|
|||
err.span_label(self.token.span, msg);
|
||||
return Err(err);
|
||||
}
|
||||
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
|
||||
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None))?;
|
||||
Ok(PatKind::TupleStruct(path, fields))
|
||||
}
|
||||
|
||||
|
|
@ -627,7 +660,7 @@ impl<'a> Parser<'a> {
|
|||
// Parsing a pattern of the form "fieldname: pat"
|
||||
let fieldname = self.parse_field_name()?;
|
||||
self.bump();
|
||||
let pat = self.parse_pat(None)?;
|
||||
let pat = self.parse_pat_with_or(None)?;
|
||||
hi = pat.span;
|
||||
(pat, fieldname, false)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -436,18 +436,30 @@ pub trait PrintState<'a>: std::ops::Deref<Target=pp::Printer> + std::ops::DerefM
|
|||
fn print_ident(&mut self, ident: ast::Ident);
|
||||
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
|
||||
|
||||
fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F)
|
||||
fn strsep<T, F>(&mut self, sep: &'static str, space_before: bool,
|
||||
b: Breaks, elts: &[T], mut op: F)
|
||||
where F: FnMut(&mut Self, &T),
|
||||
{
|
||||
self.rbox(0, b);
|
||||
let mut first = true;
|
||||
for elt in elts {
|
||||
if first { first = false; } else { self.word_space(","); }
|
||||
op(self, elt);
|
||||
if let Some((first, rest)) = elts.split_first() {
|
||||
op(self, first);
|
||||
for elt in rest {
|
||||
if space_before {
|
||||
self.space();
|
||||
}
|
||||
self.word_space(sep);
|
||||
op(self, elt);
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
}
|
||||
|
||||
fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
|
||||
where F: FnMut(&mut Self, &T),
|
||||
{
|
||||
self.strsep(",", false, b, elts, op)
|
||||
}
|
||||
|
||||
fn maybe_print_comment(&mut self, pos: BytePos) {
|
||||
while let Some(ref cmnt) = self.next_comment() {
|
||||
if cmnt.pos < pos {
|
||||
|
|
@ -2353,6 +2365,9 @@ impl<'a> State<'a> {
|
|||
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p));
|
||||
}
|
||||
PatKind::Path(None, ref path) => {
|
||||
self.print_path(path, true, 0);
|
||||
}
|
||||
|
|
@ -2429,16 +2444,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_pats(&mut self, pats: &[P<ast::Pat>]) {
|
||||
let mut first = true;
|
||||
for p in pats {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
self.s.space();
|
||||
self.word_space("|");
|
||||
}
|
||||
self.print_pat(p);
|
||||
}
|
||||
self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p));
|
||||
}
|
||||
|
||||
fn print_arm(&mut self, arm: &ast::Arm) {
|
||||
|
|
|
|||
|
|
@ -447,9 +447,6 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
|||
visitor.visit_pat(&field.pat)
|
||||
}
|
||||
}
|
||||
PatKind::Tuple(ref elems) => {
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
}
|
||||
PatKind::Box(ref subpattern) |
|
||||
PatKind::Ref(ref subpattern, _) |
|
||||
PatKind::Paren(ref subpattern) => {
|
||||
|
|
@ -465,7 +462,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
|||
visitor.visit_expr(upper_bound);
|
||||
}
|
||||
PatKind::Wild | PatKind::Rest => {},
|
||||
PatKind::Slice(ref elems) => {
|
||||
PatKind::Tuple(ref elems)
|
||||
| PatKind::Slice(ref elems)
|
||||
| PatKind::Or(ref elems) => {
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
}
|
||||
PatKind::Mac(ref mac) => visitor.visit_mac(mac),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue