Skip to content

Commit a8a2ee4

Browse files
Recover dyn and impl after for<...>
1 parent 85b8450 commit a8a2ee4

File tree

5 files changed

+95
-3
lines changed

5 files changed

+95
-3
lines changed

compiler/rustc_parse/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,9 @@ parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
739739
parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
740740
parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
741741
742+
parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before
743+
.suggestion = move `{$kw}` before the `for<...>`
744+
742745
parse_type_ascription_removed =
743746
if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
744747

compiler/rustc_parse/src/errors.rs

+20
Original file line numberDiff line numberDiff line change
@@ -2828,3 +2828,23 @@ pub(crate) struct GenericArgsInPatRequireTurbofishSyntax {
28282828
)]
28292829
pub suggest_turbofish: Span,
28302830
}
2831+
2832+
#[derive(Diagnostic)]
2833+
#[diag(parse_transpose_dyn_or_impl)]
2834+
pub(crate) struct TransposeDynOrImpl<'a> {
2835+
#[primary_span]
2836+
pub span: Span,
2837+
pub kw: &'a str,
2838+
#[subdiagnostic]
2839+
pub sugg: TransposeDynOrImplSugg<'a>,
2840+
}
2841+
2842+
#[derive(Subdiagnostic)]
2843+
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
2844+
pub(crate) struct TransposeDynOrImplSugg<'a> {
2845+
#[suggestion_part(code = "")]
2846+
pub removal_span: Span,
2847+
#[suggestion_part(code = "{kw} ")]
2848+
pub insertion_span: Span,
2849+
pub kw: &'a str,
2850+
}

compiler/rustc_parse/src/parser/ty.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ impl<'a> Parser<'a> {
287287
// Function pointer type
288288
self.parse_ty_bare_fn(lo, ThinVec::new(), None, recover_return_sign)?
289289
} else if self.check_keyword(kw::For) {
290+
let for_span = self.token.span;
290291
// Function pointer type or bound list (trait object type) starting with a poly-trait.
291292
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
292293
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
@@ -299,9 +300,42 @@ impl<'a> Parser<'a> {
299300
recover_return_sign,
300301
)?
301302
} else {
302-
let path = self.parse_path(PathStyle::Type)?;
303-
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
304-
self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?
303+
// Try to recover `for<'a> dyn Trait` or `for<'a> impl Trait`.
304+
if self.may_recover()
305+
&& (self.eat_keyword_noexpect(kw::Impl) || self.eat_keyword_noexpect(kw::Dyn))
306+
{
307+
let kw = self.prev_token.ident().unwrap().0.name;
308+
let mut err = self.sess.create_err(errors::TransposeDynOrImpl {
309+
span: self.prev_token.span,
310+
kw: kw.as_str(),
311+
sugg: errors::TransposeDynOrImplSugg {
312+
removal_span: self.prev_token.span.with_hi(self.token.span.lo()),
313+
insertion_span: for_span.shrink_to_lo(),
314+
kw: kw.as_str(),
315+
},
316+
});
317+
let path = self.parse_path(PathStyle::Type)?;
318+
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
319+
let kind =
320+
self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?;
321+
// Take the parsed bare trait object and turn it either
322+
// into a `dyn` object or an `impl Trait`.
323+
let kind = match (kind, kw) {
324+
(TyKind::TraitObject(bounds, _), kw::Dyn) => {
325+
TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
326+
}
327+
(TyKind::TraitObject(bounds, _), kw::Impl) => {
328+
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
329+
}
330+
_ => return Err(err),
331+
};
332+
err.emit();
333+
kind
334+
} else {
335+
let path = self.parse_path(PathStyle::Type)?;
336+
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
337+
self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?
338+
}
305339
}
306340
} else if self.eat_keyword(kw::Impl) {
307341
self.parse_impl_ty(&mut impl_dyn_multi)?
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
trait Trait {}
2+
3+
fn test(_: &for<'a> dyn Trait) {}
4+
//~^ ERROR `for<...>` expected after `dyn`, not before
5+
6+
fn test2(_: for<'a> impl Trait) {}
7+
//~^ ERROR `for<...>` expected after `impl`, not before
8+
9+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: `for<...>` expected after `dyn`, not before
2+
--> $DIR/recover-hrtb-before-dyn-impl-kw.rs:3:21
3+
|
4+
LL | fn test(_: &for<'a> dyn Trait) {}
5+
| ^^^
6+
|
7+
help: move `dyn` before the `for<...>`
8+
|
9+
LL - fn test(_: &for<'a> dyn Trait) {}
10+
LL + fn test(_: &dyn for<'a> Trait) {}
11+
|
12+
13+
error: `for<...>` expected after `impl`, not before
14+
--> $DIR/recover-hrtb-before-dyn-impl-kw.rs:6:21
15+
|
16+
LL | fn test2(_: for<'a> impl Trait) {}
17+
| ^^^^
18+
|
19+
help: move `impl` before the `for<...>`
20+
|
21+
LL - fn test2(_: for<'a> impl Trait) {}
22+
LL + fn test2(_: impl for<'a> Trait) {}
23+
|
24+
25+
error: aborting due to 2 previous errors
26+

0 commit comments

Comments
 (0)