Skip to content

Commit f3fceff

Browse files
committed
Remove AsyncFn* impls from gnerator closures
1 parent 3eb4deb commit f3fceff

File tree

8 files changed

+102
-9
lines changed

8 files changed

+102
-9
lines changed

compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
591591
if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref()
592592
&& let Some(
593593
coroutine_kind @ hir::CoroutineKind::Desugared(
594-
hir::CoroutineDesugaring::Async,
594+
hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::Gen,
595595
_,
596596
),
597597
) = self.tcx.coroutine_kind(def_id)

compiler/rustc_hir_typeck/src/closure.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
470470

471471
if let Some(trait_def_id) = trait_def_id {
472472
let found_kind = match closure_kind {
473-
hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
473+
hir::ClosureKind::Closure
474+
// FIXME(iter_macro): Someday we'll probably want iterator closures instead of
475+
// just using Fn* for iterators.
476+
| hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => {
477+
self.tcx.fn_trait_kind_from_def_id(trait_def_id)
478+
}
474479
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self
475480
.tcx
476481
.async_fn_trait_kind_from_def_id(trait_def_id)

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::ops::ControlFlow;
1111
use hir::LangItem;
1212
use hir::def_id::DefId;
1313
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
14-
use rustc_hir as hir;
14+
use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind};
1515
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
1616
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
1717
use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode, elaborate};
@@ -438,6 +438,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
438438
}
439439
}
440440

441+
#[instrument(level = "debug", skip(self, candidates))]
441442
fn assemble_async_closure_candidates(
442443
&mut self,
443444
obligation: &PolyTraitObligation<'tcx>,
@@ -446,15 +447,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
446447
let goal_kind =
447448
self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
448449

450+
debug!("self_ty = {:?}", obligation.self_ty().skip_binder().kind());
449451
match *obligation.self_ty().skip_binder().kind() {
450-
ty::CoroutineClosure(_, args) => {
452+
ty::CoroutineClosure(def_id, args) => {
451453
if let Some(closure_kind) =
452454
args.as_coroutine_closure().kind_ty().to_opt_closure_kind()
453455
&& !closure_kind.extends(goal_kind)
454456
{
455457
return;
456458
}
457-
candidates.vec.push(AsyncClosureCandidate);
459+
460+
// Make sure this is actually an async closure.
461+
let Some(coroutine_kind) =
462+
self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(def_id))
463+
else {
464+
bug!("coroutine with no kind");
465+
};
466+
467+
debug!(?coroutine_kind);
468+
match coroutine_kind {
469+
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
470+
candidates.vec.push(AsyncClosureCandidate);
471+
}
472+
_ => (),
473+
}
458474
}
459475
// Closures and fn pointers implement `AsyncFn*` if their return types
460476
// implement `Future`, which is checked later.

tests/ui/iterators/generator_capture_.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-pass
1+
// This test exercises lending behavior for iterator closures which is not yet supported.
22

33
#![feature(iter_macro, yield_expr)]
44

@@ -18,7 +18,7 @@ fn main() {
1818
assert_eq!(i.next(), Some('o'));
1919
assert_eq!(i.next(), Some('o'));
2020
assert_eq!(i.next(), None);
21-
let mut i = f();
21+
let mut i = f(); //~ ERROR use of moved value: `f`
2222
assert_eq!(i.next(), Some('f'));
2323
assert_eq!(i.next(), Some('o'));
2424
assert_eq!(i.next(), Some('o'));
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0382]: use of moved value: `f`
2+
--> $DIR/generator_capture_.rs:21:17
3+
|
4+
LL | let f = {
5+
| - move occurs because `f` has type `{gen closure@$DIR/generator_capture_.rs:10:17: 10:24}`, which does not implement the `Copy` trait
6+
...
7+
LL | let mut i = f();
8+
| --- `f` moved due to this call
9+
...
10+
LL | let mut i = f();
11+
| ^ value used here after move
12+
|
13+
note: this value implements `FnOnce`, which causes it to be moved when called
14+
--> $DIR/generator_capture_.rs:16:17
15+
|
16+
LL | let mut i = f();
17+
| ^
18+
help: consider cloning the value if the performance cost is acceptable
19+
|
20+
LL | let mut i = f.clone()();
21+
| ++++++++
22+
23+
error: aborting due to 1 previous error
24+
25+
For more information about this error, try `rustc --explain E0382`.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ run-pass
2+
3+
#![feature(iter_macro, yield_expr)]
4+
5+
use std::iter::iter;
6+
7+
fn main() {
8+
let i = {
9+
let s = String::new();
10+
iter! { move || {
11+
yield s.len();
12+
for x in 5..10 {
13+
yield x * 2;
14+
}
15+
}}
16+
};
17+
test_iterator(i);
18+
}
19+
20+
/// Exercise the iterator in a separate function to ensure it's not capturing anything it shoudln't.
21+
fn test_iterator<I: Iterator<Item = usize>>(i: impl FnOnce() -> I) {
22+
let mut i = i();
23+
assert_eq!(i.next(), Some(0));
24+
assert_eq!(i.next(), Some(10));
25+
assert_eq!(i.next(), Some(12));
26+
assert_eq!(i.next(), Some(14));
27+
assert_eq!(i.next(), Some(16));
28+
assert_eq!(i.next(), Some(18));
29+
assert_eq!(i.next(), None);
30+
assert_eq!(i.next(), None);
31+
assert_eq!(i.next(), None);
32+
}

tests/ui/iterators/iter-macro-not-async-closure.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ fn main() {
2323
//~^ ERROR AsyncFnOnce()` is not satisfied
2424
//~^^ ERROR AsyncFnOnce()` is not satisfied
2525
//~^^^ ERROR AsyncFnOnce()` is not satisfied
26+
//~^^^^ ERROR AsyncFnOnce()` is not satisfied
2627
x.poll(&mut Context::from_waker(Waker::noop()));
2728
//~^ ERROR AsyncFnOnce()` is not satisfied
2829
}

tests/ui/iterators/iter-macro-not-async-closure.stderr

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,21 @@ LL | async fn call_async_once(f: impl AsyncFnOnce()) {
4141
= note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
4242

4343
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:16:21: 16:28}: AsyncFnOnce()` is not satisfied
44-
--> $DIR/iter-macro-not-async-closure.rs:26:5
44+
--> $DIR/iter-macro-not-async-closure.rs:22:13
45+
|
46+
LL | let x = pin!(call_async_once(f));
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
48+
|
49+
= help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:16:21: 16:28}`
50+
note: required by a bound in `call_async_once`
51+
--> $DIR/iter-macro-not-async-closure.rs:11:34
52+
|
53+
LL | async fn call_async_once(f: impl AsyncFnOnce()) {
54+
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
55+
= note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
56+
57+
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:16:21: 16:28}: AsyncFnOnce()` is not satisfied
58+
--> $DIR/iter-macro-not-async-closure.rs:27:5
4559
|
4660
LL | x.poll(&mut Context::from_waker(Waker::noop()));
4761
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
@@ -53,6 +67,6 @@ note: required by a bound in `call_async_once`
5367
LL | async fn call_async_once(f: impl AsyncFnOnce()) {
5468
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
5569

56-
error: aborting due to 4 previous errors
70+
error: aborting due to 5 previous errors
5771

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

0 commit comments

Comments
 (0)