feat(joinir): Phase 200-B/C/D capture analysis + Phase 201-A reserved_value_ids infra

Phase 200-B: FunctionScopeCaptureAnalyzer implementation
- analyze_captured_vars_v2() with structural loop matching
- CapturedEnv for immutable function-scope variables
- ParamRole::Condition for condition-only variables

Phase 200-C: ConditionEnvBuilder extension
- build_with_captures() integrates CapturedEnv into ConditionEnv
- fn_body propagation through LoopPatternContext to Pattern 2

Phase 200-D: E2E verification
- capture detection working for base, limit, n etc.
- Test files: phase200d_capture_minimal.hako, phase200d_capture_in_condition.hako

Phase 201-A: MirBuilder reserved_value_ids infrastructure
- reserved_value_ids: HashSet<ValueId> field in MirBuilder
- next_value_id() skips reserved IDs
- merge/mod.rs sets/clears reserved IDs around JoinIR merge

Phase 201: JoinValueSpace design document
- Param/Local/PHI disjoint regions design
- API: alloc_param(), alloc_local(), reserve_phi()
- Migration plan for Pattern 1-4 lowerers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-09 18:32:03 +09:00
parent 3a9b44c4e2
commit 32a91e31ac
24 changed files with 2815 additions and 193 deletions

View File

@ -31,12 +31,26 @@ impl super::MirBuilder {
/// Allocate a new ValueId in the appropriate context
/// - Inside function: uses function-local allocator
/// - Outside function: uses module-global allocator
///
/// Phase 201-A: Skips reserved ValueIds (PHI dsts from LoopHeaderPhiBuilder)
/// to prevent carrier value corruption in JoinIR loops.
#[inline]
pub(crate) fn next_value_id(&mut self) -> super::ValueId {
if let Some(ref mut f) = self.current_function {
f.next_value_id() // Function context
} else {
self.value_gen.next() // Module context
loop {
let candidate = if let Some(ref mut f) = self.current_function {
f.next_value_id() // Function context
} else {
self.value_gen.next() // Module context
};
// Phase 201-A: Skip reserved PHI dst ValueIds
if !self.reserved_value_ids.contains(&candidate) {
return candidate;
}
// Reserved ID - try next one (loop continues)
if std::env::var("NYASH_201A_DEBUG").is_ok() {
eprintln!("[201-A] next_value_id: Skipping reserved {:?}", candidate);
}
}
}