refactor(mir): Phase 139-P3-B - RoutingDecision を enum 対応 + レガシー削除

- RoutingDecision の missing_caps を Vec<CapabilityTag> に変更(型安全化)
- error_tags は to_tag() メソッドで自動生成
- 全 callsite を enum variant に修正
- capability_tags モジュール(文字列定数群)を完全削除
- 全テスト PASS(型安全性向上を確認)
- フォーマット適用
This commit is contained in:
nyash-codex
2025-12-16 07:02:14 +09:00
parent 146f14a019
commit e404746612
106 changed files with 1475 additions and 1017 deletions

View File

@ -132,8 +132,8 @@ impl NormalizedDevFixture {
use super::super::frontend::ast_lowerer::AstToJoinIrLowerer;
let fixture_json = self.fixture_content();
let program_json: serde_json::Value = serde_json::from_str(fixture_json)
.unwrap_or_else(|e| {
let program_json: serde_json::Value =
serde_json::from_str(fixture_json).unwrap_or_else(|e| {
panic!(
"{} fixture should be valid JSON: {}",
self.function_name(),
@ -165,11 +165,12 @@ mod tests {
#[test]
fn test_all_fixtures_have_unique_names() {
use std::collections::HashSet;
let names: HashSet<_> = ALL_DEV_FIXTURES
.iter()
.map(|f| f.function_name())
.collect();
assert_eq!(names.len(), ALL_DEV_FIXTURES.len(), "Fixture names must be unique");
let names: HashSet<_> = ALL_DEV_FIXTURES.iter().map(|f| f.function_name()).collect();
assert_eq!(
names.len(),
ALL_DEV_FIXTURES.len(),
"Fixture names must be unique"
);
}
#[test]

View File

@ -24,7 +24,12 @@ fn const_i64(func: &mut JoinFunction, dst: ValueId, value: i64) {
}
fn compare(func: &mut JoinFunction, dst: ValueId, op: CompareOp, lhs: ValueId, rhs: ValueId) {
func.body.push(JoinInst::Compute(MirLikeInst::Compare { dst, op, lhs, rhs }));
func.body.push(JoinInst::Compute(MirLikeInst::Compare {
dst,
op,
lhs,
rhs,
}));
}
fn unary_not(func: &mut JoinFunction, dst: ValueId, operand: ValueId) {
@ -44,7 +49,13 @@ fn bin_add(func: &mut JoinFunction, dst: ValueId, lhs: ValueId, rhs: ValueId) {
}));
}
fn select(func: &mut JoinFunction, dst: ValueId, cond: ValueId, then_val: ValueId, else_val: ValueId) {
fn select(
func: &mut JoinFunction,
dst: ValueId,
cond: ValueId,
then_val: ValueId,
else_val: ValueId,
) {
func.body.push(JoinInst::Compute(MirLikeInst::Select {
dst,
cond,
@ -165,8 +176,8 @@ pub fn build_jsonparser_skip_ws_real_structured_for_normalized_dev() -> JoinModu
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_skip_ws_real.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("jsonparser skip_ws real fixture should be valid JSON");
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("jsonparser skip_ws real fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
@ -189,8 +200,8 @@ pub fn build_jsonparser_parse_number_real_structured_for_normalized_dev() -> Joi
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_parse_number_real.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("jsonparser parse_number real fixture should be valid JSON");
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("jsonparser parse_number real fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
@ -319,13 +330,7 @@ pub fn build_pattern3_if_sum_multi_min_structured_for_normalized_dev() -> JoinMo
let cond_cmp = alloc();
let zero_const = alloc();
const_i64(&mut loop_step, zero_const, 0);
compare(
&mut loop_step,
cond_cmp,
CompareOp::Gt,
i_param,
zero_const,
);
compare(&mut loop_step, cond_cmp, CompareOp::Gt, i_param, zero_const);
// then: sum = sum + 1, count = count + 1
let one_const = alloc();
@ -415,18 +420,17 @@ pub fn build_pattern3_json_if_sum_min_structured_for_normalized_dev() -> JoinMod
// loop_step params: i, sum
let i_param = alloc();
let sum_param = alloc();
let mut loop_step = JoinFunction::new(loop_id, "loop_step".to_string(), vec![i_param, sum_param]);
let mut loop_step =
JoinFunction::new(loop_id, "loop_step".to_string(), vec![i_param, sum_param]);
// loop condition: i < 5
let limit_const = alloc();
let cmp_loop = alloc();
let exit_cond = alloc();
loop_step
.body
.push(JoinInst::Compute(MirLikeInst::Const {
dst: limit_const,
value: ConstValue::Integer(5),
}));
loop_step.body.push(JoinInst::Compute(MirLikeInst::Const {
dst: limit_const,
value: ConstValue::Integer(5),
}));
compare(
&mut loop_step,
cmp_loop,
@ -445,13 +449,7 @@ pub fn build_pattern3_json_if_sum_min_structured_for_normalized_dev() -> JoinMod
let cond_cmp = alloc();
let zero_const = alloc();
const_i64(&mut loop_step, zero_const, 0);
compare(
&mut loop_step,
cond_cmp,
CompareOp::Gt,
i_param,
zero_const,
);
compare(&mut loop_step, cond_cmp, CompareOp::Gt, i_param, zero_const);
// then: sum = sum + i
let sum_then = alloc();
@ -524,8 +522,8 @@ pub fn build_selfhost_if_sum_p3_ext_structured_for_normalized_dev() -> JoinModul
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_if_sum_p3_ext.program.json"
);
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("selfhost if_sum P3 ext fixture should be valid JSON");
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("selfhost if_sum P3 ext fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
@ -548,8 +546,8 @@ pub fn build_selfhost_args_parse_p2_structured_for_normalized_dev() -> JoinModul
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_args_parse_p2.program.json"
);
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("selfhost args_parse P2 fixture should be valid JSON");
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("selfhost args_parse P2 fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
@ -572,8 +570,8 @@ pub fn build_selfhost_stmt_count_p3_structured_for_normalized_dev() -> JoinModul
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_stmt_count_p3.program.json"
);
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("selfhost stmt_count P3 fixture should be valid JSON");
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("selfhost stmt_count P3 fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
@ -604,7 +602,7 @@ pub fn build_jsonparser_atoi_structured_for_normalized_dev() -> JoinModule {
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] jsonparser_atoi_mini structured module: {:#?}",
"[joinir/normalized-dev] jsonparser_atoi_mini structured module: {:#?}",
module
);
}
@ -679,18 +677,9 @@ pub fn build_pattern3_if_sum_min_structured_for_normalized_dev() -> JoinModule {
let loop_condition = bin(BinaryOperator::Less, var("i"), int_lit(3));
let if_condition = bin(BinaryOperator::Greater, var("i"), int_lit(0));
let then_update = assignment(
var("sum"),
bin(BinaryOperator::Add, var("sum"), int_lit(1)),
);
let else_update = assignment(
var("sum"),
bin(BinaryOperator::Add, var("sum"), int_lit(0)),
);
let counter_update = assignment(
var("i"),
bin(BinaryOperator::Add, var("i"), int_lit(1)),
);
let then_update = assignment(var("sum"), bin(BinaryOperator::Add, var("sum"), int_lit(1)));
let else_update = assignment(var("sum"), bin(BinaryOperator::Add, var("sum"), int_lit(0)));
let counter_update = assignment(var("i"), bin(BinaryOperator::Add, var("i"), int_lit(1)));
let if_stmt = ASTNode::If {
condition: Box::new(if_condition),
@ -707,9 +696,14 @@ pub fn build_pattern3_if_sum_min_structured_for_normalized_dev() -> JoinModule {
let i_id = join_value_space.alloc_param();
cond_env.insert("i".to_string(), i_id);
let (module, _meta) =
lower_if_sum_pattern(&loop_condition, &if_stmt, &body, &cond_env, &mut join_value_space)
.expect("if-sum lowering should succeed for minimal pattern3");
let (module, _meta) = lower_if_sum_pattern(
&loop_condition,
&if_stmt,
&body,
&cond_env,
&mut join_value_space,
)
.expect("if-sum lowering should succeed for minimal pattern3");
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
@ -743,7 +737,8 @@ pub fn build_jsonparser_parse_array_continue_skip_ws_structured_for_normalized_d
/// JsonParser _parse_object の whitespace continue ループを Structured で組み立てるヘルパーdev-only
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_parse_object_continue_skip_ws.program.json
pub fn build_jsonparser_parse_object_continue_skip_ws_structured_for_normalized_dev() -> JoinModule {
pub fn build_jsonparser_parse_object_continue_skip_ws_structured_for_normalized_dev() -> JoinModule
{
use super::dev_fixtures::NormalizedDevFixture;
NormalizedDevFixture::Pattern4JsonParserParseObjectContinueSkipWs.load_and_lower()
}
@ -818,15 +813,15 @@ pub mod prelude {
build_jsonparser_skip_ws_real_structured_for_normalized_dev,
build_jsonparser_skip_ws_structured_for_normalized_dev,
build_jsonparser_unescape_string_step2_min_structured_for_normalized_dev,
build_parse_array_min_structured_for_normalized_dev,
build_parse_object_min_structured_for_normalized_dev,
build_parse_string_composite_min_structured_for_normalized_dev,
build_pattern2_break_fixture_structured, build_pattern2_minimal_structured,
build_pattern3_if_sum_min_structured_for_normalized_dev,
build_pattern3_if_sum_multi_min_structured_for_normalized_dev,
build_pattern3_json_if_sum_min_structured_for_normalized_dev,
build_pattern4_continue_min_structured_for_normalized_dev,
build_pattern_continue_return_min_structured_for_normalized_dev,
build_parse_string_composite_min_structured_for_normalized_dev,
build_parse_array_min_structured_for_normalized_dev,
build_parse_object_min_structured_for_normalized_dev,
build_selfhost_if_sum_p3_ext_structured_for_normalized_dev,
build_selfhost_if_sum_p3_structured_for_normalized_dev,
build_selfhost_token_scan_p2_accum_structured_for_normalized_dev,

View File

@ -29,12 +29,10 @@ impl LoopStepInspector {
///
/// ループ条件や continue/break 判定で使用される。
pub fn has_compare_instruction(loop_step_func: &JoinFunction) -> bool {
loop_step_func.body.iter().any(|inst| {
matches!(
inst,
JoinInst::Compute(MirLikeInst::Compare { .. })
)
})
loop_step_func
.body
.iter()
.any(|inst| matches!(inst, JoinInst::Compute(MirLikeInst::Compare { .. })))
}
/// 条件付き Jump の個数をカウント
@ -77,10 +75,7 @@ mod tests {
use super::*;
use crate::mir::join_ir::{JoinFuncId, VarId};
fn make_dummy_loop_step(
body: Vec<JoinInst>,
param_count: usize,
) -> JoinFunction {
fn make_dummy_loop_step(body: Vec<JoinInst>, param_count: usize) -> JoinFunction {
let params: Vec<_> = (0..param_count).map(|i| VarId(i as u32)).collect();
JoinFunction {
id: JoinFuncId(1),
@ -105,7 +100,9 @@ mod tests {
assert!(LoopStepInspector::has_select_instruction(&func_with_select));
let func_without_select = make_dummy_loop_step(vec![], 2);
assert!(!LoopStepInspector::has_select_instruction(&func_without_select));
assert!(!LoopStepInspector::has_select_instruction(
&func_without_select
));
}
#[test]
@ -124,7 +121,7 @@ mod tests {
},
JoinInst::Jump {
target: JoinFuncId(2),
cond: None, // 無条件は含まれない
cond: None, // 無条件は含まれない
args: vec![],
},
],
@ -139,7 +136,7 @@ mod tests {
vec![JoinInst::Call {
target: JoinFuncId(1),
args: vec![],
k_next: None, // tail call
k_next: None, // tail call
results: vec![],
}],
2,
@ -150,7 +147,7 @@ mod tests {
vec![JoinInst::Call {
target: JoinFuncId(1),
args: vec![],
k_next: Some(JoinFuncId(3)), // not tail call
k_next: Some(JoinFuncId(3)), // not tail call
results: vec![],
}],
2,
@ -160,10 +157,20 @@ mod tests {
#[test]
fn test_has_reasonable_param_count() {
assert!(!LoopStepInspector::has_reasonable_param_count(&make_dummy_loop_step(vec![], 1)));
assert!(LoopStepInspector::has_reasonable_param_count(&make_dummy_loop_step(vec![], 2)));
assert!(LoopStepInspector::has_reasonable_param_count(&make_dummy_loop_step(vec![], 3)));
assert!(LoopStepInspector::has_reasonable_param_count(&make_dummy_loop_step(vec![], 4)));
assert!(!LoopStepInspector::has_reasonable_param_count(&make_dummy_loop_step(vec![], 5)));
assert!(!LoopStepInspector::has_reasonable_param_count(
&make_dummy_loop_step(vec![], 1)
));
assert!(LoopStepInspector::has_reasonable_param_count(
&make_dummy_loop_step(vec![], 2)
));
assert!(LoopStepInspector::has_reasonable_param_count(
&make_dummy_loop_step(vec![], 3)
));
assert!(LoopStepInspector::has_reasonable_param_count(
&make_dummy_loop_step(vec![], 4)
));
assert!(!LoopStepInspector::has_reasonable_param_count(
&make_dummy_loop_step(vec![], 5)
));
}
}

View File

@ -37,7 +37,6 @@ pub enum ShapeCapabilityKind {
/// Selfhost P3 if-sum family
SelfhostP3IfSum,
// Future: Other P2 patterns
// P2MidAtOfLoop,
// P2HeavyString,
@ -100,8 +99,14 @@ pub enum NormalizedDevShape {
type Detector = fn(&JoinModule) -> bool;
const SHAPE_DETECTORS: &[(NormalizedDevShape, Detector)] = &[
(NormalizedDevShape::Pattern1Mini, detectors::is_pattern1_mini),
(NormalizedDevShape::Pattern2Mini, detectors::is_pattern2_mini),
(
NormalizedDevShape::Pattern1Mini,
detectors::is_pattern1_mini,
),
(
NormalizedDevShape::Pattern2Mini,
detectors::is_pattern2_mini,
),
(
NormalizedDevShape::JsonparserSkipWsMini,
detectors::is_jsonparser_skip_ws_mini,
@ -552,18 +557,16 @@ mod detectors {
let has_select = loop_func.body.iter().any(|inst| match inst {
JoinInst::Select { .. } => true,
JoinInst::Compute(mir_inst) => matches!(
mir_inst,
crate::mir::join_ir::MirLikeInst::Select { .. }
),
JoinInst::Compute(mir_inst) => {
matches!(mir_inst, crate::mir::join_ir::MirLikeInst::Select { .. })
}
_ => false,
});
let has_boxcall = loop_func.body.iter().any(|inst| match inst {
JoinInst::Compute(mir_inst) => matches!(
mir_inst,
crate::mir::join_ir::MirLikeInst::BoxCall { .. }
),
JoinInst::Compute(mir_inst) => {
matches!(mir_inst, crate::mir::join_ir::MirLikeInst::BoxCall { .. })
}
_ => false,
});
@ -601,8 +604,7 @@ mod detectors {
.iter()
.any(|inst| matches!(inst, JoinInst::Call { k_next: None, .. }));
let param_set: std::collections::BTreeSet<_> =
loop_step.params.iter().copied().collect();
let param_set: std::collections::BTreeSet<_> = loop_step.params.iter().copied().collect();
let has_ge_compare_between_params = loop_step.body.iter().any(|inst| match inst {
JoinInst::Compute(mir_inst) => match mir_inst {
@ -617,10 +619,9 @@ mod detectors {
});
let has_boxcall = loop_step.body.iter().any(|inst| match inst {
JoinInst::Compute(mir_inst) => matches!(
mir_inst,
crate::mir::join_ir::MirLikeInst::BoxCall { .. }
),
JoinInst::Compute(mir_inst) => {
matches!(mir_inst, crate::mir::join_ir::MirLikeInst::BoxCall { .. })
}
_ => false,
});
@ -667,10 +668,9 @@ mod detectors {
// Phase 220: Select can be either JoinInst::Select or Compute(MirLikeInst::Select)
let has_select = loop_step.body.iter().any(|inst| match inst {
JoinInst::Select { .. } => true,
JoinInst::Compute(mir_inst) => matches!(
mir_inst,
crate::mir::join_ir::MirLikeInst::Select { .. }
),
JoinInst::Compute(mir_inst) => {
matches!(mir_inst, crate::mir::join_ir::MirLikeInst::Select { .. })
}
_ => false,
});
@ -896,7 +896,7 @@ mod detectors {
&& has_select
&& has_tail_call
&& reasonable_param_count
&& k_exit_jumps_count == 1 // Exactly one loop break (not early return)
&& k_exit_jumps_count == 1 // Exactly one loop break (not early return)
}
pub(crate) fn is_jsonparser_parse_array_continue_skip_ws(module: &JoinModule) -> bool {
@ -952,7 +952,7 @@ mod detectors {
&& has_select
&& has_tail_call
&& reasonable_param_count
&& k_exit_jumps_count >= 2 // At least 2: loop break + early return
&& k_exit_jumps_count >= 2 // At least 2: loop break + early return
}
/// Phase 90: Check if module matches Parse String Composite pattern
@ -993,8 +993,12 @@ mod detectors {
// Check if rhs is a const value 2 (indicating i+=2 for escape)
// We need to check if rhs points to a Const instruction with value 2
loop_step.body.iter().any(|other_inst| match other_inst {
JoinInst::Compute(crate::mir::join_ir::MirLikeInst::Const { dst, value }) => {
dst == rhs && matches!(value, crate::mir::join_ir::ConstValue::Integer(2))
JoinInst::Compute(crate::mir::join_ir::MirLikeInst::Const {
dst,
value,
}) => {
dst == rhs
&& matches!(value, crate::mir::join_ir::ConstValue::Integer(2))
}
_ => false,
})
@ -1171,7 +1175,9 @@ mod tests {
shapes
);
assert!(
!shapes.iter().any(|s| matches!(s, NormalizedDevShape::Pattern3IfSumMinimal)),
!shapes
.iter()
.any(|s| matches!(s, NormalizedDevShape::Pattern3IfSumMinimal)),
"selfhost_if_sum_p3 should not rely on canonical P3 minimal detection: {:?}",
shapes
);
@ -1286,7 +1292,9 @@ mod tests {
k_next: None,
dst: Some(ValueId(2)),
},
JoinInst::Ret { value: Some(ValueId(2)) },
JoinInst::Ret {
value: Some(ValueId(2)),
},
],
exit_cont: None,
};
@ -1348,7 +1356,9 @@ mod tests {
k_next: None,
dst: Some(ValueId(40)),
},
JoinInst::Ret { value: Some(ValueId(40)) },
JoinInst::Ret {
value: Some(ValueId(40)),
},
],
exit_cont: None,
};
@ -1358,7 +1368,9 @@ mod tests {
id: JoinFuncId::new(2),
name: "k_exit".to_string(),
params: vec![ValueId(0)],
body: vec![JoinInst::Ret { value: Some(ValueId(0)) }],
body: vec![JoinInst::Ret {
value: Some(ValueId(0)),
}],
exit_cont: None,
};