refactor(mir): Separate KeepAlive/ReleaseStrong instructions (Phase 287)

Phase 287: KeepAlive/ReleaseStrong 命令分離

## 変更内容(2つの側面)

### 1. 命令セマンティクスの分離
- KeepAlive { values, drop_after: bool } を2命令に分離
  - KeepAlive { values }: スコープ終了での生存維持(PURE)
  - ReleaseStrong { values }: 変数上書き時の強参照解放(WRITE)
- 効果分析の明確化: PURE vs WRITE の境界確定

### 2. VM実行サポート
- handlers/mod.rs: KeepAlive → 完全 no-op
- handlers/mod.rs: ReleaseStrong → release_strong_refs() 呼び出し
- handlers/lifecycle.rs: handle_keepalive() 削除

## 影響範囲
- 10 ファイル修正(31箇所の出現を全変換)
- instruction.rs, builder.rs, lexical_scope.rs, methods.rs,
  display.rs, printer_helpers.rs, query.rs, joinir_id_remapper.rs,
  handlers/mod.rs, handlers/lifecycle.rs

## 検証
- 154/154 quick smoke PASS
- weak テスト回帰なし(weak_upgrade_fail, weak_basic)
- rg -n drop_after src → 0 件(完全除去確認)
- MIRダンプで release_strong/keepalive 正常表示

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-26 14:12:58 +09:00
parent f74ff6116c
commit 3bb865c6b0
10 changed files with 60 additions and 43 deletions

View File

@ -146,8 +146,9 @@ impl JoinIrIdRemapper {
Print { value, .. } => vec![*value],
Debug { value, .. } => vec![*value],
DebugLog { values, .. } => values.clone(),
// Phase 285 P2.1: KeepAlive collects all values
KeepAlive { values, .. } => values.clone(),
// Phase 287: Lifecycle management collects all values
KeepAlive { values } => values.clone(),
ReleaseStrong { values } => values.clone(),
Throw { exception, .. } => vec![*exception],
Catch {
exception_value, ..
@ -319,10 +320,12 @@ impl JoinIrIdRemapper {
message: message.clone(),
values: values.iter().map(|&v| remap(v)).collect(),
},
// Phase 285 P2.1: KeepAlive remaps all values
KeepAlive { values, drop_after } => KeepAlive {
// Phase 287: Lifecycle management remaps all values
KeepAlive { values } => KeepAlive {
values: values.iter().map(|&v| remap(v)).collect(),
},
ReleaseStrong { values } => ReleaseStrong {
values: values.iter().map(|&v| remap(v)).collect(),
drop_after: *drop_after,
},
Throw { exception, effects } => Throw {
exception: remap(*exception),

View File

@ -47,8 +47,8 @@ impl super::super::MirBuilder {
.pop_lexical_scope()
.expect("COMPILER BUG: pop_lexical_scope without push_lexical_scope");
// Phase 285 P2.1: Emit KeepAlive for all declared variables in this scope
// This keeps strong refs alive until scope end (language scope semantics)
// Phase 287: Emit KeepAlive for all declared variables in this scope
// This keeps values alive until scope end for PHI node inputs (liveness analysis)
// ⚠️ Termination guard: don't emit after return/throw
if !self.is_current_block_terminated() {
let keepalive_values: Vec<crate::mir::ValueId> = frame
@ -60,7 +60,6 @@ impl super::super::MirBuilder {
if !keepalive_values.is_empty() {
let _ = self.emit_instruction(crate::mir::MirInstruction::KeepAlive {
values: keepalive_values,
drop_after: false, // Scope-end: don't drop, values may be needed for PHI
});
}
}