From c692896ba27adc1c14941593349c76bd27e189f5 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Fri, 2 Jul 2021 17:07:32 +0200 Subject: [PATCH] Recover from `&dyn mut ...` parse errors --- compiler/rustc_parse/src/parser/ty.rs | 22 ++++++++++++++++++- src/test/ui/parser/recover-ref-dyn-mut.rs | 9 ++++++++ src/test/ui/parser/recover-ref-dyn-mut.stderr | 15 +++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/recover-ref-dyn-mut.rs create mode 100644 src/test/ui/parser/recover-ref-dyn-mut.stderr diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index de5a5632600e4..1fbf01b1b97d5 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -393,7 +393,7 @@ impl<'a> Parser<'a> { let and_span = self.prev_token.span; let mut opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; - let mutbl = self.parse_mutability(); + let mut mutbl = self.parse_mutability(); if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() { // A lifetime is invalid here: it would be part of a bare trait bound, which requires // it to be followed by a plus, but we disallow plus in the pointee type. @@ -417,6 +417,26 @@ impl<'a> Parser<'a> { opt_lifetime = Some(self.expect_lifetime()); } + } else if self.token.is_keyword(kw::Dyn) + && mutbl == Mutability::Not + && self.look_ahead(1, |t| t.is_keyword(kw::Mut)) + { + // We have `&dyn mut ...`, which is invalid and should be `&mut dyn ...`. + let span = and_span.to(self.look_ahead(1, |t| t.span)); + let mut err = self.struct_span_err(span, "`mut` must precede `dyn`"); + err.span_suggestion( + span, + "place `mut` before `dyn`", + "&mut dyn".to_string(), + Applicability::MachineApplicable, + ); + err.emit(); + + // Recovery + mutbl = Mutability::Mut; + let (dyn_tok, dyn_tok_sp) = (self.token.clone(), self.token_spacing); + self.bump(); + self.bump_with((dyn_tok, dyn_tok_sp)); } let ty = self.parse_ty_no_plus()?; Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })) diff --git a/src/test/ui/parser/recover-ref-dyn-mut.rs b/src/test/ui/parser/recover-ref-dyn-mut.rs new file mode 100644 index 0000000000000..3016275cc0fd2 --- /dev/null +++ b/src/test/ui/parser/recover-ref-dyn-mut.rs @@ -0,0 +1,9 @@ +// Test that the parser detects `&dyn mut`, offers a help message, and +// recovers. + +fn main() { + let r: &dyn mut Trait; + //~^ ERROR: `mut` must precede `dyn` + //~| HELP: place `mut` before `dyn` + //~| ERROR: cannot find trait `Trait` in this scope [E0405] +} diff --git a/src/test/ui/parser/recover-ref-dyn-mut.stderr b/src/test/ui/parser/recover-ref-dyn-mut.stderr new file mode 100644 index 0000000000000..c048c8ea1b0dd --- /dev/null +++ b/src/test/ui/parser/recover-ref-dyn-mut.stderr @@ -0,0 +1,15 @@ +error: `mut` must precede `dyn` + --> $DIR/recover-ref-dyn-mut.rs:5:12 + | +LL | let r: &dyn mut Trait; + | ^^^^^^^^ help: place `mut` before `dyn`: `&mut dyn` + +error[E0405]: cannot find trait `Trait` in this scope + --> $DIR/recover-ref-dyn-mut.rs:5:21 + | +LL | let r: &dyn mut Trait; + | ^^^^^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0405`.