about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-08-19 02:40:24 +0200
committerMazdak Farrokhzad <twingoow@gmail.com>2019-08-24 21:53:55 +0200
commitb205055c7bc92c0f873755996e6fac3e694c7e72 (patch)
treed08790b43bae6854a53e82b90f47fa7df1ba413c
parent1ffea18ddbe9ebaba4ff301a3c42e44a55741355 (diff)
downloadrust-b205055c7bc92c0f873755996e6fac3e694c7e72.tar.gz
rust-b205055c7bc92c0f873755996e6fac3e694c7e72.zip
parser: better recovery for || in inner pats.
-rw-r--r--src/libsyntax/parse/parser/pat.rs27
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-fail.rs39
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr77
3 files changed, 96 insertions, 47 deletions
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index e77d9120bce..b9871be229c 100644
--- a/src/libsyntax/parse/parser/pat.rs
+++ b/src/libsyntax/parse/parser/pat.rs
@@ -155,6 +155,25 @@ 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, expected: Expected) -> PResult<'a, P<Pat>> {
+        // Recover if `|` or `||` is here.
+        // The user is thinking that a leading `|` is allowed in this position.
+        if let token::BinOp(token::Or) | token::OrOr = self.token.kind {
+            let span = self.token.span;
+            let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token));
+
+            self.struct_span_err(span, "a leading `|` is only allowed in a top-level pattern")
+                .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable)
+                .emit();
+
+            self.bump();
+        }
+
+        self.parse_pat_with_or(expected, true, false)
+    }
+
     /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
     /// allowed).
     fn parse_pat_with_range_pat(
@@ -173,7 +192,7 @@ impl<'a> Parser<'a> {
                 // Parse `[pat, pat,...]` as a slice pattern.
                 let (pats, _) = self.parse_delim_comma_seq(
                     token::Bracket,
-                    |p| p.parse_pat_with_or(None, true, false),
+                    |p| p.parse_pat_with_or_inner(None),
                 )?;
                 PatKind::Slice(pats)
             }
@@ -303,7 +322,7 @@ 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(None, true, false)
+            p.parse_pat_with_or_inner(None)
         })?;
 
         // Here, `(pat,)` is a tuple pattern.
@@ -547,7 +566,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_with_or(None, true, false))?;
+        let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner(None))?;
         Ok(PatKind::TupleStruct(path, fields))
     }
 
@@ -691,7 +710,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(None, true, false)?;
+            let pat = self.parse_pat_with_or_inner(None)?;
             hi = pat.span;
             (pat, fieldname, false)
         } else {
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 43c9214bd98..7959812f5b3 100644
--- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs
@@ -30,27 +30,20 @@ fn no_top_level_or_patterns() {
 
 // We also do not allow a leading `|` when not in a top level position:
 
-#[cfg(FALSE)]
-fn no_leading_parens() {
-    let ( | A | B); //~ ERROR expected pattern, found `|`
-}
-
-#[cfg(FALSE)]
-fn no_leading_tuple() {
-    let ( | A | B,); //~ ERROR expected pattern, found `|`
-}
-
-#[cfg(FALSE)]
-fn no_leading_slice() {
-    let [ | A | B ]; //~ ERROR expected pattern, found `|`
-}
-
-#[cfg(FALSE)]
-fn no_leading_tuple_struct() {
-    let TS( | A | B ); //~ ERROR expected pattern, found `|`
-}
-
-#[cfg(FALSE)]
-fn no_leading_struct() {
-    let NS { f: | A | B }; //~ ERROR expected pattern, found `|`
+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
 }
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 809ff272f62..dd4c309ce85 100644
--- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
@@ -4,35 +4,59 @@ error: expected one of `:` or `@`, found `|`
 LL |     fn fun(A | B: E) {}
    |              ^ expected one of `:` or `@` here
 
-error: expected pattern, found `|`
-  --> $DIR/or-patterns-syntactic-fail.rs:35:11
+error: a leading `|` is only allowed in a top-level pattern
+  --> $DIR/or-patterns-syntactic-fail.rs:37:11
    |
-LL |     let ( | A | B);
-   |           ^ expected pattern
+LL |     let ( | A | B) = E::A;
+   |           ^ help: remove the `|`
 
-error: expected pattern, found `|`
-  --> $DIR/or-patterns-syntactic-fail.rs:40:11
+error: a leading `|` is only allowed in a top-level pattern
+  --> $DIR/or-patterns-syntactic-fail.rs:38:11
    |
-LL |     let ( | A | B,);
-   |           ^ expected pattern
+LL |     let ( | A | B,) = (E::B,);
+   |           ^ help: remove the `|`
 
-error: expected pattern, found `|`
-  --> $DIR/or-patterns-syntactic-fail.rs:45:11
+error: a leading `|` is only allowed in a top-level pattern
+  --> $DIR/or-patterns-syntactic-fail.rs:39:11
    |
-LL |     let [ | A | B ];
-   |           ^ expected pattern
+LL |     let [ | A | B ] = [E::A];
+   |           ^ help: remove the `|`
 
-error: expected pattern, found `|`
-  --> $DIR/or-patterns-syntactic-fail.rs:50:13
+error: a leading `|` is only allowed in a top-level pattern
+  --> $DIR/or-patterns-syntactic-fail.rs:40:13
    |
 LL |     let TS( | A | B );
-   |             ^ expected pattern
+   |             ^ help: remove the `|`
 
-error: expected pattern, found `|`
-  --> $DIR/or-patterns-syntactic-fail.rs:55:17
+error: a leading `|` is only allowed in a top-level pattern
+  --> $DIR/or-patterns-syntactic-fail.rs:41:17
    |
 LL |     let NS { f: | A | B };
-   |                 ^ expected pattern
+   |                 ^ help: remove the `|`
+
+error: a leading `|` is only allowed in a top-level pattern
+  --> $DIR/or-patterns-syntactic-fail.rs:43: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:44: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:45: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:46:17
+   |
+LL |     let NS { f: || A | B };
+   |                 ^^ help: remove the `||`
 
 error: no rules expected the token `|`
   --> $DIR/or-patterns-syntactic-fail.rs:14:15
@@ -70,6 +94,19 @@ LL |     let _ = |A | B: E| ();
    |
    = note: an implementation of `std::ops::BitOr` might be missing for `E`
 
-error: aborting due to 9 previous errors
+error[E0308]: mismatched types
+  --> $DIR/or-patterns-syntactic-fail.rs:48:36
+   |
+LL |     let recovery_witness: String = 0;
+   |                                    ^
+   |                                    |
+   |                                    expected struct `std::string::String`, found integer
+   |                                    help: try using a conversion method: `0.to_string()`
+   |
+   = note: expected type `std::string::String`
+              found type `{integer}`
+
+error: aborting due to 14 previous errors
 
-For more information about this error, try `rustc --explain E0369`.
+Some errors have detailed explanations: E0308, E0369.
+For more information about an error, try `rustc --explain E0308`.