feat(joinir): Phase 45 - JoinIR mode unification

Unified JoinIR routing logic through centralized JoinIrMode enum:

Key changes:
- Added JoinIrMode enum (StructuredOnly / NormalizedDev / NormalizedCanonical)
- Added current_joinir_mode() for centralized mode determination
- Refactored normalized_dev_enabled() as thin wrapper over mode enum
- Updated bridge.rs: mode-based routing with canonical P2-Core special handling
- Updated runner.rs: mode pattern matching for dev roundtrip path

Files modified:
- joinir_dev.rs: JoinIrMode enum + current_joinir_mode() (+49 lines)
- bridge.rs: Replaced boolean checks with mode pattern matching (+29 lines)
- runner.rs: Mode-based routing logic (+9 lines)
- CURRENT_TASK.md: Phase 45 implementation summary

Documentation:
- phase45-norm-mode-design.md: Complete design spec and implementation guide

Behavior preservation:
- Canonical P2-Core shapes: always Normalized→MIR(direct) (mode-independent)
- NormalizedDev mode: Structured→Normalized→MIR for supported shapes
- StructuredOnly mode: Structured→MIR direct (default)

Tests: 937/937 PASS (no regression, pure refactor)

🤖 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-12 03:31:58 +09:00
parent ed8e2d3142
commit 879d3ee08e
5 changed files with 254 additions and 16 deletions

View File

@ -1,8 +1,26 @@
//! JoinIR development / experimental flags (SSOT).
//! Phase 72-C: Consolidate all NYASH_JOINIR_* dev flags through centralized helpers.
//! Phase 45: JoinIR mode unification (StructuredOnly / NormalizedDev / NormalizedCanonical)
use crate::config::env::env_bool;
/// Phase 45: JoinIR execution mode enum
///
/// Centralizes all JoinIR routing decisions (Structured vs Normalized paths).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JoinIrMode {
/// Default mode: Structured→MIR direct (no Normalized layer)
StructuredOnly,
/// Development mode: Structured→Normalized→MIR(direct) for supported shapes
/// Requires `--features normalized_dev` + env var
NormalizedDev,
/// Future mode: All canonical shapes use Normalized→MIR(direct)
/// Currently unused, reserved for Phase 46+ canonical migration
NormalizedCanonical,
}
/// NYASH_JOINIR_LOWER_GENERIC=1 - Enable generic lowering path for JoinIR
/// (CRITICAL: 15 occurrences in codebase)
pub fn lower_generic_enabled() -> bool {
@ -105,16 +123,37 @@ pub fn joinir_normalized_dev_run_enabled() -> bool {
env_bool("NYASH_JOINIR_NORMALIZED_DEV_RUN")
}
/// Phase 45: Get current JoinIR execution mode
///
/// Determines routing based on feature flags and environment variables:
/// - `--features normalized_dev` + `NYASH_JOINIR_NORMALIZED_DEV_RUN=1` → NormalizedDev
/// - Otherwise → StructuredOnly
///
/// Note: NormalizedCanonical is reserved for future canonical migration (Phase 46+)
pub fn current_joinir_mode() -> JoinIrMode {
#[cfg(feature = "normalized_dev")]
{
if joinir_normalized_dev_run_enabled() {
JoinIrMode::NormalizedDev
} else {
JoinIrMode::StructuredOnly
}
}
#[cfg(not(feature = "normalized_dev"))]
{
JoinIrMode::StructuredOnly
}
}
/// Unified switch for Normalized dev experiments (feature + env).
///
/// - Requires `--features normalized_dev`
/// - Requires `NYASH_JOINIR_NORMALIZED_DEV_RUN=1`
///
/// Phase 45: Now implemented as a thin wrapper over current_joinir_mode()
pub fn normalized_dev_enabled() -> bool {
if cfg!(feature = "normalized_dev") {
joinir_normalized_dev_run_enabled()
} else {
false
}
matches!(current_joinir_mode(), JoinIrMode::NormalizedDev)
}
/// JOINIR_TEST_DEBUG=1 (or NYASH_JOINIR_TEST_DEBUG=1) - Verbose logging for normalized dev tests

View File

@ -31,7 +31,7 @@
use std::collections::HashMap;
#[cfg(feature = "normalized_dev")]
use crate::config::env::normalized_dev_enabled;
use crate::config::env::joinir_dev::{current_joinir_mode, JoinIrMode};
use crate::mir::join_ir::{ConstValue, JoinFuncId, JoinInst, JoinModule, MirLikeInst, VarId};
#[cfg(feature = "normalized_dev")]
use crate::mir::join_ir::normalized::{
@ -51,8 +51,13 @@ pub fn run_joinir_function(
args: &[JoinValue],
) -> Result<JoinValue, JoinRuntimeError> {
#[cfg(feature = "normalized_dev")]
if normalized_dev_enabled() {
return run_joinir_function_normalized_dev(vm, module, entry, args);
match current_joinir_mode() {
JoinIrMode::NormalizedDev => {
return run_joinir_function_normalized_dev(vm, module, entry, args);
}
_ => {
// Structured-only path (default)
}
}
execute_function(vm, module, entry, args.to_vec())
@ -65,6 +70,7 @@ fn run_joinir_function_normalized_dev(
entry: JoinFuncId,
args: &[JoinValue],
) -> Result<JoinValue, JoinRuntimeError> {
// JoinIrMode::NormalizedDev path: Structured→Normalized→Structured roundtrip
// Keep dev path opt-in and fail-fast: only Structured P1/P2 minis are supported.
dev_env::with_dev_env_if_unset(|| {
let debug = dev_env::normalized_dev_logs_enabled();

View File

@ -1,9 +1,13 @@
use super::{convert_join_module_to_mir_with_meta, JoinIrVmBridgeError};
use crate::mir::join_ir::frontend::JoinFuncMetaMap;
use crate::mir::join_ir::{JoinIrPhase, JoinModule};
use crate::mir::join_ir::JoinModule;
use crate::mir::MirModule;
use std::collections::BTreeMap;
#[cfg(feature = "normalized_dev")]
use crate::config::env::joinir_dev::{current_joinir_mode, JoinIrMode};
#[cfg(feature = "normalized_dev")]
use crate::mir::join_ir::JoinIrPhase;
#[cfg(feature = "normalized_dev")]
use crate::mir::join_ir::normalized::{
normalize_pattern1_minimal, normalize_pattern2_minimal, NormalizedModule,
@ -158,14 +162,21 @@ fn try_normalized_direct_bridge(
}
}
/// JoinIR → MIR の単一入口。Normalized dev が有効なら roundtrip してから既存経路へ
/// JoinIR → MIR の単一入口。Mode に応じて Normalized/Structured 経路を選択
///
/// Phase 45: JoinIrMode 導入による統一ルーティング:
/// - Canonical P2-Core shapes → 常に Normalized→MIR(direct)mode 無視)
/// - NormalizedDev → サポート形状のみ Normalized path、それ以外 Structured path
/// - StructuredOnly | NormalizedCanonical → Structured path
pub(crate) fn bridge_joinir_to_mir_with_meta(
module: &JoinModule,
meta: &JoinFuncMetaMap,
) -> Result<MirModule, JoinIrVmBridgeError> {
#[cfg(feature = "normalized_dev")]
{
// Phase 41: canonical shapes は env が OFF でも常に Normalized → MIR を通す。
let mode = current_joinir_mode();
// Phase 41: canonical shapes は mode が何であろうと常に Normalized → MIR を通す。
let canonical_shapes = shape_guard::canonical_shapes(module);
if !canonical_shapes.is_empty() {
match try_normalized_direct_bridge(module, meta, &canonical_shapes, false, false)? {
@ -178,11 +189,19 @@ pub(crate) fn bridge_joinir_to_mir_with_meta(
}
}
if crate::config::env::normalized_dev_enabled() {
let shapes = shape_guard::direct_shapes(module);
match try_normalized_direct_bridge(module, meta, &shapes, true, true)? {
Some(mir) => return Ok(mir),
None => {}
// Phase 45: Mode によるルーティング分岐
match mode {
JoinIrMode::NormalizedDev => {
// サポート形状のみ Normalized path を試行、失敗時は Structured fallback
let shapes = shape_guard::direct_shapes(module);
match try_normalized_direct_bridge(module, meta, &shapes, true, true)? {
Some(mir) => return Ok(mir),
None => {} // Fallback to Structured
}
}
JoinIrMode::StructuredOnly | JoinIrMode::NormalizedCanonical => {
// Structured path のみ使用
// NormalizedCanonical は将来 Phase 46+ で canonical migration 完了後に専用経路を持つ)
}
}
}