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 ```
This commit is contained in:
commit
9cda9e0ab6
4 changed files with 155 additions and 5 deletions
|
@ -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) {
|
||||
|
@ -938,6 +940,36 @@ impl<'a> Parser<'a> {
|
|||
&& self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
|
||||
&& 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)?
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue