(&mut self, params: &[String])
| 640 | } |
| 641 | |
| 642 | pub(super) fn compile_body(&mut self, params: &[String]) -> SSAChunk { |
| 643 | let mut body = self.with_fresh_chunk(|s| { |
| 644 | for p in params { |
| 645 | // Base name shadows the enclosing scope; prefix/`=` marker must be stripped. |
| 646 | s.ssa_versions.insert(super::types::param_base_name(p).to_string(), 0); |
| 647 | let _ = s.push_ssa_name(super::types::param_base_name(p), 0); |
| 648 | } |
| 649 | s.compile_block_body(); |
| 650 | }); |
| 651 | body.is_pure = !body.instructions.iter().any(|i| matches!( |
| 652 | i.opcode, |
| 653 | OpCode::CallPrint |
| 654 | | OpCode::StoreItem |
| 655 | | OpCode::DelItem |
| 656 | | OpCode::DelAttr |
| 657 | | OpCode::StoreAttr |
| 658 | | OpCode::CallInput |
| 659 | | OpCode::Global |
| 660 | | OpCode::Nonlocal |
| 661 | | OpCode::LoadAttr |
| 662 | | OpCode::Raise |
| 663 | | OpCode::RaiseFrom |
| 664 | | OpCode::Yield |
| 665 | )) && !Self::body_reads_free_name(&body, params); |
| 666 | // Pre-compute is_generator to avoid O(n) scan per `exec_call`. |
| 667 | body.is_generator = body.instructions.iter().any(|i| matches!( |
| 668 | i.opcode, |
| 669 | OpCode::Yield |
| 670 | )); |
| 671 | body |
| 672 | } |
| 673 | |
| 674 | /* A body is memoizable-pure only if every name it loads is bound locally; free names (globals, builtins) introduce mutable state, making memoization stale. */ |
| 675 | fn body_reads_free_name(body: &SSAChunk, params: &[String]) -> bool { |
no test coverage detected