From 45c1e381473b39e7fece2663638d09288370a821 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Fri, 13 Dec 2019 00:59:33 +0100
Subject: [PATCH] parser: recover on `&'lifetime mut $pat`.

---
 src/librustc_parse/parser/pat.rs              | 22 +++++++++++++-----
 .../ui/parser/lifetime-in-pattern-recover.rs  |  6 +++++
 .../parser/lifetime-in-pattern-recover.stderr | 23 +++++++++++++++++++
 src/test/ui/parser/lifetime-in-pattern.rs     |  1 +
 src/test/ui/parser/lifetime-in-pattern.stderr | 10 ++++++--
 .../ui/self/self-vs-path-ambiguity.stderr     |  2 +-
 6 files changed, 55 insertions(+), 9 deletions(-)
 create mode 100644 src/test/ui/parser/lifetime-in-pattern-recover.rs
 create mode 100644 src/test/ui/parser/lifetime-in-pattern-recover.stderr

diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs
index 42ece96adb99a..117b92dc9a574 100644
--- a/src/librustc_parse/parser/pat.rs
+++ b/src/librustc_parse/parser/pat.rs
@@ -459,16 +459,26 @@ impl<'a> Parser<'a> {
     /// Parse `&pat` / `&mut pat`.
     fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> {
         self.expect_and()?;
+        self.recover_lifetime_in_deref_pat();
         let mutbl = self.parse_mutability();
+        let subpat = self.parse_pat_with_range_pat(false, expected)?;
+        Ok(PatKind::Ref(subpat, mutbl))
+    }
 
+    fn recover_lifetime_in_deref_pat(&mut self) {
         if let token::Lifetime(name) = self.token.kind {
-            let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", name));
-            err.span_label(self.token.span, "unexpected lifetime");
-            return Err(err);
-        }
+            self.bump(); // `'a`
 
-        let subpat = self.parse_pat_with_range_pat(false, expected)?;
-        Ok(PatKind::Ref(subpat, mutbl))
+            let span = self.prev_span;
+            self.struct_span_err(span, &format!("unexpected lifetime `{}` in pattern", name))
+                .span_suggestion(
+                    span,
+                    "remove the lifetime",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+        }
     }
 
     /// Parse a tuple or parenthesis pattern.
diff --git a/src/test/ui/parser/lifetime-in-pattern-recover.rs b/src/test/ui/parser/lifetime-in-pattern-recover.rs
new file mode 100644
index 0000000000000..7fb14b8007671
--- /dev/null
+++ b/src/test/ui/parser/lifetime-in-pattern-recover.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let &'a x = &0; //~ ERROR unexpected lifetime `'a` in pattern
+    let &'a mut y = &mut 0; //~ ERROR unexpected lifetime `'a` in pattern
+
+    let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/lifetime-in-pattern-recover.stderr b/src/test/ui/parser/lifetime-in-pattern-recover.stderr
new file mode 100644
index 0000000000000..4bf7f57bfb59f
--- /dev/null
+++ b/src/test/ui/parser/lifetime-in-pattern-recover.stderr
@@ -0,0 +1,23 @@
+error: unexpected lifetime `'a` in pattern
+  --> $DIR/lifetime-in-pattern-recover.rs:2:10
+   |
+LL |     let &'a x = &0;
+   |          ^^ help: remove the lifetime
+
+error: unexpected lifetime `'a` in pattern
+  --> $DIR/lifetime-in-pattern-recover.rs:3:10
+   |
+LL |     let &'a mut y = &mut 0;
+   |          ^^ help: remove the lifetime
+
+error[E0308]: mismatched types
+  --> $DIR/lifetime-in-pattern-recover.rs:5:33
+   |
+LL |     let _recovery_witness: () = 0;
+   |                            --   ^ expected `()`, found integer
+   |                            |
+   |                            expected due to this
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/lifetime-in-pattern.rs b/src/test/ui/parser/lifetime-in-pattern.rs
index afee685cd056f..d3c638d0cd74b 100644
--- a/src/test/ui/parser/lifetime-in-pattern.rs
+++ b/src/test/ui/parser/lifetime-in-pattern.rs
@@ -1,5 +1,6 @@
 fn test(&'a str) {
     //~^ ERROR unexpected lifetime `'a` in pattern
+    //~| ERROR expected one of `:`, `@`, or `|`, found `)`
 }
 
 fn main() {
diff --git a/src/test/ui/parser/lifetime-in-pattern.stderr b/src/test/ui/parser/lifetime-in-pattern.stderr
index e525c7b6d680f..71fd3cdf72370 100644
--- a/src/test/ui/parser/lifetime-in-pattern.stderr
+++ b/src/test/ui/parser/lifetime-in-pattern.stderr
@@ -2,7 +2,13 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/lifetime-in-pattern.rs:1:10
    |
 LL | fn test(&'a str) {
-   |          ^^ unexpected lifetime
+   |          ^^ help: remove the lifetime
 
-error: aborting due to previous error
+error: expected one of `:`, `@`, or `|`, found `)`
+  --> $DIR/lifetime-in-pattern.rs:1:16
+   |
+LL | fn test(&'a str) {
+   |                ^ expected one of `:`, `@`, or `|`
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/self/self-vs-path-ambiguity.stderr b/src/test/ui/self/self-vs-path-ambiguity.stderr
index 5ce6a81bfcfd7..2beef50cdb5c6 100644
--- a/src/test/ui/self/self-vs-path-ambiguity.stderr
+++ b/src/test/ui/self/self-vs-path-ambiguity.stderr
@@ -2,7 +2,7 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/self-vs-path-ambiguity.rs:9:11
    |
 LL |     fn i(&'a self::S: &S) {}
-   |           ^^ unexpected lifetime
+   |           ^^ help: remove the lifetime
 
 error: aborting due to previous error