Skip to content

Commit 9cda9e0

Browse files
authored
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 ```
2 parents f740442 + fcd5ed2 commit 9cda9e0

File tree

4 files changed

+155
-5
lines changed

4 files changed

+155
-5
lines changed

compiler/rustc_ast/src/ast.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2032,7 +2032,8 @@ impl Clone for Ty {
20322032
impl Ty {
20332033
pub fn peel_refs(&self) -> &Self {
20342034
let mut final_ty = self;
2035-
while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
2035+
while let TyKind::Ref(_, MutTy { ty, .. }) | TyKind::Ptr(MutTy { ty, .. }) = &final_ty.kind
2036+
{
20362037
final_ty = ty;
20372038
}
20382039
final_ty

compiler/rustc_parse/src/parser/ty.rs

+36-4
Original file line numberDiff line numberDiff line change
@@ -727,11 +727,13 @@ impl<'a> Parser<'a> {
727727
let mut bounds = Vec::new();
728728
let mut negative_bounds = Vec::new();
729729

730+
// In addition to looping while we find generic bounds:
731+
// We continue even if we find a keyword. This is necessary for error recovery on,
732+
// for example, `impl fn()`. The only keyword that can go after generic bounds is
733+
// `where`, so stop if it's it.
734+
// We also continue if we find types (not traits), again for error recovery.
730735
while self.can_begin_bound()
731-
// Continue even if we find a keyword.
732-
// This is necessary for error recover on, for example, `impl fn()`.
733-
//
734-
// The only keyword that can go after generic bounds is `where`, so stop if it's it.
736+
|| self.token.can_begin_type()
735737
|| (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where))
736738
{
737739
if self.token.is_keyword(kw::Dyn) {
@@ -938,6 +940,36 @@ impl<'a> Parser<'a> {
938940
&& self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
939941
&& let Some(path) = self.recover_path_from_fn()
940942
{
943+
path
944+
} else if !self.token.is_path_start() && self.token.can_begin_type() {
945+
let ty = self.parse_ty_no_plus()?;
946+
// Instead of finding a path (a trait), we found a type.
947+
let mut err = self.struct_span_err(ty.span, "expected a trait, found type");
948+
949+
// If we can recover, try to extract a path from the type. Note
950+
// that we do not use the try operator when parsing the type because
951+
// if it fails then we get a parser error which we don't want (we're trying
952+
// to recover from errors, not make more).
953+
let path = if self.may_recover()
954+
&& matches!(ty.kind, TyKind::Ptr(..) | TyKind::Ref(..))
955+
&& let TyKind::Path(_, path) = &ty.peel_refs().kind {
956+
// Just get the indirection part of the type.
957+
let span = ty.span.until(path.span);
958+
959+
err.span_suggestion_verbose(
960+
span,
961+
"consider removing the indirection",
962+
"",
963+
Applicability::MaybeIncorrect,
964+
);
965+
966+
path.clone()
967+
} else {
968+
return Err(err);
969+
};
970+
971+
err.emit();
972+
941973
path
942974
} else {
943975
self.parse_path(PathStyle::Type)?

tests/ui/generics/issue-106694.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
trait Trait {}
2+
3+
fn foo(_: impl &Trait) {}
4+
//~^ ERROR expected a trait, found type
5+
6+
fn bar<T: &Trait>(_: T) {}
7+
//~^ ERROR expected a trait, found type
8+
9+
fn partially_correct_impl(_: impl &*const &Trait + Copy) {}
10+
//~^ ERROR expected a trait, found type
11+
12+
fn foo_bad(_: impl &BadTrait) {}
13+
//~^ ERROR expected a trait, found type
14+
//~^^ ERROR cannot find trait `BadTrait` in this scope
15+
16+
fn bar_bad<T: &BadTrait>(_: T) {}
17+
//~^ ERROR expected a trait, found type
18+
//~^^ ERROR cannot find trait `BadTrait` in this scope
19+
20+
fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
21+
//~^ ERROR expected a trait, found type
22+
//~^^ ERROR cannot find trait `BadTrait` in this scope
23+
24+
fn main() {}

tests/ui/generics/issue-106694.stderr

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
error: expected a trait, found type
2+
--> $DIR/issue-106694.rs:3:16
3+
|
4+
LL | fn foo(_: impl &Trait) {}
5+
| ^^^^^^
6+
|
7+
help: consider removing the indirection
8+
|
9+
LL - fn foo(_: impl &Trait) {}
10+
LL + fn foo(_: impl Trait) {}
11+
|
12+
13+
error: expected a trait, found type
14+
--> $DIR/issue-106694.rs:6:11
15+
|
16+
LL | fn bar<T: &Trait>(_: T) {}
17+
| ^^^^^^
18+
|
19+
help: consider removing the indirection
20+
|
21+
LL - fn bar<T: &Trait>(_: T) {}
22+
LL + fn bar<T: Trait>(_: T) {}
23+
|
24+
25+
error: expected a trait, found type
26+
--> $DIR/issue-106694.rs:9:35
27+
|
28+
LL | fn partially_correct_impl(_: impl &*const &Trait + Copy) {}
29+
| ^^^^^^^^^^^^^^
30+
|
31+
help: consider removing the indirection
32+
|
33+
LL - fn partially_correct_impl(_: impl &*const &Trait + Copy) {}
34+
LL + fn partially_correct_impl(_: impl Trait + Copy) {}
35+
|
36+
37+
error: expected a trait, found type
38+
--> $DIR/issue-106694.rs:12:20
39+
|
40+
LL | fn foo_bad(_: impl &BadTrait) {}
41+
| ^^^^^^^^^
42+
|
43+
help: consider removing the indirection
44+
|
45+
LL - fn foo_bad(_: impl &BadTrait) {}
46+
LL + fn foo_bad(_: impl BadTrait) {}
47+
|
48+
49+
error: expected a trait, found type
50+
--> $DIR/issue-106694.rs:16:15
51+
|
52+
LL | fn bar_bad<T: &BadTrait>(_: T) {}
53+
| ^^^^^^^^^
54+
|
55+
help: consider removing the indirection
56+
|
57+
LL - fn bar_bad<T: &BadTrait>(_: T) {}
58+
LL + fn bar_bad<T: BadTrait>(_: T) {}
59+
|
60+
61+
error: expected a trait, found type
62+
--> $DIR/issue-106694.rs:20:39
63+
|
64+
LL | fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
65+
| ^^^^^^^^^^^^^^^^^
66+
|
67+
help: consider removing the indirection
68+
|
69+
LL - fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
70+
LL + fn partially_correct_impl_bad(_: impl BadTrait + Copy) {}
71+
|
72+
73+
error[E0405]: cannot find trait `BadTrait` in this scope
74+
--> $DIR/issue-106694.rs:12:21
75+
|
76+
LL | fn foo_bad(_: impl &BadTrait) {}
77+
| ^^^^^^^^ not found in this scope
78+
79+
error[E0405]: cannot find trait `BadTrait` in this scope
80+
--> $DIR/issue-106694.rs:16:16
81+
|
82+
LL | fn bar_bad<T: &BadTrait>(_: T) {}
83+
| ^^^^^^^^ not found in this scope
84+
85+
error[E0405]: cannot find trait `BadTrait` in this scope
86+
--> $DIR/issue-106694.rs:20:48
87+
|
88+
LL | fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
89+
| ^^^^^^^^ not found in this scope
90+
91+
error: aborting due to 9 previous errors
92+
93+
For more information about this error, try `rustc --explain E0405`.

0 commit comments

Comments
 (0)