diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2023-01-17 05:25:21 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-17 05:25:21 +0100 |
| commit | 9cda9e0ab62467199e09644258618343bd40d52e (patch) | |
| tree | 465aa506c27ca589296a3c6ae1f60bdad1d971ff /compiler/rustc_parse | |
| parent | f74044259a4f9392203f3b28d9e9172be22f2fef (diff) | |
| parent | fcd5ed21b77dd1d72696e43dd70e60b1ad458f55 (diff) | |
| download | rust-9cda9e0ab62467199e09644258618343bd40d52e.tar.gz rust-9cda9e0ab62467199e09644258618343bd40d52e.zip | |
Rollup merge of #106712 - Ezrashaw:impl-ref-trait, r=estebank
make error emitted on `impl &Trait` nicer
Fixes #106694
Turned out to be simpler than I thought, also added UI test.
Before: ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9bda53271ef3a8886793cf427b8cea91))
```text
error: expected one of `:`, ``@`,` or `|`, found `)`
--> src/main.rs:2:22
|
2 | fn foo(_: impl &Trait) {}
| ^ expected one of `:`, ``@`,` or `|`
|
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
help: if this is a parameter name, give it a type
|
2 | fn foo(_: impl Trait: &TypeName) {}
| ~~~~~~~~~~~~~~~~
help: if this is a type, explicitly ignore the parameter name
|
2 | fn foo(_: impl _: &Trait) {}
| ++
error: expected one of `!`, `(`, `)`, `,`, `?`, `for`, `~`, lifetime, or path, found `&`
--> src/main.rs:2:16
|
2 | fn foo(_: impl &Trait) {}
| -^ expected one of 9 possible tokens
| |
| help: missing `,`
error: expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, `~`, lifetime, or path, found `&`
--> src/main.rs:3:11
|
3 | fn bar<T: &Trait>(_: T) {}
| ^ expected one of 10 possible tokens
```
After:
```text
error: expected a trait, found type
--> <anon>:2:16
|
2 | fn foo(_: impl &Trait) {}
| -^^^^^
| |
| help: consider removing the indirection
error: expected a trait, found type
--> <anon>:3:11
|
3 | fn bar<T: &Trait>(_: T) {}
| -^^^^^
| |
| help: consider removing the indirection
```
Diffstat (limited to 'compiler/rustc_parse')
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a6f702e5428..1766b0293de 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -727,11 +727,13 @@ impl<'a> Parser<'a> { let mut bounds = Vec::new(); let mut negative_bounds = Vec::new(); + // In addition to looping while we find generic bounds: + // We continue even if we find a keyword. This is necessary for error recovery on, + // for example, `impl fn()`. The only keyword that can go after generic bounds is + // `where`, so stop if it's it. + // We also continue if we find types (not traits), again for error recovery. while self.can_begin_bound() - // Continue even if we find a keyword. - // This is necessary for error recover on, for example, `impl fn()`. - // - // The only keyword that can go after generic bounds is `where`, so stop if it's it. + || self.token.can_begin_type() || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where)) { if self.token.is_keyword(kw::Dyn) { @@ -939,6 +941,36 @@ impl<'a> Parser<'a> { && let Some(path) = self.recover_path_from_fn() { path + } else if !self.token.is_path_start() && self.token.can_begin_type() { + let ty = self.parse_ty_no_plus()?; + // Instead of finding a path (a trait), we found a type. + let mut err = self.struct_span_err(ty.span, "expected a trait, found type"); + + // If we can recover, try to extract a path from the type. Note + // that we do not use the try operator when parsing the type because + // if it fails then we get a parser error which we don't want (we're trying + // to recover from errors, not make more). + let path = if self.may_recover() + && matches!(ty.kind, TyKind::Ptr(..) | TyKind::Ref(..)) + && let TyKind::Path(_, path) = &ty.peel_refs().kind { + // Just get the indirection part of the type. + let span = ty.span.until(path.span); + + err.span_suggestion_verbose( + span, + "consider removing the indirection", + "", + Applicability::MaybeIncorrect, + ); + + path.clone() + } else { + return Err(err); + }; + + err.emit(); + + path } else { self.parse_path(PathStyle::Type)? }; |
