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 parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
.label = to use `async fn`, switch to Rust 2018 or later .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_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 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect

View File

@ -2975,3 +2975,10 @@ pub(crate) struct ArrayIndexInOffsetOf(#[primary_span] pub Span);
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(parse_invalid_offset_of)] #[diag(parse_invalid_offset_of)]
pub(crate) struct InvalidOffsetOf(#[primary_span] pub Span); 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 @@ impl<'a> Parser<'a> {
self.sess.gated_spans.gate(sym::const_trait_impl, span); 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(); let polarity = self.parse_polarity();
// Parse both types and traits as a type, then reinterpret if necessary. // Parse both types and traits as a type, then reinterpret if necessary.

View File

@ -778,9 +778,10 @@ impl<'a> Parser<'a> {
|| self.check(&token::Not) || self.check(&token::Not)
|| self.check(&token::Question) || self.check(&token::Question)
|| self.check(&token::Tilde) || self.check(&token::Tilde)
|| self.check_keyword(kw::Const)
|| self.check_keyword(kw::For) || self.check_keyword(kw::For)
|| self.check(&token::OpenDelim(Delimiter::Parenthesis)) || self.check(&token::OpenDelim(Delimiter::Parenthesis))
|| self.check_keyword(kw::Const)
|| self.check_keyword(kw::Async)
} }
/// Parses a bound according to the grammar: /// Parses a bound according to the grammar:
@ -882,11 +883,13 @@ impl<'a> Parser<'a> {
BoundConstness::Never 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); self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span);
BoundAsyncness::Async(self.prev_token.span) BoundAsyncness::Async(self.prev_token.span)
} else if self.may_recover() } 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.is_kw_followed_by_ident(kw::Async)
{ {
self.bump(); // eat `async` self.bump(); // eat `async`

View File

@ -3,6 +3,10 @@
struct F; struct F;
impl async Fn<()> for 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() {} 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 --> $DIR/impl-header.rs:5:6
| |
LL | impl async Fn<()> for F {} 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 //@ edition:2021
// for the `impl` + keyword test // for the `impl` + keyword test
@ -11,5 +11,7 @@ macro_rules! impl_primitive {
} }
impl_primitive!(impl async); impl_primitive!(impl async);
//~^ ERROR expected identifier, found `<eof>`
//~| ERROR async closures are unstable
fn main() {} 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 foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds
fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{` 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 //~| ERROR at least one trait is required for an object type
fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<` 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>}) {} LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| ^ expected parameter name | ^ 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 --> $DIR/trait-object-delimiters.rs:10:17
| |
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| -^ expected one of 11 possible tokens | -^ expected one of 12 possible tokens
| | | |
| help: missing `,` | help: missing `,`

View File

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

View File

@ -1,31 +1,45 @@
error: expected identifier, found `<eof>` error: ty
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:13:14 --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:8:19
| |
LL | ($ty:ty) => { compile_error!("ty"); }; LL | ($ty:ty) => { compile_error!("ty"); };
| ------ while parsing argument for this `ty` macro fragment | ^^^^^^^^^^^^^^^^^^^^
... ...
LL | demo! { impl const } LL | demo! { impl const Trait }
| ^^^^^ expected identifier | -------------------------- 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>` error: ty
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13 --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:8:19
| |
LL | ($ty:ty) => { compile_error!("ty"); }; LL | ($ty:ty) => { compile_error!("ty"); };
| ------ while parsing argument for this `ty` macro fragment | ^^^^^^^^^^^^^^^^^^^^
... ...
LL | demo! { dyn const } LL | demo! { dyn const Trait }
| ^^^^^ expected identifier | ------------------------- 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 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 = 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 = 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 = 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[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 4 previous errors
For more information about this error, try `rustc --explain E0658`. For more information about this error, try `rustc --explain E0658`.