From 54db272cc972f232cc50a7c6dff30140f904738a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 26 Jan 2024 17:15:43 +0000 Subject: [PATCH] Better error message in ed 2015 --- compiler/rustc_parse/messages.ftl | 2 + compiler/rustc_parse/src/errors.rs | 9 ++++ compiler/rustc_parse/src/parser/ty.rs | 15 +++++- .../async-fn/edition-2015-not-async-bound.rs | 10 ++++ tests/ui/async-await/async-fn/edition-2015.rs | 11 ++-- .../async-await/async-fn/edition-2015.stderr | 53 +++++++++++++------ 6 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index aac8c0b3103..7c2ecf34c17 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -22,6 +22,8 @@ parse_associated_static_item_not_allowed = associated `static` items are not all parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later +parse_async_bound_modifier_in_2015 = `async` trait bounds are only allowed in Rust 2018 or later + parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015 .label = to use `async fn`, switch to Rust 2018 or later diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 4e4bf9bdad9..86a64d90deb 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1588,6 +1588,15 @@ pub(crate) struct AsyncMoveBlockIn2015 { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_async_bound_modifier_in_2015)] +pub(crate) struct AsyncBoundModifierIn2015 { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub help: HelpUseLatestEdition, +} + #[derive(Diagnostic)] #[diag(parse_self_argument_pointer)] pub(crate) struct SelfArgumentPointer { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 72089dc2a91..5fe54a536a7 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -3,8 +3,8 @@ use super::{Parser, PathStyle, TokenType}; use crate::errors::{ self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg, - InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, - ReturnTypesUseThinArrow, + HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, + NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -882,6 +882,17 @@ impl<'a> Parser<'a> { let asyncness = if self.token.span.at_least_rust_2018() && self.eat_keyword(kw::Async) { self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span); BoundAsyncness::Async(self.prev_token.span) + } else if self.may_recover() + && self.token.span.is_rust_2015() + && self.is_kw_followed_by_ident(kw::Async) + { + self.bump(); // eat `async` + self.dcx().emit_err(errors::AsyncBoundModifierIn2015 { + span: self.prev_token.span, + help: HelpUseLatestEdition::new(), + }); + self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span); + BoundAsyncness::Async(self.prev_token.span) } else { BoundAsyncness::Normal }; diff --git a/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs b/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs new file mode 100644 index 00000000000..6436787b665 --- /dev/null +++ b/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs @@ -0,0 +1,10 @@ +// check-pass +// Make sure that we don't eagerly recover `async ::Bound` in edition 2015. + +mod async { + pub trait Foo {} +} + +fn test(x: impl async ::Foo) {} + +fn main() {} diff --git a/tests/ui/async-await/async-fn/edition-2015.rs b/tests/ui/async-await/async-fn/edition-2015.rs index 287d05ecacb..83b9d415dda 100644 --- a/tests/ui/async-await/async-fn/edition-2015.rs +++ b/tests/ui/async-await/async-fn/edition-2015.rs @@ -1,8 +1,7 @@ -// FIXME(async_closures): This error message could be made better. - -fn foo(x: impl async Fn()) -> impl async Fn() {} -//~^ ERROR expected -//~| ERROR expected -//~| ERROR expected +fn foo(x: impl async Fn()) -> impl async Fn() { x } +//~^ ERROR `async` trait bounds are only allowed in Rust 2018 or later +//~| ERROR `async` trait bounds are only allowed in Rust 2018 or later +//~| ERROR async closures are unstable +//~| ERROR async closures are unstable fn main() {} diff --git a/tests/ui/async-await/async-fn/edition-2015.stderr b/tests/ui/async-await/async-fn/edition-2015.stderr index e79b92ccf9f..0029d53868d 100644 --- a/tests/ui/async-await/async-fn/edition-2015.stderr +++ b/tests/ui/async-await/async-fn/edition-2015.stderr @@ -1,22 +1,43 @@ -error: expected one of `:` or `|`, found `)` - --> $DIR/edition-2015.rs:3:26 +error: `async` trait bounds are only allowed in Rust 2018 or later + --> $DIR/edition-2015.rs:1:16 | -LL | fn foo(x: impl async Fn()) -> impl async Fn() {} - | ^ expected one of `:` or `|` - -error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `Fn` - --> $DIR/edition-2015.rs:3:22 +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^^ | -LL | fn foo(x: impl async Fn()) -> impl async Fn() {} - | -^^ expected one of `(`, `)`, `+`, `,`, `::`, or `<` - | | - | help: missing `,` + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error: expected one of `(`, `+`, `::`, `<`, `where`, or `{`, found `Fn` - --> $DIR/edition-2015.rs:3:42 +error: `async` trait bounds are only allowed in Rust 2018 or later + --> $DIR/edition-2015.rs:1:36 | -LL | fn foo(x: impl async Fn()) -> impl async Fn() {} - | ^^ expected one of `(`, `+`, `::`, `<`, `where`, or `{` +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^^ + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error: aborting due to 3 previous errors +error[E0658]: async closures are unstable + --> $DIR/edition-2015.rs:1:16 + | +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: to use an async block, remove the `||`: `async {` +error[E0658]: async closures are unstable + --> $DIR/edition-2015.rs:1:36 + | +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: to use an async block, remove the `||`: `async {` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`.