Skip to content

Commit

Permalink
Auto merge of rust-lang#105094 - Swatinem:generator-not-future, r=com…
Browse files Browse the repository at this point in the history
…piler-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 rust-lang#105082 (comment) and is a regression from rust-lang#104321.

r? `@compiler-errors`
  • Loading branch information
bors committed Dec 4, 2022
2 parents 53e4b9d + b5ae4c9 commit d144956
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// type/region parameters.
let self_ty = obligation.self_ty().skip_binder();
match self_ty.kind() {
ty::Generator(..) => {
// async constructs get lowered to a special kind of generator that
// should *not* `impl Generator`.
ty::Generator(did, ..) if !self.tcx().generator_is_async(*did) => {
debug!(?self_ty, ?obligation, "assemble_generator_candidates",);

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

Expand Down
45 changes: 45 additions & 0 deletions src/test/ui/async-await/generator-not-future.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// edition:2018
#![feature(generators, generator_trait)]

use std::future::Future;
use std::ops::Generator;

async fn async_fn() {}
fn returns_async_block() -> impl Future<Output = ()> {
async {}
}
fn returns_generator() -> impl Generator<(), Yield = (), Return = ()> {
|| {
let _: () = yield ();
}
}

fn takes_future(_f: impl Future<Output = ()>) {}
fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}

fn main() {
// okay:
takes_future(async_fn());
takes_future(returns_async_block());
takes_future(async {});
takes_generator(returns_generator());
takes_generator(|| {
let _: () = yield ();
});

// async futures are not generators:
takes_generator(async_fn());
//~^ ERROR the trait bound
takes_generator(returns_async_block());
//~^ ERROR the trait bound
takes_generator(async {});
//~^ ERROR the trait bound

// generators are not futures:
takes_future(returns_generator());
//~^ ERROR is not a future
takes_future(|ctx| {
//~^ ERROR is not a future
ctx = yield ();
});
}
81 changes: 81 additions & 0 deletions src/test/ui/async-await/generator-not-future.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
error[E0277]: the trait bound `impl Future<Output = ()>: Generator<_>` is not satisfied
--> $DIR/generator-not-future.rs:31:21
|
LL | takes_generator(async_fn());
| --------------- ^^^^^^^^^^ the trait `Generator<_>` is not implemented for `impl Future<Output = ()>`
| |
| required by a bound introduced by this call
|
note: required by a bound in `takes_generator`
--> $DIR/generator-not-future.rs:18:39
|
LL | fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator`

error[E0277]: the trait bound `impl Future<Output = ()>: Generator<_>` is not satisfied
--> $DIR/generator-not-future.rs:33:21
|
LL | takes_generator(returns_async_block());
| --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `Generator<_>` is not implemented for `impl Future<Output = ()>`
| |
| required by a bound introduced by this call
|
note: required by a bound in `takes_generator`
--> $DIR/generator-not-future.rs:18:39
|
LL | fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator`

error[E0277]: the trait bound `[async block@$DIR/generator-not-future.rs:35:21: 35:29]: Generator<_>` is not satisfied
--> $DIR/generator-not-future.rs:35:21
|
LL | takes_generator(async {});
| --------------- ^^^^^^^^ the trait `Generator<_>` is not implemented for `[async block@$DIR/generator-not-future.rs:35:21: 35:29]`
| |
| required by a bound introduced by this call
|
note: required by a bound in `takes_generator`
--> $DIR/generator-not-future.rs:18:39
|
LL | fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator`

error[E0277]: `impl Generator<Yield = (), Return = ()>` is not a future
--> $DIR/generator-not-future.rs:39:18
|
LL | takes_future(returns_generator());
| ------------ ^^^^^^^^^^^^^^^^^^^ `impl Generator<Yield = (), Return = ()>` is not a future
| |
| required by a bound introduced by this call
|
= help: the trait `Future` is not implemented for `impl Generator<Yield = (), Return = ()>`
= note: impl Generator<Yield = (), Return = ()> must be a future or must implement `IntoFuture` to be awaited
note: required by a bound in `takes_future`
--> $DIR/generator-not-future.rs:17:26
|
LL | fn takes_future(_f: impl Future<Output = ()>) {}
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`

error[E0277]: `[generator@$DIR/generator-not-future.rs:41:18: 41:23]` is not a future
--> $DIR/generator-not-future.rs:41:18
|
LL | takes_future(|ctx| {
| _____------------_^
| | |
| | required by a bound introduced by this call
LL | |
LL | | ctx = yield ();
LL | | });
| |_____^ `[generator@$DIR/generator-not-future.rs:41:18: 41:23]` is not a future
|
= help: the trait `Future` is not implemented for `[generator@$DIR/generator-not-future.rs:41:18: 41:23]`
= note: [generator@$DIR/generator-not-future.rs:41:18: 41:23] must be a future or must implement `IntoFuture` to be awaited
note: required by a bound in `takes_future`
--> $DIR/generator-not-future.rs:17:26
|
LL | fn takes_future(_f: impl Future<Output = ()>) {}
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0277`.

0 comments on commit d144956

Please sign in to comment.