Skip to content

Commit 5309dbd

Browse files
committed
Remove AsyncFn* impls from gnerator closures
1 parent 69a65cd commit 5309dbd

File tree

6 files changed

+90
-8
lines changed

6 files changed

+90
-8
lines changed

compiler/rustc_const_eval/src/check_consts/check.rs

+1-1
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

+6-1
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
462462

463463
if let Some(trait_def_id) = trait_def_id {
464464
let found_kind = match closure_kind {
465-
hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
465+
hir::ClosureKind::Closure
466+
// FIXME(iter_macro): Someday we'll probably want iterator closures instead of
467+
// just using Fn* for iterators.
468+
| hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => {
469+
self.tcx.fn_trait_kind_from_def_id(trait_def_id)
470+
}
466471
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self
467472
.tcx
468473
.async_fn_trait_kind_from_def_id(trait_def_id)

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

+24-4
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};
@@ -125,11 +125,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
125125
self.assemble_async_iterator_candidates(obligation, &mut candidates);
126126
} else if tcx.is_lang_item(def_id, LangItem::AsyncFnKindHelper) {
127127
self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates);
128+
} else if tcx.is_lang_item(def_id, LangItem::AsyncFn)
129+
|| tcx.is_lang_item(def_id, LangItem::AsyncFnOnce)
130+
|| tcx.is_lang_item(def_id, LangItem::AsyncFnMut)
131+
{
132+
self.assemble_async_closure_candidates(obligation, &mut candidates);
128133
}
129134

130135
// FIXME: Put these into `else if` blocks above, since they're built-in.
131136
self.assemble_closure_candidates(obligation, &mut candidates);
132-
self.assemble_async_closure_candidates(obligation, &mut candidates);
133137
self.assemble_fn_pointer_candidates(obligation, &mut candidates);
134138

135139
self.assemble_candidates_from_impls(obligation, &mut candidates);
@@ -425,6 +429,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
425429
}
426430
}
427431

432+
#[instrument(level = "debug", skip(self, candidates))]
428433
fn assemble_async_closure_candidates(
429434
&mut self,
430435
obligation: &PolyTraitObligation<'tcx>,
@@ -436,15 +441,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
436441
return;
437442
};
438443

444+
debug!("self_ty = {:?}", obligation.self_ty().skip_binder().kind());
439445
match *obligation.self_ty().skip_binder().kind() {
440-
ty::CoroutineClosure(_, args) => {
446+
ty::CoroutineClosure(def_id, args) => {
441447
if let Some(closure_kind) =
442448
args.as_coroutine_closure().kind_ty().to_opt_closure_kind()
443449
&& !closure_kind.extends(goal_kind)
444450
{
445451
return;
446452
}
447-
candidates.vec.push(AsyncClosureCandidate);
453+
454+
// Make sure this is actually an async closure.
455+
let Some(coroutine_kind) =
456+
self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(def_id))
457+
else {
458+
bug!("coroutine with no kind");
459+
};
460+
461+
debug!(?coroutine_kind);
462+
match coroutine_kind {
463+
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
464+
candidates.vec.push(AsyncClosureCandidate);
465+
}
466+
_ => (),
467+
}
448468
}
449469
// Closures and fn pointers implement `AsyncFn*` if their return types
450470
// implement `Future`, which is checked later.

tests/ui/iterators/generator_capture_.rs

+2-2
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'));
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`.
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+
}

0 commit comments

Comments
 (0)