From aee1e59e6f00876a881e9d8c2ff00e0f11f896eb Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 7 Feb 2021 20:40:33 -0600 Subject: [PATCH] Simplify pattern grammar by allowing nested leading vert Along the way, we also implement a handful of diagnostics improvements and fixes, particularly with respect to the special handling of `||` in place of `|` and when there are leading verts in function params, which don't allow top-level or-patterns anyway. --- compiler/rustc_expand/src/expand.rs | 6 +- .../rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 8 +- compiler/rustc_parse/src/parser/mod.rs | 1 + .../rustc_parse/src/parser/nonterminal.rs | 4 +- compiler/rustc_parse/src/parser/pat.rs | 183 ++++++++++-------- compiler/rustc_parse/src/parser/stmt.rs | 2 +- .../feature-gate-or_patterns.stderr | 8 +- .../ui/or-patterns/fn-param-wrap-parens.fixed | 2 +- .../ui/or-patterns/fn-param-wrap-parens.rs | 2 +- .../or-patterns/fn-param-wrap-parens.stderr | 4 +- .../ui/or-patterns/multiple-pattern-typo.rs | 14 +- .../or-patterns/multiple-pattern-typo.stderr | 14 +- .../or-patterns/or-patterns-syntactic-fail.rs | 25 +-- .../or-patterns-syntactic-fail.stderr | 91 +-------- .../ui/or-patterns/remove-leading-vert.fixed | 26 +-- .../ui/or-patterns/remove-leading-vert.rs | 26 +-- .../ui/or-patterns/remove-leading-vert.stderr | 72 ++----- 18 files changed, 188 insertions(+), 302 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 870b5c92d8983..8c5395b12abce 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -22,7 +22,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, PResult}; use rustc_feature::Features; -use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser}; +use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, GateOr, Parser, RecoverComma}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; @@ -914,7 +914,9 @@ pub fn parse_ast_fragment<'a>( } } AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?), - AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat(None)?), + AstFragmentKind::Pat => { + AstFragment::Pat(this.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)?) + } AstFragmentKind::Arms | AstFragmentKind::Fields | AstFragmentKind::FieldPats diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 5512e849c451d..0f49386dec07b 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1654,7 +1654,7 @@ impl<'a> Parser<'a> { } pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { - let pat = self.parse_pat(Some("argument name"))?; + let pat = self.parse_pat_no_top_alt(Some("argument name"))?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 20430ece05b06..59fd060aa2465 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1726,7 +1726,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { - let pat = this.parse_pat(PARAM_EXPECTED)?; + let pat = this.parse_pat_no_top_alt(PARAM_EXPECTED)?; let ty = if this.eat(&token::Colon) { this.parse_ty()? } else { @@ -1803,7 +1803,7 @@ impl<'a> Parser<'a> { /// The `let` token has already been eaten. fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; - let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?; + let pat = self.parse_pat_allow_top_alt(None, GateOr::No, RecoverComma::Yes)?; self.expect(&token::Eq)?; let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| { this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) @@ -1866,7 +1866,7 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?; + let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::Yes)?; if !self.eat_keyword(kw::In) { self.error_missing_in_for_loop(); } @@ -1977,7 +1977,7 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; - let pat = this.parse_top_pat(GateOr::No, RecoverComma::Yes)?; + let pat = this.parse_pat_allow_top_alt(None, GateOr::No, RecoverComma::Yes)?; let guard = if this.eat_keyword(kw::If) { let if_span = this.prev_token.span; let cond = this.parse_expr()?; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 18013f1250bdb..ace4134b1f698 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -14,6 +14,7 @@ use crate::lexer::UnmatchedBrace; pub use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; use diagnostics::Error; +pub use pat::{GateOr, RecoverComma}; pub use path::PathStyle; use rustc_ast::ptr::P; diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 40dd938f000e3..a84ae5151442d 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -120,9 +120,9 @@ impl<'a> Parser<'a> { }, NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => { token::NtPat(self.collect_tokens_no_attrs(|this| match kind { - NonterminalKind::Pat2018 { .. } => this.parse_pat(None), + NonterminalKind::Pat2018 { .. } => this.parse_pat_no_top_alt(None), NonterminalKind::Pat2021 { .. } => { - this.parse_top_pat(GateOr::Yes, RecoverComma::No) + this.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No) } _ => unreachable!(), })?) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 317ef84742c21..8874548da784d 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -19,14 +19,14 @@ const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here" /// Whether or not an or-pattern should be gated when occurring in the current context. #[derive(PartialEq, Clone, Copy)] -pub(super) enum GateOr { +pub enum GateOr { Yes, No, } /// Whether or not to recover a `,` when parsing or-patterns. #[derive(PartialEq, Copy, Clone)] -pub(super) enum RecoverComma { +pub enum RecoverComma { Yes, No, } @@ -37,80 +37,57 @@ impl<'a> Parser<'a> { /// Corresponds to `pat` in RFC 2535 and does not admit or-patterns /// at the top level. Used when parsing the parameters of lambda expressions, /// functions, function pointers, and `pat` macro fragments. - pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P> { + pub fn parse_pat_no_top_alt(&mut self, expected: Expected) -> PResult<'a, P> { self.parse_pat_with_range_pat(true, expected) } - /// Entry point to the main pattern parser. + /// Parses a pattern. + /// /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. - pub(super) fn parse_top_pat( + /// Used for parsing patterns in all cases when `pat` is not used. + /// + /// Note that after the FCP in , + /// a leading vert is allowed in nested or-patterns, too. This allows us to + /// simplify the grammar somewhat. + pub fn parse_pat_allow_top_alt( &mut self, + expected: Expected, gate_or: GateOr, rc: RecoverComma, ) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes; - let leading_vert_span = self.prev_token.span; - - // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(None, gate_or, rc)?; - - // If we parsed a leading `|` which should be gated, - // and no other gated or-pattern has been parsed thus far, - // then we should really gate the leading `|`. - // This complicated procedure is done purely for diagnostics UX. - if gated_leading_vert && self.sess.gated_spans.is_ungated(sym::or_patterns) { - self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span); - } - - Ok(pat) - } - - /// Parse the pattern for a function or function pointer parameter. - /// Special recovery is provided for or-patterns and leading `|`. - pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { - self.recover_leading_vert(None, "not allowed in a parameter pattern"); - let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?; - - if let PatKind::Or(..) = &pat.kind { - self.ban_illegal_fn_param_or_pat(&pat); - } - - Ok(pat) - } + let leading_vert_span = + if self.eat_or_separator(None) { Some(self.prev_token.span) } else { None }; - /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens. - fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) { - let msg = "wrap the pattern in parenthesis"; - let fix = format!("({})", pprust::pat_to_string(pat)); - self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parenthesis") - .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable) - .emit(); - } - - /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). - /// Corresponds to `pat` in RFC 2535. - fn parse_pat_with_or( - &mut self, - expected: Expected, - gate_or: GateOr, - rc: RecoverComma, - ) -> PResult<'a, P> { // Parse the first pattern (`p_0`). - let first_pat = self.parse_pat(expected)?; + let first_pat = self.parse_pat_no_top_alt(expected)?; self.maybe_recover_unexpected_comma(first_pat.span, rc, gate_or)?; // 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)) && self.token != token::OrOr { + // If we parsed a leading `|` which should be gated, + // then we should really gate the leading `|`. + // This complicated procedure is done purely for diagnostics UX. + if let Some(leading_vert_span) = leading_vert_span { + if gate_or == GateOr::Yes && self.sess.gated_spans.is_ungated(sym::or_patterns) { + self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span); + } + + // If there was a leading vert, treat this as an or-pattern. This improves + // diagnostics. + let span = leading_vert_span.to(self.prev_token.span); + return Ok(self.mk_pat(span, PatKind::Or(vec![first_pat]))); + } + return Ok(first_pat); } // Parse the patterns `p_1 | ... | p_n` where `n > 0`. - let lo = first_pat.span; + let lo = leading_vert_span.unwrap_or(first_pat.span); let mut pats = vec![first_pat]; while self.eat_or_separator(Some(lo)) { - let pat = self.parse_pat(expected).map_err(|mut err| { + let pat = self.parse_pat_no_top_alt(expected).map_err(|mut err| { err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; @@ -127,6 +104,62 @@ impl<'a> Parser<'a> { Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) } + /// Parse the pattern for a function or function pointer parameter. + pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { + // We actually do _not_ allow top-level or-patterns in function params, but we use + // `parse_pat_allow_top_alt` anyway so that we can detect when a user tries to use it. This + // allows us to print a better error message. + // + // In order to get good UX, we first recover in the case of a leading vert for an illegal + // top-level or-pat. Normally, this means recovering both `|` and `||`, but in this case, + // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that + // separately. + if let token::OrOr = self.token.kind { + let span = self.token.span; + let mut err = self.struct_span_err(span, "unexpected `||` before function parameter"); + err.span_suggestion( + span, + "remove the `||`", + String::new(), + Applicability::MachineApplicable, + ); + err.note("alternatives in or-patterns are separated with `|`, not `||`"); + err.emit(); + self.bump(); + } + + let pat = self.parse_pat_allow_top_alt(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?; + + if let PatKind::Or(..) = &pat.kind { + self.ban_illegal_fn_param_or_pat(&pat); + } + + Ok(pat) + } + + /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens. + fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) { + // If all we have a leading vert, then print a special message. This is the case if + // `parse_pat_allow_top_alt` returns an or-pattern with one variant. + let (msg, fix) = match &pat.kind { + PatKind::Or(pats) if pats.len() == 1 => { + let msg = "remove the leading `|`"; + let fix = pprust::pat_to_string(pat); + (msg, fix) + } + + _ => { + let msg = "wrap the pattern in parentheses"; + let fix = format!("({})", pprust::pat_to_string(pat)); + (msg, fix) + } + }; + + self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parentheses") + .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable) + .emit(); + } + /// Eat the or-pattern `|` separator. /// If instead a `||` token is encountered, recover and pretend we parsed `|`. fn eat_or_separator(&mut self, lo: Option) -> bool { @@ -179,7 +212,7 @@ impl<'a> Parser<'a> { /// We have parsed `||` instead of `|`. Error and suggest `|` instead. fn ban_unexpected_or_or(&mut self, lo: Option) { - let mut err = self.struct_span_err(self.token.span, "unexpected token `||` after pattern"); + let mut err = self.struct_span_err(self.token.span, "unexpected token `||` in pattern"); err.span_suggestion( self.token.span, "use a single `|` to separate multiple alternative patterns", @@ -244,7 +277,7 @@ impl<'a> Parser<'a> { /// sequence of patterns until `)` is reached. fn skip_pat_list(&mut self) -> PResult<'a, ()> { while !self.check(&token::CloseDelim(token::Paren)) { - self.parse_pat(None)?; + self.parse_pat_no_top_alt(None)?; if !self.eat(&token::Comma) { return Ok(()); } @@ -252,22 +285,6 @@ impl<'a> Parser<'a> { Ok(()) } - /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. - /// See `parse_pat_with_or` for details on parsing or-patterns. - fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { - self.recover_leading_vert(None, "only allowed in a top-level pattern"); - self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No) - } - - /// Recover if `|` or `||` is here. - /// The user is thinking that a leading `|` is allowed in this position. - fn recover_leading_vert(&mut self, lo: Option, ctx: &str) { - if let token::BinOp(token::Or) | token::OrOr = self.token.kind { - self.ban_illegal_vert(lo, "leading", ctx); - self.bump(); - } - } - /// A `|` or possibly `||` token shouldn't be here. Ban it. fn ban_illegal_vert(&mut self, lo: Option, pos: &str, ctx: &str) { let span = self.token.span; @@ -305,8 +322,9 @@ impl<'a> Parser<'a> { self.parse_pat_tuple_or_parens()? } else if self.check(&token::OpenDelim(token::Bracket)) { // Parse `[pat, pat,...]` as a slice pattern. - let (pats, _) = - self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat_with_or_inner())?; + let (pats, _) = self.parse_delim_comma_seq(token::Bracket, |p| { + p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No) + })?; PatKind::Slice(pats) } else if self.check(&token::DotDot) && !self.is_pat_range_end_start(1) { // A rest pattern `..`. @@ -429,7 +447,7 @@ impl<'a> Parser<'a> { // At this point we attempt to parse `@ $pat_rhs` and emit an error. self.bump(); // `@` - let mut rhs = self.parse_pat(None)?; + let mut rhs = self.parse_pat_no_top_alt(None)?; let sp = lhs.span.to(rhs.span); if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind { @@ -518,8 +536,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_with_or_inner())?; + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { + p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No) + })?; // Here, `(pat,)` is a tuple pattern. // For backward compatibility, `(..)` is a tuple pattern as well. @@ -548,7 +567,7 @@ impl<'a> Parser<'a> { } // Parse the pattern we hope to be an identifier. - let mut pat = self.parse_pat(Some("identifier"))?; + let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?; // If we don't have `mut $ident (@ pat)?`, error. if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind { @@ -793,7 +812,7 @@ impl<'a> Parser<'a> { fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> { let ident = self.parse_ident()?; let sub = if self.eat(&token::At) { - Some(self.parse_pat(Some("binding pattern"))?) + Some(self.parse_pat_no_top_alt(Some("binding pattern"))?) } else { None }; @@ -832,7 +851,9 @@ impl<'a> Parser<'a> { if qself.is_some() { return self.error_qpath_before_pat(&path, "("); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?; + let (fields, _) = self.parse_paren_comma_seq(|p| { + p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No) + })?; Ok(PatKind::TupleStruct(path, fields)) } @@ -998,7 +1019,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_with_or_inner()?; + let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)?; hi = pat.span; (pat, fieldname, false) } else { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index e36ebd5e48113..2e00ddfaacc81 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -220,7 +220,7 @@ impl<'a> Parser<'a> { /// Parses a local variable declaration. fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; - let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?; + let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::Yes)?; let (err, ty) = if self.eat(&token::Colon) { // Save the state of the parser before parsing type normally, in case there is a `:` diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr index a9e43a4575da0..c01d17c0b3d7e 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr +++ b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr @@ -8,10 +8,10 @@ LL | Some(0 | 1 | 2) => {} = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:28:11 + --> $DIR/feature-gate-or_patterns.rs:28:9 | LL | let | A | B; - | ^^^^^ + | ^^^^^^^ | = note: see issue #54883 for more information = help: add `#![feature(or_patterns)]` to the crate attributes to enable @@ -26,10 +26,10 @@ LL | let A | B; = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:30:11 + --> $DIR/feature-gate-or_patterns.rs:30:9 | LL | for | A | B in 0 {} - | ^^^^^ + | ^^^^^^^ | = note: see issue #54883 for more information = help: add `#![feature(or_patterns)]` to the crate attributes to enable diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.fixed b/src/test/ui/or-patterns/fn-param-wrap-parens.fixed index 08730fe8b07b7..bbc75d2b411eb 100644 --- a/src/test/ui/or-patterns/fn-param-wrap-parens.fixed +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.fixed @@ -11,4 +11,4 @@ enum E { A, B } use E::*; #[cfg(FALSE)] -fn fun1((A | B): E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis +fn fun1((A | B): E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.rs b/src/test/ui/or-patterns/fn-param-wrap-parens.rs index ed667e0e66067..65b93dcbf7467 100644 --- a/src/test/ui/or-patterns/fn-param-wrap-parens.rs +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.rs @@ -11,4 +11,4 @@ enum E { A, B } use E::*; #[cfg(FALSE)] -fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis +fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.stderr b/src/test/ui/or-patterns/fn-param-wrap-parens.stderr index 2c6e4d9838ddc..0e6424a430043 100644 --- a/src/test/ui/or-patterns/fn-param-wrap-parens.stderr +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.stderr @@ -1,8 +1,8 @@ -error: an or-pattern parameter must be wrapped in parenthesis +error: an or-pattern parameter must be wrapped in parentheses --> $DIR/fn-param-wrap-parens.rs:14:9 | LL | fn fun1(A | B: E) {} - | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` + | ^^^^^ help: wrap the pattern in parentheses: `(A | B)` error: aborting due to previous error diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.rs b/src/test/ui/or-patterns/multiple-pattern-typo.rs index 702c9573741e7..4d06101044f6c 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.rs +++ b/src/test/ui/or-patterns/multiple-pattern-typo.rs @@ -4,41 +4,41 @@ fn main() { let x = 3; match x { - 1 | 2 || 3 => (), //~ ERROR unexpected token `||` after pattern + 1 | 2 || 3 => (), //~ ERROR unexpected token `||` in pattern _ => (), } match x { - (1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern + (1 | 2 || 3) => (), //~ ERROR unexpected token `||` in pattern _ => (), } match (x,) { - (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` after pattern + (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` in pattern _ => (), } struct TS(u8); match TS(x) { - TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern + TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` in pattern _ => (), } struct NS { f: u8 } match (NS { f: x }) { - NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` after pattern + NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` in pattern _ => (), } match [x] { - [1 | 2 || 3] => (), //~ ERROR unexpected token `||` after pattern + [1 | 2 || 3] => (), //~ ERROR unexpected token `||` in pattern _ => (), } match x { - || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` after pattern + || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` in pattern _ => (), } } diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr index cb32068ec0d5e..b0a82b3673b83 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.stderr +++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr @@ -1,4 +1,4 @@ -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:7:15 | LL | 1 | 2 || 3 => (), @@ -6,7 +6,7 @@ LL | 1 | 2 || 3 => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:12:16 | LL | (1 | 2 || 3) => (), @@ -14,7 +14,7 @@ LL | (1 | 2 || 3) => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:17:16 | LL | (1 | 2 || 3,) => (), @@ -22,7 +22,7 @@ LL | (1 | 2 || 3,) => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:24:18 | LL | TS(1 | 2 || 3) => (), @@ -30,7 +30,7 @@ LL | TS(1 | 2 || 3) => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:31:23 | LL | NS { f: 1 | 2 || 3 } => (), @@ -38,7 +38,7 @@ LL | NS { f: 1 | 2 || 3 } => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:36:16 | LL | [1 | 2 || 3] => (), @@ -46,7 +46,7 @@ LL | [1 | 2 || 3] => (), | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:41:9 | LL | || 1 | 2 | 3 => (), diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs index efe90b3e3c60c..cbc24eb26fa47 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -14,29 +14,8 @@ fn no_top_level_or_patterns() { // -------- This looks like an or-pattern but is in fact `|A| (B: E | ())`. // ...and for now neither do we allow or-patterns at the top level of functions. - fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis + fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses fn fun2(| A | B: E) {} - //~^ ERROR a leading `|` is not allowed in a parameter pattern - //~| ERROR an or-pattern parameter must be wrapped in parenthesis -} - -// We also do not allow a leading `|` when not in a top level position: - -fn no_leading_inner() { - struct TS(E); - struct NS { f: E } - - let ( | A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern - let ( | A | B,) = (E::B,); //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ | A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( | A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: | A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern - - let ( || A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ || A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( || A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: || A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern - - let recovery_witness: String = 0; //~ ERROR mismatched types + //~^ ERROR an or-pattern parameter must be wrapped in parentheses } diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 989aeb5200645..db4d827757b03 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -1,82 +1,14 @@ -error: an or-pattern parameter must be wrapped in parenthesis +error: an or-pattern parameter must be wrapped in parentheses --> $DIR/or-patterns-syntactic-fail.rs:17:13 | LL | fn fun1(A | B: E) {} - | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` + | ^^^^^ help: wrap the pattern in parentheses: `(A | B)` -error: a leading `|` is not allowed in a parameter pattern +error: an or-pattern parameter must be wrapped in parentheses --> $DIR/or-patterns-syntactic-fail.rs:19:13 | LL | fn fun2(| A | B: E) {} - | ^ help: remove the `|` - -error: an or-pattern parameter must be wrapped in parenthesis - --> $DIR/or-patterns-syntactic-fail.rs:19:15 - | -LL | fn fun2(| A | B: E) {} - | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:30:11 - | -LL | let ( | A | B) = E::A; - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:31:11 - | -LL | let ( | A | B,) = (E::B,); - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:32:11 - | -LL | let [ | A | B ] = [E::A]; - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:33:13 - | -LL | let TS( | A | B ); - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:34:17 - | -LL | let NS { f: | A | B }; - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:36:11 - | -LL | let ( || A | B) = E::A; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:37:11 - | -LL | let [ || A | B ] = [E::A]; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:38:13 - | -LL | let TS( || A | B ); - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:39:17 - | -LL | let NS { f: || A | B }; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` + | ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)` error[E0369]: no implementation for `E | ()` --> $DIR/or-patterns-syntactic-fail.rs:13:22 @@ -88,17 +20,6 @@ LL | let _ = |A | B: E| (); | = note: an implementation of `std::ops::BitOr` might be missing for `E` -error[E0308]: mismatched types - --> $DIR/or-patterns-syntactic-fail.rs:41:36 - | -LL | let recovery_witness: String = 0; - | ------ ^ - | | | - | | expected struct `String`, found integer - | | help: try using a conversion method: `0.to_string()` - | expected due to this - -error: aborting due to 14 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0308, E0369. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/or-patterns/remove-leading-vert.fixed b/src/test/ui/or-patterns/remove-leading-vert.fixed index 443ef398293d9..c8fac4faa2a66 100644 --- a/src/test/ui/or-patterns/remove-leading-vert.fixed +++ b/src/test/ui/or-patterns/remove-leading-vert.fixed @@ -9,17 +9,17 @@ fn main() {} #[cfg(FALSE)] fn leading() { - fn fun1( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern - fn fun2( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern - let ( A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern - let ( A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern - let ( A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern + fn fun1( A: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses + fn fun2( A: E) {} //~ ERROR unexpected `||` before function parameter + let ( | A): E; + let ( | A): (E); //~ ERROR unexpected token `||` in pattern + let ( | A,): (E,); + let [ | A ]: [E; 1]; + let [ | A ]: [E; 1]; //~ ERROR unexpected token `||` in pattern + let TS( | A ): TS; + let TS( | A ): TS; //~ ERROR unexpected token `||` in pattern + let NS { f: | A }: NS; + let NS { f: | A }: NS; //~ ERROR unexpected token `||` in pattern } #[cfg(FALSE)] @@ -29,12 +29,12 @@ fn trailing() { let ( A | B ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern let [ A | B ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern let S { f: B }; //~ ERROR a trailing `|` is not allowed in an or-pattern - let ( A | B ): E; //~ ERROR unexpected token `||` after pattern + let ( A | B ): E; //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern match A { A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern - A | B => {} //~ ERROR unexpected token `||` after pattern + A | B => {} //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern | A | B => {} //~^ ERROR a trailing `|` is not allowed in an or-pattern diff --git a/src/test/ui/or-patterns/remove-leading-vert.rs b/src/test/ui/or-patterns/remove-leading-vert.rs index 3c427a6f7b23e..2cf6b27ab1aac 100644 --- a/src/test/ui/or-patterns/remove-leading-vert.rs +++ b/src/test/ui/or-patterns/remove-leading-vert.rs @@ -9,17 +9,17 @@ fn main() {} #[cfg(FALSE)] fn leading() { - fn fun1( | A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern - fn fun2( || A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern - let ( | A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern - let ( || A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern - let ( | A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ | A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let [ || A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( | A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let TS( || A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: | A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern - let NS { f: || A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern + fn fun1( | A: E) {} //~ ERROR an or-pattern parameter must be wrapped in parentheses + fn fun2( || A: E) {} //~ ERROR unexpected `||` before function parameter + let ( | A): E; + let ( || A): (E); //~ ERROR unexpected token `||` in pattern + let ( | A,): (E,); + let [ | A ]: [E; 1]; + let [ || A ]: [E; 1]; //~ ERROR unexpected token `||` in pattern + let TS( | A ): TS; + let TS( || A ): TS; //~ ERROR unexpected token `||` in pattern + let NS { f: | A }: NS; + let NS { f: || A }: NS; //~ ERROR unexpected token `||` in pattern } #[cfg(FALSE)] @@ -29,12 +29,12 @@ fn trailing() { let ( A | B | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern let [ A | B | ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern let S { f: B | }; //~ ERROR a trailing `|` is not allowed in an or-pattern - let ( A || B | ): E; //~ ERROR unexpected token `||` after pattern + let ( A || B | ): E; //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern match A { A | => {} //~ ERROR a trailing `|` is not allowed in an or-pattern A || => {} //~ ERROR a trailing `|` is not allowed in an or-pattern - A || B | => {} //~ ERROR unexpected token `||` after pattern + A || B | => {} //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern | A | B | => {} //~^ ERROR a trailing `|` is not allowed in an or-pattern diff --git a/src/test/ui/or-patterns/remove-leading-vert.stderr b/src/test/ui/or-patterns/remove-leading-vert.stderr index 53025230a63c2..5c9efd44a187f 100644 --- a/src/test/ui/or-patterns/remove-leading-vert.stderr +++ b/src/test/ui/or-patterns/remove-leading-vert.stderr @@ -1,10 +1,10 @@ -error: a leading `|` is not allowed in a parameter pattern +error: an or-pattern parameter must be wrapped in parentheses --> $DIR/remove-leading-vert.rs:12:14 | LL | fn fun1( | A: E) {} - | ^ help: remove the `|` + | ^^^ help: remove the leading `|`: `A` -error: a leading `|` is not allowed in a parameter pattern +error: unexpected `||` before function parameter --> $DIR/remove-leading-vert.rs:13:14 | LL | fn fun2( || A: E) {} @@ -12,67 +12,29 @@ LL | fn fun2( || A: E) {} | = note: alternatives in or-patterns are separated with `|`, not `||` -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/remove-leading-vert.rs:14:11 - | -LL | let ( | A): E; - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:15:11 | LL | let ( || A): (E); - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/remove-leading-vert.rs:16:11 - | -LL | let ( | A,): (E,); - | ^ help: remove the `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/remove-leading-vert.rs:17:11 - | -LL | let [ | A ]: [E; 1]; - | ^ help: remove the `|` - -error: a leading `|` is only allowed in a top-level pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:18:11 | LL | let [ || A ]: [E; 1]; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/remove-leading-vert.rs:19:13 - | -LL | let TS( | A ): TS; - | ^ help: remove the `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` -error: a leading `|` is only allowed in a top-level pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:20:13 | LL | let TS( || A ): TS; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` - -error: a leading `|` is only allowed in a top-level pattern - --> $DIR/remove-leading-vert.rs:21:17 - | -LL | let NS { f: | A }: NS; - | ^ help: remove the `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` -error: a leading `|` is only allowed in a top-level pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:22:17 | LL | let NS { f: || A }: NS; - | ^^ help: remove the `||` - | - = note: alternatives in or-patterns are separated with `|`, not `||` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:27:13 @@ -114,7 +76,7 @@ LL | let S { f: B | }; | | | while parsing this or-pattern starting here -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:32:13 | LL | let ( A || B | ): E; @@ -148,7 +110,7 @@ LL | A || => {} | = note: alternatives in or-patterns are separated with `|`, not `||` -error: unexpected token `||` after pattern +error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:37:11 | LL | A || B | => {} @@ -168,9 +130,9 @@ error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:39:17 | LL | | A | B | => {} - | - ^ help: remove the `|` - | | - | while parsing this or-pattern starting here + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:43:11 @@ -196,5 +158,5 @@ LL | let a | ; | | | while parsing this or-pattern starting here -error: aborting due to 26 previous errors +error: aborting due to 21 previous errors