feat(mir): Phase 285 P2.1 - KeepAlive instruction for weak ref semantics

Add KeepAlive instruction to fix hidden root problem where x = null
doesn't properly drop the strong reference.

Key changes:
- Add KeepAlive { values, drop_after } instruction to MIR
- Emit KeepAlive[drop=true] in build_assignment() before variable overwrite
- Emit KeepAlive[drop=false] in pop_lexical_scope() at scope end
- VM handler: when drop_after=true, remove ALL ValueIds pointing to
  the same Arc (handles SSA Copy chains)

Test results:
- weak_upgrade_fail: exit 1  (weak_to_strong returns null after x=null)
- weak_basic: exit 2  (weak_to_strong succeeds while x alive)
- quick smoke: 154/154 PASS 

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-26 13:08:32 +09:00
parent 58ceb3de2f
commit 3bf0dee2b0
12 changed files with 165 additions and 19 deletions

View File

@ -146,6 +146,8 @@ 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(),
Throw { exception, .. } => vec![*exception],
Catch {
exception_value, ..
@ -317,6 +319,11 @@ 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 {
values: values.iter().map(|&v| remap(v)).collect(),
drop_after: *drop_after,
},
Throw { exception, effects } => Throw {
exception: remap(*exception),
effects: *effects,