Phase 61: structural if-sum+break lowering (dev-only)
This commit is contained in:
@ -638,7 +638,7 @@ fn normalized_selfhost_if_sum_p3_vm_bridge_direct_matches_structured() {
|
||||
let _ctx = normalized_dev_test_ctx();
|
||||
let structured = build_selfhost_if_sum_p3_structured_for_normalized_dev();
|
||||
let entry = structured.entry.expect("structured entry required");
|
||||
let cases = [0, 1, 3, 4];
|
||||
let cases = [0, 1, 3, 4, 5];
|
||||
|
||||
for n in cases {
|
||||
let input = [JoinValue::Int(n)];
|
||||
@ -646,6 +646,7 @@ fn normalized_selfhost_if_sum_p3_vm_bridge_direct_matches_structured() {
|
||||
let dev = run_joinir_vm_bridge(&structured, entry, &input, true);
|
||||
|
||||
assert_eq!(base, dev, "vm bridge mismatch for selfhost_if_sum_p3 n={}", n);
|
||||
assert_eq!(dev, JoinValue::Int(expected_selfhost_if_sum_p3(n)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -654,7 +655,7 @@ fn normalized_selfhost_if_sum_p3_ext_vm_bridge_direct_matches_structured() {
|
||||
let _ctx = normalized_dev_test_ctx();
|
||||
let structured = build_selfhost_if_sum_p3_ext_structured_for_normalized_dev();
|
||||
let entry = structured.entry.expect("structured entry required");
|
||||
let cases = [0, 1, 3, 4];
|
||||
let cases = [0, 1, 3, 4, 5];
|
||||
|
||||
for n in cases {
|
||||
let input = [JoinValue::Int(n)];
|
||||
@ -662,9 +663,30 @@ fn normalized_selfhost_if_sum_p3_ext_vm_bridge_direct_matches_structured() {
|
||||
let dev = run_joinir_vm_bridge(&structured, entry, &input, true);
|
||||
|
||||
assert_eq!(base, dev, "vm bridge mismatch for selfhost_if_sum_p3_ext n={}", n);
|
||||
assert_eq!(dev, JoinValue::Int(expected_selfhost_if_sum_p3_ext(n)));
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_selfhost_if_sum_p3(n: i64) -> i64 {
|
||||
if n <= 1 {
|
||||
return 0;
|
||||
}
|
||||
let sum = (n - 1) * n / 2;
|
||||
let count = n - 1;
|
||||
sum + count
|
||||
}
|
||||
|
||||
fn expected_selfhost_if_sum_p3_ext(n: i64) -> i64 {
|
||||
if n <= 0 {
|
||||
return 0;
|
||||
}
|
||||
// i=0: sum += 1
|
||||
// i=1..n-1: sum += i, count += 1
|
||||
let sum = 1 + (n - 1) * n / 2;
|
||||
let count = n - 1;
|
||||
sum + count
|
||||
}
|
||||
|
||||
/// Phase 53: selfhost args-parse P2 (practical variation with string carrier)
|
||||
#[test]
|
||||
fn normalized_selfhost_args_parse_p2_vm_bridge_direct_matches_structured() {
|
||||
@ -1067,17 +1089,17 @@ fn test_phase54_structural_axis_discrimination_p3() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase 58: Compare ownership-based P2 lowering with existing path
|
||||
/// Phase 60: Ownership relay threading helpers for P2 (analysis + contract)
|
||||
///
|
||||
/// This test demonstrates that OwnershipAnalyzer can analyze P2 fixtures
|
||||
/// and plan_to_p2_inputs can convert the result to reasonable CarrierVar structures.
|
||||
///
|
||||
/// Note: This is analysis-only testing. We're NOT modifying the actual lowering path yet.
|
||||
/// Full integration will come in Phase 60+ after validating the analysis is correct.
|
||||
/// plan_to_p2_inputs remains Fail-Fast on relay_writes (legacy contract),
|
||||
/// while plan_to_p2_inputs_with_relay accepts single-hop relay and promotes them
|
||||
/// to carriers (dev-only).
|
||||
#[test]
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
fn test_phase58_ownership_p2_comparison() {
|
||||
use nyash_rust::mir::join_ir::ownership::{plan_to_p2_inputs, OwnershipAnalyzer};
|
||||
fn test_phase60_ownership_p2_with_relay_conversion() {
|
||||
use nyash_rust::mir::join_ir::ownership::{
|
||||
plan_to_p2_inputs, plan_to_p2_inputs_with_relay, OwnershipAnalyzer,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
// Create a simple P2 fixture JSON (loop with i and sum)
|
||||
@ -1154,11 +1176,11 @@ fn test_phase58_ownership_p2_comparison() {
|
||||
loop_plan.relay_writes
|
||||
);
|
||||
|
||||
// Phase 58 Fail-Fast: relay_writes should be rejected
|
||||
// Legacy Fail-Fast: relay_writes should be rejected
|
||||
let result = plan_to_p2_inputs(loop_plan, "i");
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Phase 58: relay_writes should be rejected (not supported yet)"
|
||||
"Legacy contract: relay_writes should be rejected"
|
||||
);
|
||||
let err = result.unwrap_err();
|
||||
assert!(
|
||||
@ -1167,7 +1189,22 @@ fn test_phase58_ownership_p2_comparison() {
|
||||
err
|
||||
);
|
||||
|
||||
eprintln!("[phase58/test] Phase 58 Fail-Fast verified: relay_writes correctly rejected");
|
||||
// Phase 60 dev-only: with_relay should accept and include relay vars as carriers
|
||||
let inputs_with_relay =
|
||||
plan_to_p2_inputs_with_relay(loop_plan, "i").expect("with_relay should accept");
|
||||
assert!(
|
||||
inputs_with_relay.carriers.iter().any(|c| c.name == "sum"),
|
||||
"relay carrier sum should be promoted"
|
||||
);
|
||||
|
||||
eprintln!(
|
||||
"[phase60/test] with_relay carriers={:?}",
|
||||
inputs_with_relay
|
||||
.carriers
|
||||
.iter()
|
||||
.map(|c| &c.name)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
// Also test the case where variables ARE owned by loop (future scenario)
|
||||
// This would work once we support loop-local carriers
|
||||
@ -1239,7 +1276,41 @@ fn test_phase58_ownership_p2_comparison() {
|
||||
assert_eq!(inputs.carriers.len(), 1, "Should have 1 carrier (sum)");
|
||||
assert_eq!(inputs.carriers[0].name, "sum");
|
||||
|
||||
eprintln!("[phase58/test] Phase 58 conversion verified: sum correctly extracted as carrier");
|
||||
eprintln!("[phase60/test] Loop-local conversion verified");
|
||||
}
|
||||
|
||||
/// Phase 60: P2 dev-only ownership relay route matches legacy Break lowering.
|
||||
#[test]
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
fn test_phase60_break_lowering_ownership_matches_legacy() {
|
||||
use nyash_rust::mir::join_ir::frontend::ast_lowerer::lower_break_legacy_for_comparison;
|
||||
use nyash_rust::mir::join_ir::frontend::ast_lowerer::AstToJoinIrLowerer;
|
||||
|
||||
let _ctx = normalized_dev_test_ctx();
|
||||
|
||||
let program_json: serde_json::Value = serde_json::from_str(include_str!(
|
||||
"../docs/private/roadmap2/phases/phase-34-joinir-frontend/fixtures/loop_frontend_break.program.json"
|
||||
))
|
||||
.expect("fixture json");
|
||||
|
||||
let mut lowerer_new = AstToJoinIrLowerer::new();
|
||||
let structured_new = lowerer_new.lower_program_json(&program_json);
|
||||
|
||||
let mut lowerer_old = AstToJoinIrLowerer::new();
|
||||
let structured_old =
|
||||
lower_break_legacy_for_comparison(&mut lowerer_old, &program_json);
|
||||
|
||||
let entry_new = structured_new.entry.expect("new entry");
|
||||
let entry_old = structured_old.entry.expect("old entry");
|
||||
let input = vec![JoinValue::Int(5)];
|
||||
|
||||
let out_old = run_joinir_vm_bridge(&structured_old, entry_old, &input, false);
|
||||
let out_new = run_joinir_vm_bridge(&structured_new, entry_new, &input, false);
|
||||
|
||||
assert_eq!(
|
||||
out_old, out_new,
|
||||
"ownership relay dev route must match legacy output"
|
||||
);
|
||||
}
|
||||
|
||||
/// Phase 59: P3 with outer-owned carriers (relay case) should fail-fast
|
||||
@ -1412,3 +1483,40 @@ fn test_phase59_ownership_p3_loop_local_success() {
|
||||
|
||||
eprintln!("[phase59/test] P3 loop-local conversion verified: sum and count correctly extracted as carriers");
|
||||
}
|
||||
|
||||
/// Phase 60: Program(JSON v0) fixture (selfhost_if_sum_p3) should produce relay_writes and convert with single-hop relay.
|
||||
#[test]
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
fn test_phase60_ownership_p3_program_json_fixture_with_relay() {
|
||||
use nyash_rust::mir::join_ir::ownership::{plan_to_p3_inputs_with_relay, OwnershipAnalyzer};
|
||||
|
||||
let program_json: serde_json::Value = serde_json::from_str(include_str!(
|
||||
"../docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_if_sum_p3.program.json"
|
||||
))
|
||||
.expect("fixture json");
|
||||
|
||||
let mut analyzer = OwnershipAnalyzer::new();
|
||||
let plans = analyzer
|
||||
.analyze_json(&program_json)
|
||||
.expect("Program(JSON v0) analysis should succeed");
|
||||
|
||||
let loop_plan = plans
|
||||
.iter()
|
||||
.find(|p| !p.relay_writes.is_empty())
|
||||
.expect("expected a loop plan with relay_writes");
|
||||
|
||||
// i/sum/count are defined outside the loop but updated in the loop body -> relay_writes
|
||||
assert!(loop_plan.relay_writes.iter().any(|r| r.name == "i"));
|
||||
assert!(loop_plan.relay_writes.iter().any(|r| r.name == "sum"));
|
||||
assert!(loop_plan.relay_writes.iter().any(|r| r.name == "count"));
|
||||
|
||||
let inputs = plan_to_p3_inputs_with_relay(loop_plan, "i").expect("with_relay should succeed");
|
||||
|
||||
let mut carriers: Vec<&str> = inputs.carriers.iter().map(|c| c.name.as_str()).collect();
|
||||
carriers.sort();
|
||||
assert_eq!(carriers, vec!["count", "sum"]);
|
||||
|
||||
// n is read-only in loop condition -> capture + condition_capture
|
||||
assert!(inputs.captures.iter().any(|n| n == "n"));
|
||||
assert!(inputs.condition_captures.iter().any(|n| n == "n"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user