Skip to content

Commit 8230fd5

Browse files
Rollup merge of rust-lang#118764 - compiler-errors:fused-async-iterator, r=eholk
Make async generators fused by default I actually changed my mind about this since the implementation PR landed. I think it's beneficial for `async gen` blocks to be "fused" by default -- i.e., for them to repeatedly return `Poll::Ready(None)` -- rather than panic. We have [`FusedStream`](https://docs.rs/futures/latest/futures/stream/trait.FusedStream.html) in futures-rs to represent streams with this capability already anyways. r? eholk cc ``@rust-lang/wg-async,`` would like to know if anyone else has opinions about this.
2 parents 5b720b4 + e987812 commit 8230fd5

File tree

2 files changed

+37
-11
lines changed

2 files changed

+37
-11
lines changed

compiler/rustc_mir_transform/src/coroutine.rs

+33-11
Original file line numberDiff line numberDiff line change
@@ -252,15 +252,15 @@ struct TransformVisitor<'tcx> {
252252

253253
impl<'tcx> TransformVisitor<'tcx> {
254254
fn insert_none_ret_block(&self, body: &mut Body<'tcx>) -> BasicBlock {
255-
assert!(matches!(self.coroutine_kind, CoroutineKind::Gen(_)));
256-
257255
let block = BasicBlock::new(body.basic_blocks.len());
258256
let source_info = SourceInfo::outermost(body.span);
259-
let option_def_id = self.tcx.require_lang_item(LangItem::Option, None);
260257

261-
let statements = vec![Statement {
262-
kind: StatementKind::Assign(Box::new((
263-
Place::return_place(),
258+
let none_value = match self.coroutine_kind {
259+
CoroutineKind::Async(_) => span_bug!(body.span, "`Future`s are not fused inherently"),
260+
CoroutineKind::Coroutine => span_bug!(body.span, "`Coroutine`s cannot be fused"),
261+
// `gen` continues return `None`
262+
CoroutineKind::Gen(_) => {
263+
let option_def_id = self.tcx.require_lang_item(LangItem::Option, None);
264264
Rvalue::Aggregate(
265265
Box::new(AggregateKind::Adt(
266266
option_def_id,
@@ -270,8 +270,29 @@ impl<'tcx> TransformVisitor<'tcx> {
270270
None,
271271
)),
272272
IndexVec::new(),
273-
),
274-
))),
273+
)
274+
}
275+
// `async gen` continues to return `Poll::Ready(None)`
276+
CoroutineKind::AsyncGen(_) => {
277+
let ty::Adt(_poll_adt, args) = *self.old_yield_ty.kind() else { bug!() };
278+
let ty::Adt(_option_adt, args) = *args.type_at(0).kind() else { bug!() };
279+
let yield_ty = args.type_at(0);
280+
Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
281+
span: source_info.span,
282+
const_: Const::Unevaluated(
283+
UnevaluatedConst::new(
284+
self.tcx.require_lang_item(LangItem::AsyncGenFinished, None),
285+
self.tcx.mk_args(&[yield_ty.into()]),
286+
),
287+
self.old_yield_ty,
288+
),
289+
user_ty: None,
290+
})))
291+
}
292+
};
293+
294+
let statements = vec![Statement {
295+
kind: StatementKind::Assign(Box::new((Place::return_place(), none_value))),
275296
source_info,
276297
}];
277298

@@ -1393,11 +1414,12 @@ fn create_coroutine_resume_function<'tcx>(
13931414

13941415
if can_return {
13951416
let block = match coroutine_kind {
1396-
// FIXME(gen_blocks): Should `async gen` yield `None` when resumed once again?
1397-
CoroutineKind::Async(_) | CoroutineKind::AsyncGen(_) | CoroutineKind::Coroutine => {
1417+
CoroutineKind::Async(_) | CoroutineKind::Coroutine => {
13981418
insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))
13991419
}
1400-
CoroutineKind::Gen(_) => transform.insert_none_ret_block(body),
1420+
CoroutineKind::AsyncGen(_) | CoroutineKind::Gen(_) => {
1421+
transform.insert_none_ret_block(body)
1422+
}
14011423
};
14021424
cases.insert(1, (RETURNED, block));
14031425
}

tests/ui/coroutine/async_gen_fn_iter.rs

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ async fn async_main() {
3333
assert_eq!(iter.as_mut().next().await, Some(2));
3434
assert_eq!(iter.as_mut().next().await, Some(3));
3535
assert_eq!(iter.as_mut().next().await, None);
36+
37+
// Test that the iterator is fused and does not panic
38+
assert_eq!(iter.as_mut().next().await, None);
39+
assert_eq!(iter.as_mut().next().await, None);
3640
}
3741

3842
// ------------------------------------------------------------------------- //

0 commit comments

Comments
 (0)