Support async trait bounds in macros

This commit is contained in:
Michael Goulet 2024-02-20 16:09:03 +00:00
parent 29f87ade9d
commit 9c8b107955
16 changed files with 229 additions and 31 deletions

View file

@ -27,6 +27,8 @@ parse_async_bound_modifier_in_2015 = `async` trait bounds are only allowed in Ru
parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
.label = to use `async fn`, switch to Rust 2018 or later
parse_async_impl = `async` trait implementations are unsupported
parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 2018 or later
parse_async_move_order_incorrect = the order of `move` and `async` is incorrect

View file

@ -2975,3 +2975,10 @@ pub(crate) struct TransposeDynOrImplSugg<'a> {
#[derive(Diagnostic)]
#[diag(parse_invalid_offset_of)]
pub(crate) struct InvalidOffsetOf(#[primary_span] pub Span);
#[derive(Diagnostic)]
#[diag(parse_async_impl)]
pub(crate) struct AsyncImpl {
#[primary_span]
pub span: Span,
}

View file

@ -562,6 +562,15 @@ fn parse_item_impl(
self.sess.gated_spans.gate(sym::const_trait_impl, span);
}
// Parse stray `impl async Trait`
if (self.token.uninterpolated_span().at_least_rust_2018()
&& self.token.is_keyword(kw::Async))
|| self.is_kw_followed_by_ident(kw::Async)
{
self.bump();
self.dcx().emit_err(errors::AsyncImpl { span: self.prev_token.span });
}
let polarity = self.parse_polarity();
// Parse both types and traits as a type, then reinterpret if necessary.

View file

@ -778,9 +778,10 @@ fn can_begin_bound(&mut self) -> bool {
|| self.check(&token::Not)
|| self.check(&token::Question)
|| self.check(&token::Tilde)
|| self.check_keyword(kw::Const)
|| self.check_keyword(kw::For)
|| self.check(&token::OpenDelim(Delimiter::Parenthesis))
|| self.check_keyword(kw::Const)
|| self.check_keyword(kw::Async)
}
/// Parses a bound according to the grammar:
@ -882,11 +883,13 @@ fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
BoundConstness::Never
};
let asyncness = if self.token.span.at_least_rust_2018() && self.eat_keyword(kw::Async) {
let asyncness = if self.token.uninterpolated_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.token.uninterpolated_span().is_rust_2015()
&& self.is_kw_followed_by_ident(kw::Async)
{
self.bump(); // eat `async`

View file

@ -3,6 +3,10 @@
struct F;
impl async Fn<()> for F {}
//~^ ERROR expected type, found keyword `async`
//~^ ERROR `async` trait implementations are unsupported
//~| ERROR the precise format of `Fn`-family traits' type parameters is subject to change
//~| ERROR manual implementations of `Fn` are experimental
//~| ERROR expected a `FnMut()` closure, found `F`
//~| ERROR not all trait items implemented, missing: `call`
fn main() {}

View file

@ -1,8 +1,47 @@
error: expected type, found keyword `async`
error: `async` trait implementations are unsupported
--> $DIR/impl-header.rs:5:6
|
LL | impl async Fn<()> for F {}
| ^^^^^ expected type
| ^^^^^
error: aborting due to 1 previous error
error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
--> $DIR/impl-header.rs:5:12
|
LL | impl async Fn<()> for F {}
| ^^^^^^
|
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0183]: manual implementations of `Fn` are experimental
--> $DIR/impl-header.rs:5:12
|
LL | impl async Fn<()> for F {}
| ^^^^^^ manual implementations of `Fn` are experimental
|
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
error[E0277]: expected a `FnMut()` closure, found `F`
--> $DIR/impl-header.rs:5:23
|
LL | impl async Fn<()> for F {}
| ^ expected an `FnMut()` closure, found `F`
|
= help: the trait `FnMut<()>` is not implemented for `F`
= note: wrap the `F` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `Fn`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
error[E0046]: not all trait items implemented, missing: `call`
--> $DIR/impl-header.rs:5:1
|
LL | impl async Fn<()> for F {}
| ^^^^^^^^^^^^^^^^^^^^^^^ missing `call` in implementation
|
= help: implement the missing item: `fn call(&self, _: ()) -> <Self as FnOnce<()>>::Output { todo!() }`
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0046, E0183, E0277, E0658.
For more information about an error, try `rustc --explain E0046`.

View file

@ -0,0 +1,21 @@
// Demonstrates and records a theoretical regressions / breaking changes caused by the
// introduction of async trait bounds.
// Setting the edition to 2018 since we don't regress `demo! { dyn async }` in Rust <2018.
//@ edition:2018
macro_rules! demo {
($ty:ty) => { compile_error!("ty"); };
//~^ ERROR ty
//~| ERROR ty
(impl $c:ident Trait) => {};
(dyn $c:ident Trait) => {};
}
demo! { impl async Trait }
//~^ ERROR async closures are unstable
demo! { dyn async Trait }
//~^ ERROR async closures are unstable
fn main() {}

View file

@ -0,0 +1,47 @@
error: ty
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:8:19
|
LL | ($ty:ty) => { compile_error!("ty"); };
| ^^^^^^^^^^^^^^^^^^^^
...
LL | demo! { impl async Trait }
| -------------------------- in this macro invocation
|
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
error: ty
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:8:19
|
LL | ($ty:ty) => { compile_error!("ty"); };
| ^^^^^^^^^^^^^^^^^^^^
...
LL | demo! { dyn async Trait }
| ------------------------- in this macro invocation
|
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0658]: async closures are unstable
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:15:14
|
LL | demo! { impl async Trait }
| ^^^^^
|
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/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/mbe-async-trait-bound-theoretical-regression.rs:18:13
|
LL | demo! { dyn async Trait }
| ^^^^^
|
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/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`.

View file

@ -0,0 +1,12 @@
//@ edition: 2021
macro_rules! x {
($x:item) => {}
}
x! {
async fn foo() -> impl async Fn() { }
//~^ ERROR async closures are unstable
}
fn main() {}

View file

@ -0,0 +1,14 @@
error[E0658]: async closures are unstable
--> $DIR/trait-bounds-in-macro.rs:8:28
|
LL | async fn foo() -> impl async Fn() { }
| ^^^^^
|
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/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 1 previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,4 +1,4 @@
//@ check-pass
// This is just `mbe-async-trait-bound-theoretical-regression.rs` in practice.
//@ edition:2021
// for the `impl` + keyword test
@ -11,5 +11,7 @@ macro_rules! impl_primitive {
}
impl_primitive!(impl async);
//~^ ERROR expected identifier, found `<eof>`
//~| ERROR async closures are unstable
fn main() {}

View file

@ -0,0 +1,23 @@
error: expected identifier, found `<eof>`
--> $DIR/bad-recover-kw-after-impl.rs:13:22
|
LL | ($ty:ty) => {
| ------ while parsing argument for this `ty` macro fragment
...
LL | impl_primitive!(impl async);
| ^^^^^ expected identifier
error[E0658]: async closures are unstable
--> $DIR/bad-recover-kw-after-impl.rs:13:22
|
LL | impl_primitive!(impl async);
| ^^^^^
|
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/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 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around t
fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds
fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `const`, `for`, `~`, lifetime, or path, found `{`
//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{`
//~| ERROR at least one trait is required for an object type
fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`

View file

@ -34,11 +34,11 @@ error: expected parameter name, found `{`
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| ^ expected parameter name
error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `const`, `for`, `~`, lifetime, or path, found `{`
error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{`
--> $DIR/trait-object-delimiters.rs:10:17
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| -^ expected one of 11 possible tokens
| -^ expected one of 12 possible tokens
| |
| help: missing `,`

View file

@ -6,15 +6,16 @@
macro_rules! demo {
($ty:ty) => { compile_error!("ty"); };
(impl $c:ident) => {};
(dyn $c:ident) => {};
//~^ ERROR ty
//~| ERROR ty
(impl $c:ident Trait) => {};
(dyn $c:ident Trait) => {};
}
demo! { impl const }
//~^ ERROR expected identifier, found `<eof>`
demo! { dyn const }
demo! { impl const Trait }
//~^ ERROR const trait impls are experimental
demo! { dyn const Trait }
//~^ ERROR const trait impls are experimental
//~| ERROR expected identifier, found `<eof>`
fn main() {}

View file

@ -1,31 +1,45 @@
error: expected identifier, found `<eof>`
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:13:14
error: ty
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:8:19
|
LL | ($ty:ty) => { compile_error!("ty"); };
| ------ while parsing argument for this `ty` macro fragment
| ^^^^^^^^^^^^^^^^^^^^
...
LL | demo! { impl const }
| ^^^^^ expected identifier
LL | demo! { impl const Trait }
| -------------------------- in this macro invocation
|
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected identifier, found `<eof>`
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13
error: ty
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:8:19
|
LL | ($ty:ty) => { compile_error!("ty"); };
| ------ while parsing argument for this `ty` macro fragment
| ^^^^^^^^^^^^^^^^^^^^
...
LL | demo! { dyn const }
| ^^^^^ expected identifier
LL | demo! { dyn const Trait }
| ------------------------- in this macro invocation
|
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0658]: const trait impls are experimental
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:15:14
|
LL | demo! { dyn const }
LL | demo! { impl const Trait }
| ^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: const trait impls are experimental
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:18:13
|
LL | demo! { dyn const Trait }
| ^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 3 previous errors
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0658`.