feat(joinir): Phase 57 - OwnershipAnalyzer implementation (dev-only)
AST/ProgramJSON から OwnershipPlan を生成する解析箱を実装。 Key changes: - New analyzer.rs (632 lines): - OwnershipAnalyzer: Main analysis engine - ScopeKind: Function/Loop/Block/If scope types - ScopeInfo: Internal scope representation with reads/writes tracking Algorithm: 1. Build scope tree (Function/Loop/Block/If hierarchy) 2. Collect reads/writes/condition_reads per scope 3. Apply body-local ownership rule (if/block locals → enclosing Loop/Function) 4. Generate OwnershipPlan: owned_vars, relay_writes, captures, condition_captures Core invariants enforced: - Ownership Uniqueness: Each variable has exactly one owner - Carrier Locality: carriers = writes ∩ owned - Relay Propagation: writes to ancestor-owned → relay up - Capture Read-Only: captures have no PHI at this scope Tests: 7 ownership unit tests + 946 existing (0 regressions) - test_simple_loop_ownership: relay writes to function - test_loop_local_carrier: owned AND written = carrier - test_capture_read_only: read-only captures - test_nested_loop_relay: relay chains through nested loops Design: "読むのは自由、管理は直下だけ" Phase 57 is dev-only - not yet connected to lowering. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
176
docs/development/current/main/PHASE_57_SUMMARY.md
Normal file
176
docs/development/current/main/PHASE_57_SUMMARY.md
Normal file
@ -0,0 +1,176 @@
|
||||
# Phase 57: OWNERSHIP-ANALYZER-DEV - Summary
|
||||
|
||||
## Status: ✅ COMPLETED
|
||||
|
||||
**Date**: 2025-12-12
|
||||
**Duration**: Single session implementation
|
||||
**Test Results**: All 946 tests passing (56 ignored)
|
||||
|
||||
## What Was Implemented
|
||||
|
||||
### 1. Naming SSOT Fix
|
||||
- Unified naming: `owned_vars` (code) vs `owned_carriers` (docs)
|
||||
- Decision: Keep `owned_vars` in code (more general - includes read-only owned)
|
||||
- Updated all documentation to use `owned_vars` consistently
|
||||
|
||||
### 2. Core Analyzer Implementation
|
||||
Created `/home/tomoaki/git/hakorune-selfhost/src/mir/join_ir/ownership/analyzer.rs`:
|
||||
- **OwnershipAnalyzer**: Main analysis engine (420+ lines)
|
||||
- **ScopeKind**: Function/Loop/Block/If scope types
|
||||
- **ScopeInfo**: Internal scope representation with defined/reads/writes/condition_reads
|
||||
|
||||
### 3. Analysis Algorithm
|
||||
|
||||
#### Scope Tree Construction
|
||||
- Function/Loop/Block/If each get unique ScopeId
|
||||
- Parent-child relationships tracked via scope hierarchy
|
||||
- Body-local ownership rule: `local` in if/block → enclosing Loop/Function owns it
|
||||
|
||||
#### Variable Collection (per scope)
|
||||
- `defined`: Variables declared with `local` in this scope
|
||||
- `reads`: All variable reads (including nested scopes)
|
||||
- `writes`: All variable writes (including nested scopes)
|
||||
- `condition_reads`: Variables read in loop/if conditions
|
||||
|
||||
#### Ownership Assignment
|
||||
- `owned_vars` = variables defined in Loop/Function scopes
|
||||
- Carriers = `owned_vars.filter(is_written == true)`
|
||||
- Read-only owned variables are NOT carriers
|
||||
|
||||
#### Plan Generation
|
||||
- `relay_writes` = writes - owned (find owner in ancestors)
|
||||
- `captures` = reads - owned - writes (read-only captures)
|
||||
- `condition_captures` = captures ∩ condition_reads
|
||||
|
||||
### 4. Key Implementation Decisions
|
||||
|
||||
#### Smart Propagation
|
||||
Fixed issue where parent scopes were trying to relay variables owned by child Loop/Function scopes:
|
||||
```rust
|
||||
// Only propagate writes that are NOT locally owned by Loop/Function children
|
||||
if child_kind == ScopeKind::Loop || child_kind == ScopeKind::Function {
|
||||
// Don't propagate writes for variables defined in this Loop/Function
|
||||
for write in writes {
|
||||
if !child_defined.contains(&write) {
|
||||
parent.writes.insert(write);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For If/Block, propagate all writes
|
||||
parent.writes.extend(writes);
|
||||
}
|
||||
```
|
||||
|
||||
#### Relay Path Construction
|
||||
- Walk up ancestor chain to find owner
|
||||
- Collect only Loop scopes in relay_path (skip If/Block)
|
||||
- Inner loop → Outer loop → Function (relay chain)
|
||||
|
||||
#### Invariant Verification (debug builds only)
|
||||
- No variable appears in multiple categories (owned/relay/capture)
|
||||
- All relay_writes have valid owners
|
||||
- condition_captures ⊆ captures
|
||||
|
||||
### 5. Comprehensive Test Suite
|
||||
Implemented 4 test cases covering all major scenarios:
|
||||
|
||||
1. **test_simple_loop_ownership**: Basic loop with relay writes to function
|
||||
2. **test_loop_local_carrier**: Loop-local variable (owned AND written)
|
||||
3. **test_capture_read_only**: Read-only capture in loop condition
|
||||
4. **test_nested_loop_relay**: Nested loops with relay chain
|
||||
|
||||
All tests pass ✅
|
||||
|
||||
### 6. Documentation Updates
|
||||
- Updated `phase56-ownership-relay-design.md` with Phase 57 algorithm section
|
||||
- Updated `mod.rs` to reflect Phase 57 completion status
|
||||
- Clear separation: analyzer = dev-only, not connected to lowering yet
|
||||
|
||||
## Architecture Highlights
|
||||
|
||||
### Responsibility Boundary
|
||||
**This module does**:
|
||||
- ✅ Collect reads/writes from AST/ProgramJSON
|
||||
- ✅ Determine variable ownership (owned/relay/capture)
|
||||
- ✅ Produce OwnershipPlan for downstream lowering
|
||||
|
||||
**This module does NOT**:
|
||||
- ❌ Generate MIR instructions
|
||||
- ❌ Modify JoinIR structures
|
||||
- ❌ Perform lowering transformations
|
||||
|
||||
### Core Invariants Enforced
|
||||
1. **Ownership Uniqueness**: Each variable has exactly one owner scope
|
||||
2. **Carrier Locality**: carriers = writes ∩ owned
|
||||
3. **Relay Propagation**: writes to ancestor-owned → relay up
|
||||
4. **Capture Read-Only**: captures have no PHI at this scope
|
||||
|
||||
## Files Changed
|
||||
|
||||
### New Files
|
||||
- `/home/tomoaki/git/hakorune-selfhost/src/mir/join_ir/ownership/analyzer.rs` (420+ lines)
|
||||
|
||||
### Modified Files
|
||||
- `/home/tomoaki/git/hakorune-selfhost/src/mir/join_ir/ownership/mod.rs` (export analyzer)
|
||||
- `/home/tomoaki/git/hakorune-selfhost/docs/development/current/main/phase56-ownership-relay-design.md` (algorithm section)
|
||||
|
||||
## Test Results
|
||||
|
||||
```
|
||||
running 7 tests
|
||||
test mir::join_ir::ownership::analyzer::tests::test_capture_read_only ... ok
|
||||
test mir::join_ir::ownership::types::tests::test_carriers_filter ... ok
|
||||
test mir::join_ir::ownership::analyzer::tests::test_nested_loop_relay ... ok
|
||||
test mir::join_ir::ownership::types::tests::test_invariant_verification ... ok
|
||||
test mir::join_ir::ownership::analyzer::tests::test_loop_local_carrier ... ok
|
||||
test mir::join_ir::ownership::analyzer::tests::test_simple_loop_ownership ... ok
|
||||
test mir::join_ir::ownership::types::tests::test_empty_plan ... ok
|
||||
|
||||
test result: ok. 7 passed; 0 failed; 0 ignored
|
||||
```
|
||||
|
||||
Full test suite: **946 tests passed, 0 failed, 56 ignored** ✅
|
||||
|
||||
## Next Steps (Phase 58+)
|
||||
|
||||
### Phase 58: P2 Plumbing (dev-only)
|
||||
- Connect analyzer to Pattern 2 lowering
|
||||
- Generate PHI instructions based on OwnershipPlan
|
||||
- Test with P2 loops
|
||||
|
||||
### Phase 59: P3 Plumbing (dev-only)
|
||||
- Connect analyzer to Pattern 3 lowering
|
||||
- Handle relay chains in nested loops
|
||||
- Test with P3 loops
|
||||
|
||||
### Phase 60: Cleanup Dev Heuristics
|
||||
- Remove old carrier detection logic
|
||||
- Switch to OwnershipPlan throughout
|
||||
|
||||
### Phase 61: Canonical Promotion Decision
|
||||
- Finalize promotion strategy
|
||||
- Production rollout
|
||||
|
||||
## Design Philosophy
|
||||
|
||||
### "読むのは自由、管理は直下だけ" (Read Freely, Manage Directly)
|
||||
- Variables can be READ from anywhere (capture)
|
||||
- Variables can only be WRITTEN by their owner or via relay
|
||||
- Ownership is determined by definition scope (body-local rule)
|
||||
- No shadowing complexity - clear ownership hierarchy
|
||||
|
||||
### Dev-First Approach
|
||||
- Implemented as pure analysis module first
|
||||
- Not yet connected to lowering (no behavioral changes)
|
||||
- Can be tested independently with JSON input
|
||||
- Safe to merge without affecting existing code paths
|
||||
|
||||
## References
|
||||
- **Phase 56 Design**: [phase56-ownership-relay-design.md](phase56-ownership-relay-design.md)
|
||||
- **JoinIR Architecture**: [joinir-architecture-overview.md](joinir-architecture-overview.md)
|
||||
- **Phase 43/245B**: Normalized JoinIR completion
|
||||
- **ChatGPT Discussion**: 「読むのは自由、管理は直下だけ」設計
|
||||
|
||||
---
|
||||
|
||||
**Implementation Status**: ✅ Phase 57 Complete - Ready for Phase 58 plumbing
|
||||
@ -108,7 +108,7 @@ loop outer {
|
||||
|
||||
| Current | New |
|
||||
|---------|-----|
|
||||
| CarrierInfo.carriers | OwnershipPlan.owned_carriers |
|
||||
| CarrierInfo.carriers | OwnershipPlan.owned_vars (where is_written=true) |
|
||||
| promoted_loopbodylocals | (absorbed into owned analysis) |
|
||||
| CapturedEnv | OwnershipPlan.captures |
|
||||
| ConditionEnv | OwnershipPlan.condition_captures |
|
||||
@ -119,7 +119,7 @@ loop outer {
|
||||
```rust
|
||||
pub struct OwnershipPlan {
|
||||
pub scope_id: ScopeId,
|
||||
pub owned_carriers: Vec<ScopeOwnedVar>,
|
||||
pub owned_vars: Vec<ScopeOwnedVar>, // All owned vars (carriers = is_written subset)
|
||||
pub relay_writes: Vec<RelayVar>,
|
||||
pub captures: Vec<CapturedVar>,
|
||||
pub condition_captures: Vec<CapturedVar>,
|
||||
@ -127,7 +127,7 @@ pub struct OwnershipPlan {
|
||||
```
|
||||
|
||||
**設計意図**:
|
||||
- `owned_carriers`: このスコープが所有 AND 更新する変数
|
||||
- `owned_vars`: このスコープが所有する変数(更新されるものは carriers)
|
||||
- `relay_writes`: 祖先の変数への書き込み(owner へ昇格)
|
||||
- `captures`: 祖先の変数への読み取り専用参照
|
||||
- `condition_captures`: captures のうち、条件式で使われるもの
|
||||
@ -169,7 +169,7 @@ loop {
|
||||
```
|
||||
|
||||
**OwnershipPlan (loop scope)**:
|
||||
- `owned_carriers`: [`sum` (written)]
|
||||
- `owned_vars`: [`sum` (is_written=true)]
|
||||
- `relay_writes`: []
|
||||
- `captures`: []
|
||||
|
||||
@ -185,12 +185,12 @@ loop outer {
|
||||
```
|
||||
|
||||
**OwnershipPlan (inner loop)**:
|
||||
- `owned_carriers`: []
|
||||
- `owned_vars`: []
|
||||
- `relay_writes`: [`total` → relay to outer]
|
||||
- `captures`: []
|
||||
|
||||
**OwnershipPlan (outer loop)**:
|
||||
- `owned_carriers`: [`total` (written via relay)]
|
||||
- `owned_vars`: [`total` (is_written=true, via relay)]
|
||||
- `relay_writes`: []
|
||||
- `captures`: []
|
||||
|
||||
@ -207,7 +207,7 @@ loop {
|
||||
```
|
||||
|
||||
**OwnershipPlan (loop scope)**:
|
||||
- `owned_carriers`: [`sum` (written)]
|
||||
- `owned_vars`: [`sum` (is_written=true)]
|
||||
- `relay_writes`: []
|
||||
- `captures`: [`limit` (read-only)]
|
||||
- `condition_captures`: [`limit`]
|
||||
@ -218,7 +218,54 @@ loop {
|
||||
- **ChatGPT discussion**: 「読むのは自由、管理は直下だけ」設計
|
||||
- **JoinIR Architecture**: [joinir-architecture-overview.md](joinir-architecture-overview.md)
|
||||
|
||||
## Phase 57: Algorithm Implementation
|
||||
|
||||
### Analysis Steps
|
||||
|
||||
1. **Scope Tree Construction**
|
||||
- Function/Loop/Block/If each get a ScopeId
|
||||
- Parent-child relationships tracked
|
||||
|
||||
2. **Variable Collection (per scope)**
|
||||
- `defined`: Variables declared with `local` in this scope
|
||||
- `reads`: All variable reads (including nested)
|
||||
- `writes`: All variable writes (including nested)
|
||||
- `condition_reads`: Variables read in loop/if conditions
|
||||
|
||||
3. **Ownership Assignment**
|
||||
- Body-local rule: `local` in if/block → enclosing Loop/Function owns it
|
||||
- `owned_vars` = variables defined in Loop/Function scopes
|
||||
|
||||
4. **Plan Generation**
|
||||
- `carriers` = owned_vars where is_written=true
|
||||
- `relay_writes` = writes - owned (find owner in ancestors)
|
||||
- `captures` = reads - owned - writes (read-only)
|
||||
- `condition_captures` = captures ∩ condition_reads
|
||||
|
||||
### Implementation Details
|
||||
|
||||
**Body-Local Ownership Rule**:
|
||||
```rust
|
||||
// Example: local in if/block → enclosing loop owns it
|
||||
loop {
|
||||
if cond {
|
||||
local temp = 0 // owned by LOOP, not if!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Relay Path Construction**:
|
||||
- Walk up ancestor chain to find owner
|
||||
- Collect only Loop scopes in relay_path (skip If/Block)
|
||||
- Inner loop → Outer loop → Function (relay chain)
|
||||
|
||||
**Invariant Verification** (debug builds):
|
||||
- No variable in multiple categories (owned/relay/capture)
|
||||
- All relay_writes have valid owners
|
||||
- condition_captures ⊆ captures
|
||||
|
||||
## Status
|
||||
|
||||
- ✅ Phase 56 (this): Design + interface skeleton completed
|
||||
- ⏳ Phase 57+: Implementation pending
|
||||
- ✅ Phase 56: Design + interface skeleton completed
|
||||
- ✅ Phase 57: Analyzer implemented (dev-only, not connected to lowering yet)
|
||||
- ⏳ Phase 58+: Plumbing integration pending
|
||||
|
||||
Reference in New Issue
Block a user