diff options
| author | Yuki Okushi <jtitor@2k36.org> | 2021-07-08 10:44:30 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-07-08 10:44:30 +0900 |
| commit | 165b520b89e9e2f27442a3af793c6d65e76e0981 (patch) | |
| tree | 97a89bf075041462d6449adda57b31dfdaf2b55b | |
| parent | c2d3f5f7725a15fb3ad8ec88fbf89596f3ce9aea (diff) | |
| parent | c692896ba27adc1c14941593349c76bd27e189f5 (diff) | |
| download | rust-165b520b89e9e2f27442a3af793c6d65e76e0981.tar.gz rust-165b520b89e9e2f27442a3af793c6d65e76e0981.zip | |
Rollup merge of #86812 - FabianWolff:recover-dyn-mut, r=petrochenkov
Recover from `&dyn mut ...` parse errors
Consider this example:
```rust
fn main() {
let r: &dyn mut Trait;
}
```
This currently leads to:
```
error: expected one of `!`, `(`, `;`, `=`, `?`, `for`, lifetime, or path, found keyword `mut`
--> src/main.rs:2:17
|
2 | let r: &dyn mut Trait;
| ^^^ expected one of 8 possible tokens
error: aborting due to previous error
```
However, especially for beginners, I think it is easy to get `&dyn mut` and `&mut dyn` confused. With my changes, I get a help message, and the parser even recovers:
```
error: `mut` must precede `dyn`
--> test.rs:2:12
|
2 | let r: &dyn mut Trait;
| ^^^^^^^^ help: place `mut` before `dyn`: `&mut dyn`
error[E0405]: cannot find trait `Trait` in this scope
--> test.rs:2:21
|
2 | let r: &dyn mut Trait;
| ^^^^^ not found in this scope
error: aborting due to 2 previous errors
```
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 22 | ||||
| -rw-r--r-- | src/test/ui/parser/recover-ref-dyn-mut.rs | 9 | ||||
| -rw-r--r-- | src/test/ui/parser/recover-ref-dyn-mut.stderr | 15 |
3 files changed, 45 insertions, 1 deletions
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index de5a5632600..1fbf01b1b97 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 00000000000..3016275cc0f --- /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 00000000000..c048c8ea1b0 --- /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`. |
