Skip to content

Commit 9c8b107

Browse files
Support async trait bounds in macros
1 parent 29f87ad commit 9c8b107

16 files changed

+228
-30
lines changed

compiler/rustc_parse/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ parse_async_bound_modifier_in_2015 = `async` trait bounds are only allowed in Ru
2727
parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
2828
.label = to use `async fn`, switch to Rust 2018 or later
2929
30+
parse_async_impl = `async` trait implementations are unsupported
31+
3032
parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 2018 or later
3133
3234
parse_async_move_order_incorrect = the order of `move` and `async` is incorrect

compiler/rustc_parse/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2975,3 +2975,10 @@ pub(crate) struct ArrayIndexInOffsetOf(#[primary_span] pub Span);
29752975
#[derive(Diagnostic)]
29762976
#[diag(parse_invalid_offset_of)]
29772977
pub(crate) struct InvalidOffsetOf(#[primary_span] pub Span);
2978+
2979+
#[derive(Diagnostic)]
2980+
#[diag(parse_async_impl)]
2981+
pub(crate) struct AsyncImpl {
2982+
#[primary_span]
2983+
pub span: Span,
2984+
}

compiler/rustc_parse/src/parser/item.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,15 @@ impl<'a> Parser<'a> {
562562
self.sess.gated_spans.gate(sym::const_trait_impl, span);
563563
}
564564

565+
// Parse stray `impl async Trait`
566+
if (self.token.uninterpolated_span().at_least_rust_2018()
567+
&& self.token.is_keyword(kw::Async))
568+
|| self.is_kw_followed_by_ident(kw::Async)
569+
{
570+
self.bump();
571+
self.dcx().emit_err(errors::AsyncImpl { span: self.prev_token.span });
572+
}
573+
565574
let polarity = self.parse_polarity();
566575

567576
// Parse both types and traits as a type, then reinterpret if necessary.

compiler/rustc_parse/src/parser/ty.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -778,9 +778,10 @@ impl<'a> Parser<'a> {
778778
|| self.check(&token::Not)
779779
|| self.check(&token::Question)
780780
|| self.check(&token::Tilde)
781-
|| self.check_keyword(kw::Const)
782781
|| self.check_keyword(kw::For)
783782
|| self.check(&token::OpenDelim(Delimiter::Parenthesis))
783+
|| self.check_keyword(kw::Const)
784+
|| self.check_keyword(kw::Async)
784785
}
785786

786787
/// Parses a bound according to the grammar:
@@ -882,11 +883,13 @@ impl<'a> Parser<'a> {
882883
BoundConstness::Never
883884
};
884885

885-
let asyncness = if self.token.span.at_least_rust_2018() && self.eat_keyword(kw::Async) {
886+
let asyncness = if self.token.uninterpolated_span().at_least_rust_2018()
887+
&& self.eat_keyword(kw::Async)
888+
{
886889
self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span);
887890
BoundAsyncness::Async(self.prev_token.span)
888891
} else if self.may_recover()
889-
&& self.token.span.is_rust_2015()
892+
&& self.token.uninterpolated_span().is_rust_2015()
890893
&& self.is_kw_followed_by_ident(kw::Async)
891894
{
892895
self.bump(); // eat `async`

tests/ui/async-await/async-fn/impl-header.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
struct F;
44

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

812
fn main() {}
Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,47 @@
1-
error: expected type, found keyword `async`
1+
error: `async` trait implementations are unsupported
22
--> $DIR/impl-header.rs:5:6
33
|
44
LL | impl async Fn<()> for F {}
5-
| ^^^^^ expected type
5+
| ^^^^^
66

7-
error: aborting due to 1 previous error
7+
error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
8+
--> $DIR/impl-header.rs:5:12
9+
|
10+
LL | impl async Fn<()> for F {}
11+
| ^^^^^^
12+
|
13+
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
14+
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
15+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
16+
17+
error[E0183]: manual implementations of `Fn` are experimental
18+
--> $DIR/impl-header.rs:5:12
19+
|
20+
LL | impl async Fn<()> for F {}
21+
| ^^^^^^ manual implementations of `Fn` are experimental
22+
|
23+
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
24+
25+
error[E0277]: expected a `FnMut()` closure, found `F`
26+
--> $DIR/impl-header.rs:5:23
27+
|
28+
LL | impl async Fn<()> for F {}
29+
| ^ expected an `FnMut()` closure, found `F`
30+
|
31+
= help: the trait `FnMut<()>` is not implemented for `F`
32+
= note: wrap the `F` in a closure with no arguments: `|| { /* code */ }`
33+
note: required by a bound in `Fn`
34+
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
35+
36+
error[E0046]: not all trait items implemented, missing: `call`
37+
--> $DIR/impl-header.rs:5:1
38+
|
39+
LL | impl async Fn<()> for F {}
40+
| ^^^^^^^^^^^^^^^^^^^^^^^ missing `call` in implementation
41+
|
42+
= help: implement the missing item: `fn call(&self, _: ()) -> <Self as FnOnce<()>>::Output { todo!() }`
43+
44+
error: aborting due to 5 previous errors
845

46+
Some errors have detailed explanations: E0046, E0183, E0277, E0658.
47+
For more information about an error, try `rustc --explain E0046`.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Demonstrates and records a theoretical regressions / breaking changes caused by the
2+
// introduction of async trait bounds.
3+
4+
// Setting the edition to 2018 since we don't regress `demo! { dyn async }` in Rust <2018.
5+
//@ edition:2018
6+
7+
macro_rules! demo {
8+
($ty:ty) => { compile_error!("ty"); };
9+
//~^ ERROR ty
10+
//~| ERROR ty
11+
(impl $c:ident Trait) => {};
12+
(dyn $c:ident Trait) => {};
13+
}
14+
15+
demo! { impl async Trait }
16+
//~^ ERROR async closures are unstable
17+
18+
demo! { dyn async Trait }
19+
//~^ ERROR async closures are unstable
20+
21+
fn main() {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error: ty
2+
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:8:19
3+
|
4+
LL | ($ty:ty) => { compile_error!("ty"); };
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
...
7+
LL | demo! { impl async Trait }
8+
| -------------------------- in this macro invocation
9+
|
10+
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
11+
12+
error: ty
13+
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:8:19
14+
|
15+
LL | ($ty:ty) => { compile_error!("ty"); };
16+
| ^^^^^^^^^^^^^^^^^^^^
17+
...
18+
LL | demo! { dyn async Trait }
19+
| ------------------------- in this macro invocation
20+
|
21+
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
22+
23+
error[E0658]: async closures are unstable
24+
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:15:14
25+
|
26+
LL | demo! { impl async Trait }
27+
| ^^^^^
28+
|
29+
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
30+
= help: add `#![feature(async_closure)]` to the crate attributes to enable
31+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
32+
= help: to use an async block, remove the `||`: `async {`
33+
34+
error[E0658]: async closures are unstable
35+
--> $DIR/mbe-async-trait-bound-theoretical-regression.rs:18:13
36+
|
37+
LL | demo! { dyn async Trait }
38+
| ^^^^^
39+
|
40+
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
41+
= help: add `#![feature(async_closure)]` to the crate attributes to enable
42+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
43+
= help: to use an async block, remove the `||`: `async {`
44+
45+
error: aborting due to 4 previous errors
46+
47+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@ edition: 2021
2+
3+
macro_rules! x {
4+
($x:item) => {}
5+
}
6+
7+
x! {
8+
async fn foo() -> impl async Fn() { }
9+
//~^ ERROR async closures are unstable
10+
}
11+
12+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0658]: async closures are unstable
2+
--> $DIR/trait-bounds-in-macro.rs:8:28
3+
|
4+
LL | async fn foo() -> impl async Fn() { }
5+
| ^^^^^
6+
|
7+
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
8+
= help: add `#![feature(async_closure)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
= help: to use an async block, remove the `||`: `async {`
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)