Skip to content

Commit

Permalink
Support async trait bounds in macros
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Feb 20, 2024
1 parent 29f87ad commit 9c8b107
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 9c8b107

Please sign in to comment.