Skip to content

Commit eb66d10

Browse files
committed
Fuse gen blocks
1 parent b8bfd08 commit eb66d10

File tree

4 files changed

+54
-35
lines changed

4 files changed

+54
-35
lines changed

compiler/rustc_middle/src/mir/terminator.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,9 @@ impl<O> AssertKind<O> {
243243
DivisionByZero(_) => middle_assert_divide_by_zero,
244244
RemainderByZero(_) => middle_assert_remainder_by_zero,
245245
ResumedAfterReturn(CoroutineKind::Async(_)) => middle_assert_async_resume_after_return,
246-
// FIXME(gen_blocks): custom error message for `gen` blocks
247-
ResumedAfterReturn(CoroutineKind::Gen(_)) => middle_assert_async_resume_after_return,
246+
ResumedAfterReturn(CoroutineKind::Gen(_)) => {
247+
bug!("gen blocks can be resumed after they return and will keep returning `None`")
248+
}
248249
ResumedAfterReturn(CoroutineKind::Coroutine) => {
249250
middle_assert_coroutine_resume_after_return
250251
}

compiler/rustc_mir_transform/src/coroutine.rs

+49-14
Original file line numberDiff line numberDiff line change
@@ -249,18 +249,34 @@ struct TransformVisitor<'tcx> {
249249
}
250250

251251
impl<'tcx> TransformVisitor<'tcx> {
252-
// Make a `CoroutineState` or `Poll` variant assignment.
253-
//
254-
// `core::ops::CoroutineState` only has single element tuple variants,
255-
// so we can just write to the downcasted first field and then set the
256-
// discriminant to the appropriate variant.
257-
fn make_state(
252+
fn insert_none_ret_block(&self, body: &mut Body<'tcx>) -> BasicBlock {
253+
let block = BasicBlock::new(body.basic_blocks.len());
254+
255+
let source_info = SourceInfo::outermost(body.span);
256+
257+
let (kind, idx) = self.coroutine_state_adt_and_variant_idx(true);
258+
assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 0);
259+
let statements = vec![Statement {
260+
kind: StatementKind::Assign(Box::new((
261+
Place::return_place(),
262+
Rvalue::Aggregate(Box::new(kind), IndexVec::new()),
263+
))),
264+
source_info,
265+
}];
266+
267+
body.basic_blocks_mut().push(BasicBlockData {
268+
statements,
269+
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
270+
is_cleanup: false,
271+
});
272+
273+
block
274+
}
275+
276+
fn coroutine_state_adt_and_variant_idx(
258277
&self,
259-
val: Operand<'tcx>,
260-
source_info: SourceInfo,
261278
is_return: bool,
262-
statements: &mut Vec<Statement<'tcx>>,
263-
) {
279+
) -> (AggregateKind<'tcx>, VariantIdx) {
264280
let idx = VariantIdx::new(match (is_return, self.coroutine_kind) {
265281
(true, hir::CoroutineKind::Coroutine) => 1, // CoroutineState::Complete
266282
(false, hir::CoroutineKind::Coroutine) => 0, // CoroutineState::Yielded
@@ -271,6 +287,22 @@ impl<'tcx> TransformVisitor<'tcx> {
271287
});
272288

273289
let kind = AggregateKind::Adt(self.state_adt_ref.did(), idx, self.state_args, None, None);
290+
(kind, idx)
291+
}
292+
293+
// Make a `CoroutineState` or `Poll` variant assignment.
294+
//
295+
// `core::ops::CoroutineState` only has single element tuple variants,
296+
// so we can just write to the downcasted first field and then set the
297+
// discriminant to the appropriate variant.
298+
fn make_state(
299+
&self,
300+
val: Operand<'tcx>,
301+
source_info: SourceInfo,
302+
is_return: bool,
303+
statements: &mut Vec<Statement<'tcx>>,
304+
) {
305+
let (kind, idx) = self.coroutine_state_adt_and_variant_idx(is_return);
274306

275307
match self.coroutine_kind {
276308
// `Poll::Pending`
@@ -1285,10 +1317,13 @@ fn create_coroutine_resume_function<'tcx>(
12851317
}
12861318

12871319
if can_return {
1288-
cases.insert(
1289-
1,
1290-
(RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))),
1291-
);
1320+
let block = match coroutine_kind {
1321+
CoroutineKind::Async(_) | CoroutineKind::Coroutine => {
1322+
insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))
1323+
}
1324+
CoroutineKind::Gen(_) => transform.insert_none_ret_block(body),
1325+
};
1326+
cases.insert(1, (RETURNED, block));
12921327
}
12931328

12941329
insert_switch(body, cases, &transform, TerminatorKind::Unreachable);

tests/ui/coroutine/gen_block_iterate.rs

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ fn main() {
2525
assert_eq!(iter.next(), Some(4));
2626
assert_eq!(iter.next(), Some(5));
2727
assert_eq!(iter.next(), None);
28+
// `gen` blocks are fused
29+
assert_eq!(iter.next(), None);
2830

2931
let mut iter = moved();
3032
assert_eq!(iter.next(), Some(42));

tests/ui/coroutine/gen_block_iterate_fused.rs

-19
This file was deleted.

0 commit comments

Comments
 (0)