Skip to content

Commit

Permalink
Rollup merge of rust-lang#63693 - Centril:polish-parse-or-pats, r=est…
Browse files Browse the repository at this point in the history
…ebank

Fully implement or-pattern parsing

Builds upon the initial parsing in rust-lang#61708 to fully implement or-pattern (`p | q`) parsing as specified in [the grammar section of RFC 2535](https://github.com/rust-lang/rfcs/blob/master/text/2535-or-patterns.md#grammar).

Noteworthy:

- We allow or-patterns in `[p | q, ...]`.
- We allow or-patterns in `let` statements and `for` expressions including with leading `|`.
- We improve recovery for `p || q` (+ tests for that in `multiple-pattern-typo.rs`).
- We improve recovery for `| p | q` in inner patterns (tests in `or-patterns-syntactic-fail.rs`).
- We rigorously test or-pattern parsing (in `or-patterns-syntactic-{pass,fail}.rs`).
- We harden the feature gating tests.
- We do **_not_** change `ast.rs`. That is, `ExprKind::Let.0` and `Arm.pats` still accept `Vec<P<Pat>>`.
   I was starting work on that but it would be cleaner to do this in a separate PR so this one has a narrower scope.

cc @dlrobertson
cc the tracking issue rust-lang#54883.

r? @estebank
  • Loading branch information
Centril authored Aug 26, 2019
2 parents 44cfa78 + 2bd27fb commit 7dc3c93
Show file tree
Hide file tree
Showing 67 changed files with 1,081 additions and 226 deletions.
11 changes: 4 additions & 7 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -971,15 +971,12 @@ impl<'a> Parser<'a> {
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
/// error.
/// This version of parse arg doesn't necessarily require identifier names.
fn parse_arg_general<F>(
fn parse_arg_general(
&mut self,
is_trait_item: bool,
allow_c_variadic: bool,
is_name_required: F,
) -> PResult<'a, Arg>
where
F: Fn(&token::Token) -> bool
{
is_name_required: impl Fn(&token::Token) -> bool,
) -> PResult<'a, Arg> {
let lo = self.token.span;
let attrs = self.parse_arg_attributes()?;
if let Some(mut arg) = self.parse_self_arg()? {
Expand All @@ -991,7 +988,7 @@ impl<'a> Parser<'a> {
let (pat, ty) = if is_name_required || self.is_named_argument() {
debug!("parse_arg_general parse_pat (is_name_required:{})", is_name_required);

let pat = self.parse_pat(Some("argument name"))?;
let pat = self.parse_fn_param_pat()?;
if let Err(mut err) = self.expect(&token::Colon) {
if let Some(ident) = self.argument_without_type(
&mut err,
Expand Down
17 changes: 10 additions & 7 deletions src/libsyntax/parse/parser/expr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle};
use super::{BlockMode, SemiColonMode};
use super::{SeqSep, TokenExpectType};
use super::pat::{GateOr, PARAM_EXPECTED};

use crate::maybe_recover_from_interpolated_ty_qpath;
use crate::ptr::P;
Expand Down Expand Up @@ -1175,7 +1176,7 @@ impl<'a> Parser<'a> {
fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> {
let lo = self.token.span;
let attrs = self.parse_arg_attributes()?;
let pat = self.parse_pat(Some("argument name"))?;
let pat = self.parse_pat(PARAM_EXPECTED)?;
let t = if self.eat(&token::Colon) {
self.parse_ty()?
} else {
Expand Down Expand Up @@ -1241,19 +1242,20 @@ impl<'a> Parser<'a> {
Ok(cond)
}

/// Parses a `let $pats = $expr` pseudo-expression.
/// Parses a `let $pat = $expr` pseudo-expression.
/// The `let` token has already been eaten.
fn parse_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let lo = self.prev_span;
let pats = self.parse_pats()?;
// FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead.
let pat = self.parse_top_pat_unpack(GateOr::No)?;
self.expect(&token::Eq)?;
let expr = self.with_res(
Restrictions::NO_STRUCT_LITERAL,
|this| this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
)?;
let span = lo.to(expr.span);
self.sess.gated_spans.let_chains.borrow_mut().push(span);
Ok(self.mk_expr(span, ExprKind::Let(pats, expr), attrs))
Ok(self.mk_expr(span, ExprKind::Let(pat, expr), attrs))
}

/// `else` token already eaten
Expand Down Expand Up @@ -1283,7 +1285,7 @@ impl<'a> Parser<'a> {
_ => None,
};

let pat = self.parse_top_level_pat()?;
let pat = self.parse_top_pat(GateOr::Yes)?;
if !self.eat_keyword(kw::In) {
let in_span = self.prev_span.between(self.token.span);
self.struct_span_err(in_span, "missing `in` in `for` loop")
Expand Down Expand Up @@ -1387,7 +1389,8 @@ impl<'a> Parser<'a> {
crate fn parse_arm(&mut self) -> PResult<'a, Arm> {
let attrs = self.parse_outer_attributes()?;
let lo = self.token.span;
let pats = self.parse_pats()?;
// FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead.
let pat = self.parse_top_pat_unpack(GateOr::No)?;
let guard = if self.eat_keyword(kw::If) {
Some(self.parse_expr()?)
} else {
Expand Down Expand Up @@ -1448,7 +1451,7 @@ impl<'a> Parser<'a> {

Ok(ast::Arm {
attrs,
pats,
pats: pat, // FIXME(or_patterns, Centril | dlrobertson): this should just be `pat,`.
guard,
body: expr,
span: lo.to(hi),
Expand Down
Loading

0 comments on commit 7dc3c93

Please sign in to comment.