phase29ak(p2): gate pattern8 facts by static box ctx
This commit is contained in:
@ -30,6 +30,9 @@ PlanRuleOrder を SSOT 化し、PlannerContext を配線(未使用)。single
|
||||
**2025-12-29: Phase 29ak P1 COMPLETE (Pattern1 facts guard via planner)**
|
||||
Pattern1 以外のループで pattern1_simplewhile facts 抽出を抑制。single_planner 側の guard は安全策として維持。
|
||||
|
||||
**2025-12-29: Phase 29ak P2 COMPLETE (Pattern8 static box filter via planner)**
|
||||
static box では Pattern8 facts 抽出を抑制。single_planner 側の filter は安全策として維持。
|
||||
|
||||
**2025-12-29: Phase 29aj P10 COMPLETE (single_planner unified shape)**
|
||||
single_planner を全パターンで planner-first → extractor フォールバックの共通形に統一(挙動不変)。
|
||||
|
||||
|
||||
@ -2,10 +2,15 @@
|
||||
|
||||
## Current Focus: Phase 29ak(PlanRuleOrder + PlannerContext)
|
||||
|
||||
Next: Phase 29ak P2(TBD)
|
||||
Next: Phase 29ak P3(TBD)
|
||||
運用ルール: integration filter で phase143_* は回さない(JoinIR 回帰は phase29ae pack のみ)
|
||||
運用ルール: phase286_pattern9_* は legacy pack (SKIP) を使う
|
||||
|
||||
**2025-12-29: Phase 29ak P2 完了** ✅
|
||||
- 目的: Pattern8 static box filter を planner 側へ移し、facts 抽出を抑制(仕様不変)
|
||||
- 実装: `src/mir/builder/control_flow/plan/facts/loop_facts.rs`
|
||||
- 検証: `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh` PASS
|
||||
|
||||
**2025-12-29: Phase 29ak P1 完了** ✅
|
||||
- 目的: Pattern1 guard を planner 側へ移して facts 抽出を抑制(仕様不変)
|
||||
- 実装: `src/mir/builder/control_flow/plan/facts/loop_facts.rs` / `src/mir/builder/control_flow/plan/planner/outcome.rs`
|
||||
|
||||
@ -26,8 +26,8 @@ Related:
|
||||
|
||||
- **Phase 29ak(candidate): PlanRuleOrder SSOT + PlannerContext plumbing**
|
||||
- 入口: `docs/development/current/main/phases/phase-29ak/README.md`
|
||||
- 状況: P0/P1 ✅ 完了
|
||||
- Next: Phase 29ak P2(TBD)
|
||||
- 状況: P0/P1/P2 ✅ 完了
|
||||
- Next: Phase 29ak P3(TBD)
|
||||
|
||||
- **Phase 29ai(candidate): Plan/Frag single-planner(Facts SSOT)**
|
||||
- 入口: `docs/development/current/main/phases/phase-29ai/README.md`
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
# Phase 29ak P2: Gate Pattern8 facts by static box ctx
|
||||
|
||||
Date: 2025-12-29
|
||||
Status: Ready for execution
|
||||
Scope: PlannerContext.in_static_box を使って Pattern8 facts を抑制(挙動・ログ不変)
|
||||
Goal: single_planner の特例フィルタ責務を planner 側へ移す
|
||||
|
||||
## Objective
|
||||
|
||||
- in_static_box == true のとき Pattern8 facts 抽出を行わない
|
||||
- single_planner 側の static box reject 分岐は安全策として残す
|
||||
- ログ差分は出さない(planner 側は無言で Ok(None))
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Pattern8 static box reject 分岐の削除
|
||||
- CandidateSet への順序移管
|
||||
- 新 env var 追加
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Step 1: facts 入口で Pattern8 を抑制
|
||||
|
||||
Update:
|
||||
- `src/mir/builder/control_flow/plan/facts/loop_facts.rs`
|
||||
|
||||
Notes:
|
||||
- `try_build_loop_facts_with_ctx` で `ctx.in_static_box` を参照し、Pattern8 抽出関数を呼ばない
|
||||
|
||||
### Step 2: planner outcome 側は ctx 版を継続使用
|
||||
|
||||
Update:
|
||||
- `src/mir/builder/control_flow/plan/planner/outcome.rs`
|
||||
|
||||
### Step 3: unit test 追加(facts)
|
||||
|
||||
- in_static_box=true で Pattern8 facts が None になることを固定
|
||||
|
||||
### Step 4: docs / CURRENT_TASK 更新
|
||||
|
||||
Update:
|
||||
- `docs/development/current/main/phases/phase-29ak/README.md`
|
||||
- `docs/development/current/main/10-Now.md`
|
||||
- `docs/development/current/main/30-Backlog.md`
|
||||
- `CURRENT_TASK.md`
|
||||
|
||||
## Verification
|
||||
|
||||
- `cargo build --release`
|
||||
- `./tools/smokes/v2/run.sh --profile quick`
|
||||
- `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
|
||||
|
||||
## Commit
|
||||
|
||||
- `git add -A && git commit -m "phase29ak(p2): gate pattern8 facts by static box ctx"`
|
||||
@ -15,3 +15,10 @@ Goal: single_planner の「順序・名前・ガード」の SSOT を 1 箇所
|
||||
- ねらい: pattern_kind が Pattern1 以外のとき pattern1 facts 抽出を行わない
|
||||
- 完了: PlannerContext を参照して loop_facts 入口で Pattern1 を抑制(single_planner 側の guard は維持)
|
||||
- 検証: `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
|
||||
|
||||
## P2: Pattern8 static box filter を planner 側へ移動
|
||||
|
||||
- 指示書: `docs/development/current/main/phases/phase-29ak/P2-PLANNER-PATTERN8-STATIC-BOX-FILTER-INSTRUCTIONS.md`
|
||||
- ねらい: static box では Pattern8 facts 抽出を抑制(single_planner 側の filter は維持)
|
||||
- 完了: PlannerContext.in_static_box を参照して loop_facts 入口で Pattern8 を抑制
|
||||
- 検証: `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
|
||||
|
||||
@ -74,7 +74,7 @@ pub(in crate::mir::builder) fn try_build_loop_facts(
|
||||
condition: &ASTNode,
|
||||
body: &[ASTNode],
|
||||
) -> Result<Option<LoopFacts>, Freeze> {
|
||||
try_build_loop_facts_inner(condition, body, true)
|
||||
try_build_loop_facts_inner(condition, body, true, true)
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) fn try_build_loop_facts_with_ctx(
|
||||
@ -87,13 +87,15 @@ pub(in crate::mir::builder) fn try_build_loop_facts_with_ctx(
|
||||
Some(_) => false,
|
||||
None => true,
|
||||
};
|
||||
try_build_loop_facts_inner(condition, body, allow_pattern1)
|
||||
let allow_pattern8 = !ctx.in_static_box;
|
||||
try_build_loop_facts_inner(condition, body, allow_pattern1, allow_pattern8)
|
||||
}
|
||||
|
||||
fn try_build_loop_facts_inner(
|
||||
condition: &ASTNode,
|
||||
body: &[ASTNode],
|
||||
allow_pattern1: bool,
|
||||
allow_pattern8: bool,
|
||||
) -> Result<Option<LoopFacts>, Freeze> {
|
||||
// Phase 29ai P4/P7: keep Facts conservative; only return Some when we can
|
||||
// build a concrete pattern fact set (no guesses / no hardcoded names).
|
||||
@ -112,12 +114,16 @@ fn try_build_loop_facts_inner(
|
||||
let pattern4_continue = try_extract_pattern4_continue_facts(condition, body)?;
|
||||
let pattern5_infinite_early_exit =
|
||||
try_extract_pattern5_infinite_early_exit_facts(condition, body)?;
|
||||
let pattern8_bool_predicate_scan = try_extract_pattern8_bool_predicate_scan_facts(
|
||||
condition,
|
||||
body,
|
||||
&condition_shape,
|
||||
&step_shape,
|
||||
)?;
|
||||
let pattern8_bool_predicate_scan = if allow_pattern8 {
|
||||
try_extract_pattern8_bool_predicate_scan_facts(
|
||||
condition,
|
||||
body,
|
||||
&condition_shape,
|
||||
&step_shape,
|
||||
)?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let pattern9_accum_const_loop = try_extract_pattern9_accum_const_loop_facts(condition, body)?;
|
||||
let pattern2_break = try_extract_pattern2_break_facts(condition, body)?;
|
||||
let pattern2_loopbodylocal = try_extract_pattern2_loopbodylocal_facts(condition, body)?;
|
||||
@ -808,6 +814,96 @@ mod tests {
|
||||
assert!(facts.pattern1_simplewhile.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loopfacts_ctx_blocks_pattern8_in_static_box() {
|
||||
let condition = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(ASTNode::MethodCall {
|
||||
object: Box::new(v("s")),
|
||||
method: "length".to_string(),
|
||||
arguments: vec![],
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let predicate_if = ASTNode::If {
|
||||
condition: Box::new(ASTNode::UnaryOp {
|
||||
operator: crate::ast::UnaryOperator::Not,
|
||||
operand: Box::new(ASTNode::MethodCall {
|
||||
object: Box::new(ASTNode::Me {
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
method: "is_digit".to_string(),
|
||||
arguments: vec![ASTNode::MethodCall {
|
||||
object: Box::new(v("s")),
|
||||
method: "substring".to_string(),
|
||||
arguments: vec![
|
||||
v("i"),
|
||||
ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(1),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
],
|
||||
span: Span::unknown(),
|
||||
}],
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
then_body: vec![ASTNode::Return {
|
||||
value: Some(Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Bool(false),
|
||||
span: Span::unknown(),
|
||||
})),
|
||||
span: Span::unknown(),
|
||||
}],
|
||||
else_body: None,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let step = ASTNode::Assignment {
|
||||
target: Box::new(v("i")),
|
||||
value: Box::new(ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(1),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let body = vec![predicate_if, step];
|
||||
let allow_ctx = PlannerContext {
|
||||
pattern_kind: None,
|
||||
in_static_box: false,
|
||||
debug: false,
|
||||
};
|
||||
let block_ctx = PlannerContext {
|
||||
pattern_kind: None,
|
||||
in_static_box: true,
|
||||
debug: false,
|
||||
};
|
||||
|
||||
let allow = try_build_loop_facts_with_ctx(&allow_ctx, &condition, &body).expect("Ok");
|
||||
assert!(allow
|
||||
.as_ref()
|
||||
.and_then(|facts| facts.pattern8_bool_predicate_scan.as_ref())
|
||||
.is_some());
|
||||
|
||||
let blocked = try_build_loop_facts_with_ctx(&block_ctx, &condition, &body).expect("Ok");
|
||||
assert!(blocked
|
||||
.as_ref()
|
||||
.and_then(|facts| facts.pattern8_bool_predicate_scan.as_ref())
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loopfacts_ok_none_when_condition_not_supported() {
|
||||
let condition = v("i"); // not `i < n`
|
||||
|
||||
Reference in New Issue
Block a user