| 560 | /// 3. Edge effects (propagate to successors) |
| 561 | #[expect(clippy::too_many_lines, reason = "minimal amount")] |
| 562 | fn forward(self) { |
| 563 | let Self { |
| 564 | analysis, |
| 565 | lattice, |
| 566 | derived_states, |
| 567 | |
| 568 | body, |
| 569 | state, |
| 570 | id, |
| 571 | block, |
| 572 | mut propagate, |
| 573 | } = self; |
| 574 | |
| 575 | analysis.transfer_block_params( |
| 576 | Location { |
| 577 | block: id, |
| 578 | statement_index: 0, |
| 579 | }, |
| 580 | block.params, |
| 581 | state, |
| 582 | ); |
| 583 | |
| 584 | // Statement indices start at 1 because index 0 represents the block parameters. |
| 585 | for (index, statement) in block.statements.iter().enumerate() { |
| 586 | let location = Location { |
| 587 | block: id, |
| 588 | statement_index: index + 1, |
| 589 | }; |
| 590 | |
| 591 | analysis.transfer_statement(location, statement, state); |
| 592 | } |
| 593 | |
| 594 | let location = Location { |
| 595 | block: id, |
| 596 | statement_index: block.statements.len() + 1, |
| 597 | }; |
| 598 | |
| 599 | analysis.transfer_terminator(location, &block.terminator, state); |
| 600 | |
| 601 | // After processing all instructions, `state` holds the exit state of this block. |
| 602 | let exit_state = state; |
| 603 | derived_states[id].clone_from(exit_state); |
| 604 | |
| 605 | match &block.terminator.kind { |
| 606 | TerminatorKind::Goto(Goto { target }) => { |
| 607 | analysis.transfer_edge( |
| 608 | id, |
| 609 | &target.args, |
| 610 | target.block, |
| 611 | &body.basic_blocks[target.block].params, |
| 612 | exit_state, |
| 613 | ); |
| 614 | |
| 615 | propagate(target.block, exit_state); |
| 616 | } |
| 617 | &TerminatorKind::GraphRead(GraphRead { |
| 618 | head: _, |
| 619 | body: _, |