feat(edgecfg): Phase 267 P0 BranchStub + emit_frag (Branch→MIR)
This commit is contained in:
32
src/mir/builder/control_flow/edgecfg/api/branch_stub.rs
Normal file
32
src/mir/builder/control_flow/edgecfg/api/branch_stub.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use crate::mir::basic_block::{BasicBlockId, EdgeArgs};
|
||||
use crate::mir::ValueId;
|
||||
|
||||
/// 条件分岐の未配線エッジペア(Phase 267 P0)
|
||||
///
|
||||
/// # 責務
|
||||
/// - header → then/else の分岐を表現
|
||||
/// - set_branch_with_edge_args() へのマッピング用
|
||||
///
|
||||
/// # 制約
|
||||
/// - 1 block = 1 terminator: from は重複禁止
|
||||
/// - then_target, else_target は必ず Some(未配線 Branch は存在しない)
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct BranchStub {
|
||||
/// 分岐元ブロック
|
||||
pub from: BasicBlockId,
|
||||
|
||||
/// 分岐条件の値
|
||||
pub cond: ValueId,
|
||||
|
||||
/// then ブランチの配線先
|
||||
pub then_target: BasicBlockId,
|
||||
|
||||
/// then ブランチの引数
|
||||
pub then_args: EdgeArgs,
|
||||
|
||||
/// else ブランチの配線先
|
||||
pub else_target: BasicBlockId,
|
||||
|
||||
/// else ブランチの引数
|
||||
pub else_args: EdgeArgs,
|
||||
}
|
||||
@ -10,12 +10,14 @@
|
||||
*/
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use crate::mir::basic_block::BasicBlockId;
|
||||
use crate::mir::basic_block::{BasicBlockId, EdgeArgs};
|
||||
use crate::mir::control_form::LoopId;
|
||||
use crate::mir::value_id::ValueId;
|
||||
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
|
||||
use super::frag::Frag;
|
||||
use super::exit_kind::ExitKind;
|
||||
use super::edge_stub::EdgeStub; // Phase 265 P2: wires/exits 分離で必要
|
||||
use super::branch_stub::BranchStub; // Phase 267 P0: Branch 生成に必要
|
||||
|
||||
/// 順次合成: `a; b`
|
||||
///
|
||||
@ -68,37 +70,62 @@ pub(crate) fn seq(a: Frag, b: Frag) -> Frag {
|
||||
// b の wires もマージ
|
||||
wires.extend(b.wires);
|
||||
|
||||
// Phase 267 P0: branches もマージ
|
||||
let mut branches = Vec::new();
|
||||
branches.extend(a.branches);
|
||||
branches.extend(b.branches);
|
||||
|
||||
Frag {
|
||||
entry: a.entry, // seq の入口は a の入口
|
||||
exits, // a の非 Normal + b の全 exit
|
||||
wires, // a.Normal → b.entry + a.wires + b.wires
|
||||
branches, // Phase 267 P0: a.branches + b.branches
|
||||
}
|
||||
}
|
||||
|
||||
/// 条件分岐合成: `if (cond) { t } else { e }`
|
||||
///
|
||||
/// # Phase 265 P2: wires/exits 分離実装完了
|
||||
/// # Phase 267 P0: Branch 生成実装完了
|
||||
/// - header → then/else の BranchStub を branches に追加
|
||||
/// - t/e.Normal → join_frag.entry を wires に追加(内部配線)
|
||||
/// - if の exits は join_frag.exits(join 以降の外へ出る exit)
|
||||
///
|
||||
/// # 配線ルール
|
||||
/// - header → t.entry / e.entry を BranchStub として branches に追加(Phase 267 P0)
|
||||
/// - t/e.Normal の EdgeStub.target = Some(join_frag.entry) → wires
|
||||
/// - if の exits = t/e の非 Normal + join_frag.exits
|
||||
/// - if の wires = t/e.Normal → join + t/e/join の wires
|
||||
/// - if の branches = header の BranchStub + t/e/join の branches
|
||||
///
|
||||
/// # 引数
|
||||
/// - `header`: 条件判定を行うブロック
|
||||
/// - `_cond`: 条件値(Phase 266+ で MIR 命令生成時に使用)
|
||||
/// - `cond`: 条件値(Phase 267 P0 で使用開始)
|
||||
/// - `t`: then 分岐の断片
|
||||
/// - `e`: else 分岐の断片
|
||||
/// - `join_frag`: join 以降の断片(t/e.Normal の配線先 + join 以降の処理)
|
||||
pub(crate) fn if_(
|
||||
header: BasicBlockId,
|
||||
_cond: ValueId, // Phase 266+ で使用
|
||||
cond: ValueId, // Phase 267 P0 で使用開始
|
||||
t: Frag, // then 分岐
|
||||
e: Frag, // else 分岐
|
||||
join_frag: Frag, // join 以降の断片
|
||||
) -> Frag {
|
||||
// Phase 267 P0: header → then/else の BranchStub を作成
|
||||
let branch = BranchStub {
|
||||
from: header,
|
||||
cond,
|
||||
then_target: t.entry,
|
||||
then_args: EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![], // TODO: Phase 267 P2+ で then の入口引数計算
|
||||
},
|
||||
else_target: e.entry,
|
||||
else_args: EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![], // TODO: Phase 267 P2+ で else の入口引数計算
|
||||
},
|
||||
};
|
||||
|
||||
let mut exits = BTreeMap::new();
|
||||
let mut wires = Vec::new();
|
||||
|
||||
@ -156,10 +183,17 @@ pub(crate) fn if_(
|
||||
// join_frag の wires もマージ
|
||||
wires.extend(join_frag.wires);
|
||||
|
||||
// Phase 267 P0: branches を統合
|
||||
let mut branches = vec![branch];
|
||||
branches.extend(t.branches);
|
||||
branches.extend(e.branches);
|
||||
branches.extend(join_frag.branches);
|
||||
|
||||
Frag {
|
||||
entry: header, // if の入口は header
|
||||
exits, // t/e の非 Normal + join_frag.exits
|
||||
wires, // t/e.Normal → join_frag.entry + t/e/join の wires
|
||||
branches, // Phase 267 P0: header の BranchStub + t/e/join の branches
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,10 +260,14 @@ pub(crate) fn loop_(
|
||||
// body の wires もマージ
|
||||
wires.extend(body.wires);
|
||||
|
||||
// Phase 267 P0: body の branches もマージ
|
||||
let branches = body.branches;
|
||||
|
||||
Frag {
|
||||
entry: header, // ループの入口
|
||||
exits, // Normal, Return, Unwind のみ(未配線)
|
||||
wires, // Continue → header, Break → after(配線済み)
|
||||
branches, // Phase 267 P0: body の branches
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,6 +321,7 @@ mod tests {
|
||||
entry: body_entry,
|
||||
exits: body_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Execute: compose::loop_()
|
||||
@ -317,6 +356,7 @@ mod tests {
|
||||
entry: body_entry,
|
||||
exits: body_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Execute: compose::loop_()
|
||||
@ -366,6 +406,7 @@ mod tests {
|
||||
entry: body,
|
||||
exits: body_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Execute: compose::loop_()
|
||||
@ -399,6 +440,7 @@ mod tests {
|
||||
entry: body,
|
||||
exits: body_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Execute: compose::loop_()
|
||||
@ -432,6 +474,7 @@ mod tests {
|
||||
entry: body,
|
||||
exits: body_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Execute: compose::loop_()
|
||||
@ -461,6 +504,7 @@ mod tests {
|
||||
entry: a_entry,
|
||||
exits: a_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
let mut b_exits = BTreeMap::new();
|
||||
@ -472,6 +516,7 @@ mod tests {
|
||||
entry: b_entry,
|
||||
exits: b_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Execute: compose::seq()
|
||||
@ -514,6 +559,7 @@ mod tests {
|
||||
entry: a_entry,
|
||||
exits: a_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
let mut b_exits = BTreeMap::new();
|
||||
@ -525,6 +571,7 @@ mod tests {
|
||||
entry: b_entry,
|
||||
exits: b_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Execute
|
||||
@ -564,6 +611,7 @@ mod tests {
|
||||
entry: then_entry,
|
||||
exits: then_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
let mut else_exits = BTreeMap::new();
|
||||
@ -575,6 +623,7 @@ mod tests {
|
||||
entry: else_entry,
|
||||
exits: else_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
let mut join_exits = BTreeMap::new();
|
||||
@ -586,6 +635,7 @@ mod tests {
|
||||
entry: join_entry,
|
||||
exits: join_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Execute: compose::if_()
|
||||
@ -630,6 +680,7 @@ mod tests {
|
||||
entry: then_entry,
|
||||
exits: then_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
let mut else_exits = BTreeMap::new();
|
||||
@ -645,12 +696,14 @@ mod tests {
|
||||
entry: else_entry,
|
||||
exits: else_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
let join_frag = Frag {
|
||||
entry: join_entry,
|
||||
exits: BTreeMap::new(),
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Execute
|
||||
|
||||
@ -100,6 +100,80 @@ pub fn emit_wires(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Frag を MIR に emit(Phase 267 P0: SSOT)
|
||||
///
|
||||
/// # 責務
|
||||
/// - verify_frag_invariants_strict() で事前検証(Fail-Fast)
|
||||
/// - wires → Jump/Return terminator(emit_wires を呼ぶ)
|
||||
/// - branches → Branch terminator(set_branch_with_edge_args を使う)
|
||||
/// - 1 block = 1 terminator 制約を強制
|
||||
///
|
||||
/// # 引数
|
||||
/// - `function`: MIR function
|
||||
/// - `frag`: 配線済み Frag
|
||||
///
|
||||
/// # 戻り値
|
||||
/// - `Ok(())`: 成功
|
||||
/// - `Err(String)`: 同一 block に複数 terminator、または不正な配線
|
||||
pub fn emit_frag(
|
||||
function: &mut crate::mir::MirFunction,
|
||||
frag: &super::frag::Frag,
|
||||
) -> Result<(), String> {
|
||||
use super::branch_stub::BranchStub;
|
||||
|
||||
// Step 0: verify_frag_invariants_strict() で事前検証(SSOT)
|
||||
super::verify::verify_frag_invariants_strict(frag)?;
|
||||
|
||||
// Step 1: branches を from ごとにグループ化(1本だけ許可)
|
||||
let mut branches_by_block: BTreeMap<BasicBlockId, Vec<&BranchStub>> = BTreeMap::new();
|
||||
for branch in &frag.branches {
|
||||
branches_by_block.entry(branch.from).or_default().push(branch);
|
||||
}
|
||||
|
||||
for (block_id, branches) in &branches_by_block {
|
||||
if branches.len() > 1 {
|
||||
return Err(format!(
|
||||
"[emit_frag] Multiple branches from same block {:?} (count={}). \
|
||||
1 block = 1 terminator constraint violated.",
|
||||
block_id,
|
||||
branches.len()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: wires と branches の from 重複チェック(1 block = 1 terminator)
|
||||
for wire in &frag.wires {
|
||||
if branches_by_block.contains_key(&wire.from) {
|
||||
return Err(format!(
|
||||
"[emit_frag] Block {:?} has both wire and branch. \
|
||||
1 block = 1 terminator constraint violated.",
|
||||
wire.from
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: wires を emit(既存の emit_wires を呼ぶ)
|
||||
emit_wires(function, &frag.wires)?;
|
||||
|
||||
// Step 4: branches を emit
|
||||
for branch in &frag.branches {
|
||||
let block = function
|
||||
.get_block_mut(branch.from)
|
||||
.ok_or_else(|| format!("[emit_frag] Block {:?} not found", branch.from))?;
|
||||
|
||||
// Phase 260 API を使用(terminator + successors 同期)
|
||||
block.set_branch_with_edge_args(
|
||||
branch.cond,
|
||||
branch.then_target,
|
||||
Some(branch.then_args.clone()),
|
||||
branch.else_target,
|
||||
Some(branch.else_args.clone()),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -294,5 +368,200 @@ mod tests {
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Phase 267 P0: emit_frag() テスト(3個)
|
||||
// ========================================================================
|
||||
|
||||
#[test]
|
||||
fn test_emit_frag_branch_basic() {
|
||||
use super::super::branch_stub::BranchStub;
|
||||
use super::super::frag::Frag;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
// Setup: MirFunction with 3 blocks (header, then, else)
|
||||
let mut function = create_test_function();
|
||||
let header = BasicBlockId(0);
|
||||
let then_bb = BasicBlockId(1);
|
||||
let else_bb = BasicBlockId(2);
|
||||
function.add_block(BasicBlock::new(then_bb));
|
||||
function.add_block(BasicBlock::new(else_bb));
|
||||
|
||||
// Setup: BranchStub (header → then/else)
|
||||
let branch = BranchStub {
|
||||
from: header,
|
||||
cond: ValueId(100),
|
||||
then_target: then_bb,
|
||||
then_args: EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![ValueId(101)],
|
||||
},
|
||||
else_target: else_bb,
|
||||
else_args: EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![ValueId(102)],
|
||||
},
|
||||
};
|
||||
|
||||
let frag = Frag {
|
||||
entry: header,
|
||||
exits: BTreeMap::new(),
|
||||
wires: vec![],
|
||||
branches: vec![branch],
|
||||
};
|
||||
|
||||
// Execute
|
||||
let result = emit_frag(&mut function, &frag);
|
||||
|
||||
// Verify: success
|
||||
assert!(result.is_ok(), "emit_frag failed: {:?}", result.err());
|
||||
|
||||
// Verify: header has Branch terminator
|
||||
let block = function.get_block(header).unwrap();
|
||||
match &block.terminator {
|
||||
Some(MirInstruction::Branch {
|
||||
condition,
|
||||
then_bb: t,
|
||||
else_bb: e,
|
||||
then_edge_args,
|
||||
else_edge_args,
|
||||
}) => {
|
||||
assert_eq!(*condition, ValueId(100));
|
||||
assert_eq!(*t, then_bb);
|
||||
assert_eq!(*e, else_bb);
|
||||
assert!(then_edge_args.is_some());
|
||||
assert!(else_edge_args.is_some());
|
||||
assert_eq!(
|
||||
then_edge_args.as_ref().unwrap().values,
|
||||
vec![ValueId(101)]
|
||||
);
|
||||
assert_eq!(
|
||||
else_edge_args.as_ref().unwrap().values,
|
||||
vec![ValueId(102)]
|
||||
);
|
||||
}
|
||||
other => panic!("Expected Branch, got {:?}", other),
|
||||
}
|
||||
|
||||
// Verify: successors updated
|
||||
assert!(block.successors.contains(&then_bb));
|
||||
assert!(block.successors.contains(&else_bb));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_emit_frag_branch_wire_conflict_fails() {
|
||||
use super::super::branch_stub::BranchStub;
|
||||
use super::super::frag::Frag;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
// Setup: 同じ block に branch と wire(1 block = 1 terminator 違反)
|
||||
let mut function = create_test_function();
|
||||
let bb0 = BasicBlockId(0);
|
||||
let bb1 = BasicBlockId(1);
|
||||
let bb2 = BasicBlockId(2);
|
||||
function.add_block(BasicBlock::new(bb1));
|
||||
function.add_block(BasicBlock::new(bb2));
|
||||
|
||||
let branch = BranchStub {
|
||||
from: bb0,
|
||||
cond: ValueId(100),
|
||||
then_target: bb1,
|
||||
then_args: EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![],
|
||||
},
|
||||
else_target: bb2,
|
||||
else_args: EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![],
|
||||
},
|
||||
};
|
||||
|
||||
let wire = EdgeStub::with_target(
|
||||
bb0, // 同じ from
|
||||
ExitKind::Normal,
|
||||
bb1,
|
||||
EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![],
|
||||
},
|
||||
);
|
||||
|
||||
let frag = Frag {
|
||||
entry: bb0,
|
||||
exits: BTreeMap::new(),
|
||||
wires: vec![wire],
|
||||
branches: vec![branch],
|
||||
};
|
||||
|
||||
// Execute
|
||||
let result = emit_frag(&mut function, &frag);
|
||||
|
||||
// Verify: failure
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("both wire and branch"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compose_if_creates_branch() {
|
||||
use super::super::compose::if_;
|
||||
use super::super::frag::Frag;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
// Setup: header, then, else, join blocks
|
||||
let header = BasicBlockId(0);
|
||||
let then_entry = BasicBlockId(1);
|
||||
let else_entry = BasicBlockId(2);
|
||||
let join_entry = BasicBlockId(3);
|
||||
|
||||
let then_frag = Frag {
|
||||
entry: then_entry,
|
||||
exits: {
|
||||
let mut exits = BTreeMap::new();
|
||||
exits.insert(
|
||||
ExitKind::Normal,
|
||||
vec![EdgeStub::without_args(then_entry, ExitKind::Normal)],
|
||||
);
|
||||
exits
|
||||
},
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
let else_frag = Frag {
|
||||
entry: else_entry,
|
||||
exits: {
|
||||
let mut exits = BTreeMap::new();
|
||||
exits.insert(
|
||||
ExitKind::Normal,
|
||||
vec![EdgeStub::without_args(else_entry, ExitKind::Normal)],
|
||||
);
|
||||
exits
|
||||
},
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
let join_frag = Frag {
|
||||
entry: join_entry,
|
||||
exits: BTreeMap::new(),
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
let cond = ValueId(100);
|
||||
|
||||
// Execute
|
||||
let result = if_(header, cond, then_frag, else_frag, join_frag);
|
||||
|
||||
// Verify: 1本の BranchStub が生成された
|
||||
assert_eq!(result.branches.len(), 1);
|
||||
|
||||
let branch = &result.branches[0];
|
||||
assert_eq!(branch.from, header);
|
||||
assert_eq!(branch.cond, cond);
|
||||
assert_eq!(branch.then_target, then_entry);
|
||||
assert_eq!(branch.else_target, else_entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,13 +9,15 @@ use std::collections::BTreeMap;
|
||||
use crate::mir::basic_block::BasicBlockId;
|
||||
use super::exit_kind::ExitKind;
|
||||
use super::edge_stub::EdgeStub;
|
||||
use super::branch_stub::BranchStub;
|
||||
|
||||
/// CFG Fragment(構造化制御の合成単位)
|
||||
///
|
||||
/// # 責務(Phase 265 P2 更新)
|
||||
/// # 責務(Phase 267 P0 更新)
|
||||
/// - `entry`: 断片の入口ブロック
|
||||
/// - `exits`: 断片から外へ出る未配線 edge の集合(target = None のみ)
|
||||
/// - `wires`: 断片内部で解決された配線(target = Some(...) のみ)
|
||||
/// - `wires`: 断片内部で解決された配線(target = Some(...) のみ、Jump/Return 専用)
|
||||
/// - `branches`: 断片内部の Branch 配線(Phase 267 P0 追加、Branch 専用)
|
||||
///
|
||||
/// # 設計原則
|
||||
/// - 各 Frag は「入口1つ、出口複数(種別ごと)」を持つ
|
||||
@ -25,7 +27,8 @@ use super::edge_stub::EdgeStub;
|
||||
/// # 不変条件(verify で検証)
|
||||
/// - entry は有効な BasicBlockId
|
||||
/// - exits 内の EdgeStub は target = None(未配線、外へ出る exit)
|
||||
/// - wires 内の EdgeStub は target = Some(...)(配線済み、内部配線)
|
||||
/// - wires 内の EdgeStub は target = Some(...)(配線済み、内部配線、Jump/Return のみ)
|
||||
/// - branches 内の BranchStub は Branch 専用配線(Phase 267 P0)
|
||||
/// - EdgeStub.kind と Map のキーが一致
|
||||
///
|
||||
/// # BTreeMap の使用理由
|
||||
@ -46,7 +49,14 @@ pub struct Frag {
|
||||
///
|
||||
/// target = Some(...) のみ(断片内部で解決された配線)
|
||||
/// Phase 266 で MIR terminator に落とす
|
||||
/// Jump/Return 専用(Branch は branches フィールドへ)
|
||||
pub wires: Vec<EdgeStub>,
|
||||
|
||||
/// 配線済みの分岐(Phase 267 P0 追加)
|
||||
///
|
||||
/// Branch 専用の配線
|
||||
/// wires は Jump/Return 専用のまま維持(分離を保つ)
|
||||
pub branches: Vec<BranchStub>,
|
||||
}
|
||||
|
||||
impl Frag {
|
||||
@ -56,6 +66,7 @@ impl Frag {
|
||||
entry,
|
||||
exits: BTreeMap::new(),
|
||||
wires: vec![], // Phase 265 P2: 配線済み内部配線
|
||||
branches: vec![], // Phase 267 P0: 配線済み分岐
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,6 +78,7 @@ impl Frag {
|
||||
entry,
|
||||
exits,
|
||||
wires: vec![], // Phase 265 P2: 配線済み内部配線
|
||||
branches: vec![], // Phase 267 P0: 配線済み分岐
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,11 +21,13 @@ pub mod frag;
|
||||
pub mod compose;
|
||||
pub mod verify;
|
||||
pub mod emit; // Phase 266: 追加
|
||||
pub mod branch_stub; // Phase 267 P0: 追加
|
||||
|
||||
// 公開型(安定)
|
||||
pub use exit_kind::ExitKind;
|
||||
pub use edge_stub::EdgeStub;
|
||||
pub use frag::Frag;
|
||||
pub use branch_stub::BranchStub; // Phase 267 P0: 追加
|
||||
|
||||
// 合成関数(Phase 264: crate内のみ公開、Phase 265+でpub化)
|
||||
pub(crate) use compose::{seq, if_, loop_, cleanup};
|
||||
@ -34,5 +36,5 @@ pub(crate) use compose::{seq, if_, loop_, cleanup};
|
||||
pub use verify::verify_frag_invariants;
|
||||
pub use verify::verify_frag_invariants_strict; // Phase 266: strict 版追加
|
||||
|
||||
// Phase 266: wires → MIR terminator 変換
|
||||
pub use emit::emit_wires;
|
||||
// Phase 267 P0: wires + branches → MIR terminator 変換
|
||||
pub use emit::{emit_wires, emit_frag};
|
||||
|
||||
@ -163,6 +163,7 @@ mod tests {
|
||||
entry: header,
|
||||
exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// P1: Always returns Ok(())
|
||||
|
||||
Reference in New Issue
Block a user