Skip to content

Commit d144956

Browse files
committed
Auto merge of #105094 - Swatinem:generator-not-future, r=compiler-errors
Make sure async constructs do not `impl Generator` Async lowering turns async functions and blocks into generators internally. Though these special kinds of generators should not `impl Generator` themselves. The other way around, normal generators should not `impl Future`. This was discovered in #105082 (comment) and is a regression from #104321. r? `@compiler-errors`
2 parents 53e4b9d + b5ae4c9 commit d144956

File tree

3 files changed

+131
-1
lines changed

3 files changed

+131
-1
lines changed

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
203203
// type/region parameters.
204204
let self_ty = obligation.self_ty().skip_binder();
205205
match self_ty.kind() {
206-
ty::Generator(..) => {
206+
// async constructs get lowered to a special kind of generator that
207+
// should *not* `impl Generator`.
208+
ty::Generator(did, ..) if !self.tcx().generator_is_async(*did) => {
207209
debug!(?self_ty, ?obligation, "assemble_generator_candidates",);
208210

209211
candidates.vec.push(GeneratorCandidate);
@@ -223,6 +225,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
223225
) {
224226
let self_ty = obligation.self_ty().skip_binder();
225227
if let ty::Generator(did, ..) = self_ty.kind() {
228+
// async constructs get lowered to a special kind of generator that
229+
// should directly `impl Future`.
226230
if self.tcx().generator_is_async(*did) {
227231
debug!(?self_ty, ?obligation, "assemble_future_candidates",);
228232

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// edition:2018
2+
#![feature(generators, generator_trait)]
3+
4+
use std::future::Future;
5+
use std::ops::Generator;
6+
7+
async fn async_fn() {}
8+
fn returns_async_block() -> impl Future<Output = ()> {
9+
async {}
10+
}
11+
fn returns_generator() -> impl Generator<(), Yield = (), Return = ()> {
12+
|| {
13+
let _: () = yield ();
14+
}
15+
}
16+
17+
fn takes_future(_f: impl Future<Output = ()>) {}
18+
fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
19+
20+
fn main() {
21+
// okay:
22+
takes_future(async_fn());
23+
takes_future(returns_async_block());
24+
takes_future(async {});
25+
takes_generator(returns_generator());
26+
takes_generator(|| {
27+
let _: () = yield ();
28+
});
29+
30+
// async futures are not generators:
31+
takes_generator(async_fn());
32+
//~^ ERROR the trait bound
33+
takes_generator(returns_async_block());
34+
//~^ ERROR the trait bound
35+
takes_generator(async {});
36+
//~^ ERROR the trait bound
37+
38+
// generators are not futures:
39+
takes_future(returns_generator());
40+
//~^ ERROR is not a future
41+
takes_future(|ctx| {
42+
//~^ ERROR is not a future
43+
ctx = yield ();
44+
});
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
error[E0277]: the trait bound `impl Future<Output = ()>: Generator<_>` is not satisfied
2+
--> $DIR/generator-not-future.rs:31:21
3+
|
4+
LL | takes_generator(async_fn());
5+
| --------------- ^^^^^^^^^^ the trait `Generator<_>` is not implemented for `impl Future<Output = ()>`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
note: required by a bound in `takes_generator`
10+
--> $DIR/generator-not-future.rs:18:39
11+
|
12+
LL | fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator`
14+
15+
error[E0277]: the trait bound `impl Future<Output = ()>: Generator<_>` is not satisfied
16+
--> $DIR/generator-not-future.rs:33:21
17+
|
18+
LL | takes_generator(returns_async_block());
19+
| --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `Generator<_>` is not implemented for `impl Future<Output = ()>`
20+
| |
21+
| required by a bound introduced by this call
22+
|
23+
note: required by a bound in `takes_generator`
24+
--> $DIR/generator-not-future.rs:18:39
25+
|
26+
LL | fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator`
28+
29+
error[E0277]: the trait bound `[async block@$DIR/generator-not-future.rs:35:21: 35:29]: Generator<_>` is not satisfied
30+
--> $DIR/generator-not-future.rs:35:21
31+
|
32+
LL | takes_generator(async {});
33+
| --------------- ^^^^^^^^ the trait `Generator<_>` is not implemented for `[async block@$DIR/generator-not-future.rs:35:21: 35:29]`
34+
| |
35+
| required by a bound introduced by this call
36+
|
37+
note: required by a bound in `takes_generator`
38+
--> $DIR/generator-not-future.rs:18:39
39+
|
40+
LL | fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator`
42+
43+
error[E0277]: `impl Generator<Yield = (), Return = ()>` is not a future
44+
--> $DIR/generator-not-future.rs:39:18
45+
|
46+
LL | takes_future(returns_generator());
47+
| ------------ ^^^^^^^^^^^^^^^^^^^ `impl Generator<Yield = (), Return = ()>` is not a future
48+
| |
49+
| required by a bound introduced by this call
50+
|
51+
= help: the trait `Future` is not implemented for `impl Generator<Yield = (), Return = ()>`
52+
= note: impl Generator<Yield = (), Return = ()> must be a future or must implement `IntoFuture` to be awaited
53+
note: required by a bound in `takes_future`
54+
--> $DIR/generator-not-future.rs:17:26
55+
|
56+
LL | fn takes_future(_f: impl Future<Output = ()>) {}
57+
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`
58+
59+
error[E0277]: `[generator@$DIR/generator-not-future.rs:41:18: 41:23]` is not a future
60+
--> $DIR/generator-not-future.rs:41:18
61+
|
62+
LL | takes_future(|ctx| {
63+
| _____------------_^
64+
| | |
65+
| | required by a bound introduced by this call
66+
LL | |
67+
LL | | ctx = yield ();
68+
LL | | });
69+
| |_____^ `[generator@$DIR/generator-not-future.rs:41:18: 41:23]` is not a future
70+
|
71+
= help: the trait `Future` is not implemented for `[generator@$DIR/generator-not-future.rs:41:18: 41:23]`
72+
= note: [generator@$DIR/generator-not-future.rs:41:18: 41:23] must be a future or must implement `IntoFuture` to be awaited
73+
note: required by a bound in `takes_future`
74+
--> $DIR/generator-not-future.rs:17:26
75+
|
76+
LL | fn takes_future(_f: impl Future<Output = ()>) {}
77+
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`
78+
79+
error: aborting due to 5 previous errors
80+
81+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)