Skip to content

P-022 step 4: port own-analysis (worklist solver + ownership/lifetime/effect/DI) with layered diagnostic parity #214

Description

@PhysShell

Agent brief — tier: strong. One PR (Closes #<this>); branch from main. House rules: AGENTS.md.

Goal

Step 4 of the P-022 strangler-fig migration, next after the merged own-cfg (#197/#203): the analysis heart. Port the generic worklist solver and the four analyses (ownership → then lifetime → effect → DI) to rust/crates/own-analysis, plus the minimal own-diagnostics types crate it constructs into. Python stays the reference; a divergence is a Rust bug until separately proven otherwise.

Sources of truth

  • docs/proposals/P-022-rust-core-migration.md — crate DAG (the load-bearing edges: own-analysis → own-diagnostics; own-diagnostics depends ONLY on the own-ir span leaf, never the parser or the solver), the idioms table (bitset lattice over {OWNED,MOVED,RELEASED,ESCAPED}, dense Vec by RID, RPO worklist scheduling, exhaustive match), and the migration order in §strategy step 4: diff diagnostics (line, code) first → then evidence → then SARIF, layer by layer.
  • ownlang/analysis.py, ownlang/ownership.py, ownlang/lifetimes.py, ownlang/effects.py, ownlang/di.py, ownlang/buffers.py — the reference implementations.
  • spec/Inference.md (MOS S/R/F/A/M-rules) and spec/OwnCore.md, spec/Diagnostics.md — normative behaviour.
  • The feat: P-022 step 3 — port own-cfg (AST → CFG lowering) with exact CFG-JSON parity #203 parity pattern: tests/test_cfg_fixtures.py + tests/fixtures/cfg_parity.json + own-cfg/tests/parity.rs — extend the same fixture-freezing approach to the diagnostics layer (Python emits the golden (path, line, code) sets over corpus/ + examples/ + tests/fixtures/ + curated cases; Rust replays and must match exactly, incl. intra-tie ordering).

Deliverable

  • rust/crates/own-diagnostics (Diagnostic/Evidence data types only — presentation/SARIF is step 5, out of scope).
  • rust/crates/own-analysis: Lattice/Analysis traits + one generic worklist solver + the four analyses as independent impls (the de-noodling of Python's interleaved _Analyzer).
  • A frozen diagnostics-parity fixture + Rust parity test, wired into tests/run_tests.py and the rust CI job, following feat: P-022 step 3 — port own-cfg (AST → CFG lowering) with exact CFG-JSON parity #203's ratchet conventions (regenerate on Python-core or corpus change, steady state runs zero Python).

Guardrails

  • No behaviour changes; exact parity on (line, code) per input — evidence-slice and SARIF parity are later steps, do not fake them now.
  • Cargo edge test (cargo metadata) asserting the allowed DAG edges from P-022 §fitness (diagnostics never depends on analysis; codegen untouched).
  • Workspace lints stand (unsafe_code = "forbid", the pre-resolved indexing_slicing allowance for arena/newtype access only).
  • Correctness first: no perf micro-опт before parity is green; the P-022 perf doctrine (bitset, RPO, FxHashMap) is the starting shape, not an optimization pass.
  • If a Python behaviour looks like a bug mid-port — do NOT fix it in Rust; note it in the PR and keep parity (a deliberate divergence is a separate, Python-first change).

Done when

Full-corpus diagnostics parity green in CI (rust job + the new fixture check in run_tests.py), cargo fmt/clippy/test clean, DAG edge test in place, Python side untouched except the parity-fixture generator.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions