Skip to content

Commit

Permalink
Rollup merge of #121044 - compiler-errors:mbe-async-trait-bounds, r=f…
Browse files Browse the repository at this point in the history
…mease

Support async trait bounds in macros

r? fmease

This is similar to your work on const trait bounds. This theoretically regresses `impl async $ident:ident` in macros, but I doubt this is occurring in practice.
  • Loading branch information
fmease authored Feb 21, 2024
2 parents 1d447a9 + 9c8b107 commit 082b97a
Show file tree
Hide file tree
Showing 16 changed files with 228 additions and 30 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2975,3 +2975,10 @@ pub(crate) struct ArrayIndexInOffsetOf(#[primary_span] pub Span);
#[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,
}
9 changes: 9 additions & 0 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,15 @@ impl<'a> Parser<'a> {
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.
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,9 +778,10 @@ impl<'a> Parser<'a> {
|| 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:
Expand Down Expand Up @@ -882,11 +883,13 @@ impl<'a> Parser<'a> {
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`
Expand Down
6 changes: 5 additions & 1 deletion tests/ui/async-await/async-fn/impl-header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
45 changes: 42 additions & 3 deletions tests/ui/async-await/async-fn/impl-header.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
12 changes: 12 additions & 0 deletions tests/ui/async-await/async-fn/trait-bounds-in-macro.rs
Original file line number Diff line number Diff line change
@@ -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() {}
14 changes: 14 additions & 0 deletions tests/ui/async-await/async-fn/trait-bounds-in-macro.stderr
Original file line number Diff line number Diff line change
@@ -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`.
4 changes: 3 additions & 1 deletion tests/ui/parser/bad-recover-kw-after-impl.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -11,5 +11,7 @@ macro_rules! impl_primitive {
}

impl_primitive!(impl async);
//~^ ERROR expected identifier, found `<eof>`
//~| ERROR async closures are unstable

fn main() {}
23 changes: 23 additions & 0 deletions tests/ui/parser/bad-recover-kw-after-impl.stderr
Original file line number Diff line number Diff line change
@@ -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`.
2 changes: 1 addition & 1 deletion tests/ui/parser/trait-object-delimiters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<`
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/parser/trait-object-delimiters.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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 `,`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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! { impl const Trait }
//~^ ERROR const trait impls are experimental

demo! { dyn const }
demo! { dyn const Trait }
//~^ ERROR const trait impls are experimental
//~| ERROR expected identifier, found `<eof>`

fn main() {}
Original file line number Diff line number Diff line change
@@ -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:15:14
|
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:16:13
--> $DIR/mbe-const-trait-bound-theoretical-regression.rs:18:13
|
LL | demo! { dyn const }
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`.

0 comments on commit 082b97a

Please sign in to comment.