diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 200a4ff7..a2af56b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3279,6 +3279,60 @@ jobs: fi echo "OK: Tier B A/B — external event OWN050 (no ref) -> OWN001 (with --ref-dir)" + # P-010 pillar 9, first slice: C# state protocols over OwnIR v1 (`move`, + # `borrow_mut`). The Layer 2/3 ledgers freeze the FACTS the Roslyn lowering emits, + # and both engines replay them with zero dotnet — which proves the engines agree + # on those documents and nothing about where the documents came from. This job is + # the other half: the real extractor over the real C#, so a frozen fact cannot + # drift away from the program it claims to describe. + # + # It also carries what no frozen fact can: programs the extractor must REFUSE + # (code with no contract inside a region, a protocol with a public mutator, a + # token made by hand in the protocol's own assembly), programs the C# compiler + # must reject, and an ASP.NET Core + EF Core backend driven over real HTTP against + # a real SQLite file — the transition has to reach the instance EF tracks and the + # row it saves, not merely type-check. + # + # Both platforms: the fixtures carry repo-relative `file` paths, and a path that + # is only right with one separator is the kind of thing a single runner hides. + state-protocols: + name: state protocols (C# -> OwnIR v1, real ASP.NET Core + EF Core backend) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: "3.13" + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + with: + dotnet-version: "8.0.x" + - uses: dtolnay/rust-toolchain@fa04a1451ff1842e2626ccb99004d0195b455a88 # master, 2026-07-10 + with: + toolchain: stable + - name: Build own-cli (the second public engine) + if: matrix.os == 'ubuntu-latest' + working-directory: rust + run: cargo build -p own-cli + # One script, five questions; see its docstring. + - name: The protocol gate (cases, refusals, compiler rejections, one assembly, EF backend) + if: matrix.os != 'ubuntu-latest' + run: python scripts/protocol_gate.py + # On Linux it also compares the two PUBLIC CLIs on every C#-derived document: + # exit code, stdout and stderr, byte for byte. Linux only, for the reason + # #261 recorded: byte parity with the NATIVE-Windows Python reference is not + # claimed (it writes cp1252/CRLF), so that comparison would measure the + # console, not the engines. + - name: The protocol gate + both public CLIs on the C#-derived documents + if: matrix.os == 'ubuntu-latest' + run: python scripts/protocol_gate.py --rust "$PWD/rust/target/debug/own-cli" + # P-012 slice 1: score the checker against the labeled corpus on REAL C# — not # just the .own reduction tests/test_corpus.py checks. Per case: the bug must be # CAUGHT in before.cs (recall) and the fix must be SILENT in after.cs diff --git a/audit/static/run_static.py b/audit/static/run_static.py index 2a63eff6..b884675c 100755 --- a/audit/static/run_static.py +++ b/audit/static/run_static.py @@ -363,7 +363,7 @@ def check(ok: bool, msg: str) -> None: # total derives from the call count def _fake_own_check(target_, out_dir_, severity_, root=None): facts = Path(out_dir_) / "own-check.facts.json" - facts.write_text(json.dumps({"ownir_version": 0, "module": "App", "components": [ + facts.write_text(json.dumps({"ownir_version": 1, "module": "App", "components": [ {"name": "CustomerView", "file": "Views/CustomerView.xaml.cs", "subscriptions": [ {"event": "_bus.Changed", "handler": "OnChanged", "line": 21, "released": False}]}]}), encoding="utf-8") @@ -419,7 +419,7 @@ def _fake_own_check(target_, out_dir_, severity_, root=None): ' x:Class="App.Views.CustomerView" Loaded="OnLoaded" />\n', encoding="utf-8") (out5 / "own-check.facts.json").write_text(json.dumps({ - "ownir_version": 0, "module": "Stale", "components": [ + "ownir_version": 1, "module": "Stale", "components": [ {"name": "CustomerView", "file": "Views/CustomerView.xaml.cs", "subscriptions": [{"event": "_bus.Changed", "handler": "OnChanged", "line": 21, "released": False}]}]}), encoding="utf-8") diff --git a/audit/static/tools/xaml_join.py b/audit/static/tools/xaml_join.py index 98a36edf..82e91691 100644 --- a/audit/static/tools/xaml_join.py +++ b/audit/static/tools/xaml_join.py @@ -303,7 +303,7 @@ def check(ok: bool, msg: str) -> None: "event_handlers": [{"event": "Loaded", "handler": "OnLoaded", "line": 4}], "bindings": [], "named_elements": []}, ]} - ownir = {"ownir_version": 0, "module": "App", "components": [ + ownir = {"ownir_version": 1, "module": "App", "components": [ {"name": "CustomerView", "file": "Views/CustomerView.xaml.cs", "subscriptions": [ {"event": "_bus.Changed", "handler": "OnChanged", "line": 21, "released": False}]}, {"name": "CleanView", "file": "Views/CleanView.xaml.cs", "subscriptions": [ @@ -363,7 +363,7 @@ def check(ok: bool, msg: str) -> None: wrong_ns = {"documents": [{"file": "Features/Billing/CustomerView.xaml", "x_class": "Billing.CustomerView", "event_handlers": [{"event": "Loaded", "handler": "OnLoaded", "line": 4}]}]} - other = {"ownir_version": 0, "components": [ + other = {"ownir_version": 1, "components": [ {"name": "CustomerView", "file": "Legacy/CustomerView.cs", "subscriptions": [ {"event": "_bus.Changed", "handler": "OnChanged", "line": 9, "released": False}]}]} check(join(wrong_ns, other) == [], diff --git a/corpus/ownership-lab/h29/door/neg-family.facts.json b/corpus/ownership-lab/h29/door/neg-family.facts.json index f3c2d757..e99d2710 100644 --- a/corpus/ownership-lab/h29/door/neg-family.facts.json +++ b/corpus/ownership-lab/h29/door/neg-family.facts.json @@ -1 +1 @@ -{"ownir_version": 0, "module": "M", "orphaned_awaitables": [{"local": "tx", "callee": "T.M/0", "file": "Q.cs", "line": 1, "family": "C_whatever"}]} \ No newline at end of file +{"ownir_version": 1, "module": "M", "orphaned_awaitables": [{"local": "tx", "callee": "T.M/0", "file": "Q.cs", "line": 1, "family": "C_whatever"}]} \ No newline at end of file diff --git a/corpus/ownership-lab/h29/door/neg-garbage.facts.json b/corpus/ownership-lab/h29/door/neg-garbage.facts.json index b7c3c126..79979fc8 100644 --- a/corpus/ownership-lab/h29/door/neg-garbage.facts.json +++ b/corpus/ownership-lab/h29/door/neg-garbage.facts.json @@ -1 +1 @@ -{"ownir_version": 0, "module": "M", "orphaned_awaitables": [{"local": ["what", "is", "this"], "callee": {"oops": 1}, "file": "Q.cs", "line": 119, "result_type": 12345}]} \ No newline at end of file +{"ownir_version": 1, "module": "M", "orphaned_awaitables": [{"local": ["what", "is", "this"], "callee": {"oops": 1}, "file": "Q.cs", "line": 119, "result_type": 12345}]} \ No newline at end of file diff --git a/corpus/ownership-lab/h29/door/neg-line_above.facts.json b/corpus/ownership-lab/h29/door/neg-line_above.facts.json index 7c09e789..83b21518 100644 --- a/corpus/ownership-lab/h29/door/neg-line_above.facts.json +++ b/corpus/ownership-lab/h29/door/neg-line_above.facts.json @@ -1 +1 @@ -{"ownir_version": 0, "module": "M", "orphaned_awaitables": [{"local": "tx", "callee": "T.M/0", "file": "Q.cs", "line": 2147483648}]} \ No newline at end of file +{"ownir_version": 1, "module": "M", "orphaned_awaitables": [{"local": "tx", "callee": "T.M/0", "file": "Q.cs", "line": 2147483648}]} \ No newline at end of file diff --git a/corpus/ownership-lab/h29/promotion/promo-u.facts.json b/corpus/ownership-lab/h29/promotion/promo-u.facts.json index 7b90eb3a..228b0411 100644 --- a/corpus/ownership-lab/h29/promotion/promo-u.facts.json +++ b/corpus/ownership-lab/h29/promotion/promo-u.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "components": [], "services": [], diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 8b6599fd..7913a2a6 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -318,7 +318,7 @@ own scan. Label them as estimates wherever they appear. | [P-007](proposals/P-007-arraypool-span.md) | ArrayPool / Span borrow-view | P1 | in progress (POOL001–003 built; 004/005 first slices) | | [P-008](proposals/P-008-effects-and-resources.md) | Effects & resources (`Own.Effects`) | P1/P2 | draft | | [P-009](proposals/P-009-nogc-regions.md) | No-GC / allocation-free regions | horizon | draft | -| [P-010](proposals/P-010-type-disciplines.md) | Richer type disciplines (`Own.Types`) | P2/horizon | draft | +| [P-010](proposals/P-010-type-disciplines.md) | Richer type disciplines (`Own.Types`) | P2/horizon | draft; pillar 9 first slice built | | [P-011](proposals/P-011-editor-tooling.md) | Editor tooling & syntax highlighting | side-track | draft | | [P-012](proposals/P-012-bug-corpus-mining.md) | Real-world bug corpus & mining | enabling | in progress (corpus benchmark + real-world cases, CI-gated) | | [P-013](proposals/P-013-distribution-surface.md) | Distribution surface (CI Action + dotnet tool) | enabling | v0 built | diff --git a/docs/evidence/calibration/p022-263a-design-constants.json b/docs/evidence/calibration/p022-263a-design-constants.json index fa02f43b..0ff316d5 100644 --- a/docs/evidence/calibration/p022-263a-design-constants.json +++ b/docs/evidence/calibration/p022-263a-design-constants.json @@ -1,6 +1,6 @@ { "artifact": "p022-263a-calibration-design-constants", - "bound_measurement_harness_digest": "104c384d01bf6060bdec1e7c916053ddb04b97fcbd0b39f8a4fc57b8f139672f", + "bound_measurement_harness_digest": "1a26aa63fd5fbbe06e7ae72dd5e1c8f2d611bff8856af4a5b93ae36d2d23a9b1", "bound_policy_implementation_digest": "c3068ed7fa880a7083866ead25fe8bf65c87889d242d8af1f7eee01582cd5cbf", "constants": { "G": [ diff --git a/docs/evidence/calibration/p022-263a-policy-freeze.json b/docs/evidence/calibration/p022-263a-policy-freeze.json index e206cdf8..f3445962 100644 --- a/docs/evidence/calibration/p022-263a-policy-freeze.json +++ b/docs/evidence/calibration/p022-263a-policy-freeze.json @@ -1,6 +1,6 @@ { "artifact": "p022-263a-calibration-policy-freeze", - "measurement_harness_digest": "104c384d01bf6060bdec1e7c916053ddb04b97fcbd0b39f8a4fc57b8f139672f", + "measurement_harness_digest": "1a26aa63fd5fbbe06e7ae72dd5e1c8f2d611bff8856af4a5b93ae36d2d23a9b1", "policy_implementation_digest": "c3068ed7fa880a7083866ead25fe8bf65c87889d242d8af1f7eee01582cd5cbf", "policy_implementation_digest_framing": "sha256 over the source set ordered by the UTF-8 bytes of each repo-relative POSIX path. Each file contributes, with no header and no separator: its path byte length as an 8-byte big-endian unsigned integer, its path's exact UTF-8 bytes, its blob byte length as an 8-byte big-endian unsigned integer, and its exact git blob bytes.", "policy_source_commit": "b4f657a0abdfdfaae199cbc7eee0c47acd8b0057", diff --git a/docs/evidence/calibration/p022-263a-training-preregistration.json b/docs/evidence/calibration/p022-263a-training-preregistration.json index a03e85a5..c2b23f61 100644 --- a/docs/evidence/calibration/p022-263a-training-preregistration.json +++ b/docs/evidence/calibration/p022-263a-training-preregistration.json @@ -30,8 +30,8 @@ "anchor_commit": "eedf6d3ed44ecf7bda69fa509dcd23b45960cf76", "artifact": "p022-263a-calibration-training-preregistration", "bindings": { - "design_constants_blob_sha1": "fa02f43bdf795e2f47d8ce781ec3a84f1dee64b5", - "measurement_harness_digest": "104c384d01bf6060bdec1e7c916053ddb04b97fcbd0b39f8a4fc57b8f139672f", + "design_constants_blob_sha1": "0ff316d5aea6af92c01679babaf0f0251191dcee", + "measurement_harness_digest": "1a26aa63fd5fbbe06e7ae72dd5e1c8f2d611bff8856af4a5b93ae36d2d23a9b1", "policy_implementation_digest": "c3068ed7fa880a7083866ead25fe8bf65c87889d242d8af1f7eee01582cd5cbf", "training_scope_implementation_digest": "614bf9efe6ba2bb10e26a251c10d6c4a8fdaa99985d43ea03d76c6774447d25b", "training_scope_root": "scripts/training/" diff --git a/docs/generated/p022-coord-census.md b/docs/generated/p022-coord-census.md index e23313d7..bc8459e7 100644 --- a/docs/generated/p022-coord-census.md +++ b/docs/generated/p022-coord-census.md @@ -10,8 +10,8 @@ Value classes follow the cp1 taxonomy's axis rather than blurring it: `outside-i | measure | value | |------------------------------------|------:| -| JSON files scanned | 440 | -| coordinate slots found | 2267 | +| JSON files scanned | 588 | +| coordinate slots found | 4013 | ## By value class @@ -21,12 +21,12 @@ Value classes follow the cp1 taxonomy's axis rather than blurring it: `outside-i | `below-1` | 23 | 23 | | `bool` | 17 | 17 | | `float` | 3 | 3 | -| `in-domain` | 1799 | 998 | +| `in-domain` | 3319 | 2193 | | `negative` | 26 | 26 | -| `null` | 231 | 9 | +| `null` | 259 | 9 | | `outside-int64` | 15 | 15 | | `string` | 19 | 19 | -| `zero` | 110 | 26 | +| `zero` | 308 | 26 | ## By family and slot @@ -157,10 +157,11 @@ Value classes follow the cp1 taxonomy's axis rather than blurring it: `outside-i | `cli_ownir/inputs` | `components[].subscriptions[].line` | `in-domain` | yes | 3 | 3 | — | | `cli_ownir/inputs/pa th ünïcødé` | `components[].subscriptions[].line` | `in-domain` | yes | 1 | 1 | — | | `lowered` | `components[].subscriptions[].line` | `in-domain` | yes | 24 | 10 | — | -| `lowered` | `functions[].[].line` | `in-domain` | yes | 150 | 41 | — | -| `lowered` | `functions[].params[].line` | `in-domain` | yes | 20 | 10 | — | +| `lowered` | `functions[].[].column` | `in-domain` | yes | 2 | 2 | — | +| `lowered` | `functions[].[].line` | `in-domain` | yes | 903 | 112 | — | +| `lowered` | `functions[].params[].line` | `in-domain` | yes | 460 | 79 | — | | `lowered` | `functions[].params[].line` | `zero` | yes | 4 | 3 | — | -| `lowered` | `handles[].line` | `in-domain` | — | 48 | 22 | — | +| `lowered` | `handles[].line` | `in-domain` | — | 343 | 56 | — | | `lowered` | `services[].line` | `in-domain` | yes | 2 | 1 | — | | `ownir` | `components[].subscriptions[].column` | `in-domain` | yes | 2 | 1 | — | | `ownir` | `components[].subscriptions[].line` | `in-domain` | yes | 20 | 10 | — | @@ -196,7 +197,7 @@ Value classes follow the cp1 taxonomy's axis rather than blurring it: `outside-i | `repro` | `traces[].layers[].steps[].value.params[].line` | `in-domain` | — | 4 | 1 | — | | `summaries` | `functions[].[].line` | `in-domain` | yes | 37 | 9 | — | | `summaries` | `functions[].params[].line` | `in-domain` | yes | 25 | 8 | — | -| `summaries` | `summaries[].line` | `zero` | — | 54 | 26 | — | +| `summaries` | `summaries[].line` | `zero` | — | 252 | 63 | — | | `verdict_renders` | `components[].subscriptions[].column` | `in-domain` | yes | 1 | 1 | — | | `verdict_renders` | `components[].subscriptions[].line` | `in-domain` | yes | 11 | 5 | — | | `verdict_renders` | `functions[].[].line` | `in-domain` | yes | 3 | 2 | — | @@ -214,9 +215,9 @@ Value classes follow the cp1 taxonomy's axis rather than blurring it: `outside-i | `verdicts` | `effects[].line` | `in-domain` | yes | 9 | 5 | — | | `verdicts` | `effects[].line` | `negative` | yes | 1 | 1 | `-3` | | `verdicts` | `effects[].line` | `zero` | yes | 1 | 1 | — | -| `verdicts` | `findings[].column` | `in-domain` | — | 16 | 6 | — | -| `verdicts` | `findings[].column` | `null` | — | 170 | 75 | — | -| `verdicts` | `findings[].line` | `in-domain` | — | 171 | 70 | — | +| `verdicts` | `findings[].column` | `in-domain` | — | 17 | 7 | — | +| `verdicts` | `findings[].column` | `null` | — | 198 | 93 | — | +| `verdicts` | `findings[].line` | `in-domain` | — | 200 | 89 | — | | `verdicts` | `findings[].line` | `zero` | — | 15 | 12 | — | | `verdicts` | `functions[].[].column` | `below-1` | yes | 1 | 1 | `0` | | `verdicts` | `functions[].[].column` | `in-domain` | yes | 7 | 2 | — | diff --git a/docs/generated/p022-cp4-census.md b/docs/generated/p022-cp4-census.md index b3f6a2ef..84c7650a 100644 --- a/docs/generated/p022-cp4-census.md +++ b/docs/generated/p022-cp4-census.md @@ -8,18 +8,18 @@ Computed by `tests/verdict_census.py` and `tests/verdict_render_census.py` (the | measure | value | |-------------------------------------------------------------------------|------:| -| goldens — Python's complete truth, one per planned case | 96 | +| goldens — Python's complete truth, one per planned case | 133 | | … swept from `tests/fixtures/ownir` | 22 | -| … swept from `tests/fixtures/lowered` | 27 | +| … swept from `tests/fixtures/lowered` | 64 | | … swept from `tests/fixtures/summaries` | 9 | | … synthetic controls (`manifest.json` cases) | 38 | -| reference refusals over all goldens | 5 | -| reference findings over all goldens | 186 | +| reference refusals over all goldens | 9 | +| reference findings over all goldens | 215 | | declared Rust exclusions — the executable ledger `rust_replay_excluded` | 2 | | … refused at the typed `OwnIr` door (#294 OD-1) | 2 | -| replayed by Rust (goldens minus exclusions) | 94 | -| … reference refusals among them (compared in full) | 5 | -| … findings among them (compared on every `Finding` member) | 184 | +| replayed by Rust (goldens minus exclusions) | 131 | +| … reference refusals among them (compared in full) | 9 | +| … findings among them (compared on every `Finding` member) | 213 | The differential counts over the replayed set — Python-only, Rust-only, changed, ordering-only, unexplained — are asserted, not measured here: the Rust replay compares every replayed case's full ordered verdict list (or its refusal text) against the golden on every member, collects every divergence without fail-fast, and fails if one exists. A green `cargo test -p own-bridge --test verdicts` is 0 / 0 / 0 / 0 / 0 by construction; a non-zero count is a red build. diff --git a/docs/generated/p022-cp5-inventory.md b/docs/generated/p022-cp5-inventory.md index e59a24e4..d33b498c 100644 --- a/docs/generated/p022-cp5-inventory.md +++ b/docs/generated/p022-cp5-inventory.md @@ -12,17 +12,29 @@ Checkpoint 4 proved identity, anchor, kind and tiering over the replayed set ([c | ledger row | surface | what it is | all goldens | replayed | |---|---|---|---:|---:| -| `flowlocal_own001_never` | bridge | flow-local OWN001, never released | 27 | 27 | +| `flowlocal_own001_never` | bridge | flow-local OWN001, never released | 30 | 30 | | `flowlocal_own001_partial` | bridge | flow-local OWN001, released on some path | 10 | 10 | | `flowlocal_own001_pool_partial` | bridge | flow-local OWN001 on a pooled buffer, returned on some path | 2 | 2 | -| `flowlocal_own002` | bridge | flow-local use-after-dispose | 6 | 6 | +| `flowlocal_own002` | bridge | flow-local use-after-dispose | 8 | 8 | | `flowlocal_own003` | bridge | flow-local double dispose | 1 | 1 | -| `flowlocal_own009` | bridge | flow-local maybe-use-after-dispose | 1 | 1 | +| `flowlocal_own009` | bridge | flow-local maybe-use-after-dispose | 2 | 2 | | `flowlocal_own002_pool` | bridge | flow-local use-after-return | 1 | 1 | | `flowlocal_own003_pool` | bridge | flow-local double return | 1 | 1 | | `flowlocal_own009_pool` | bridge | flow-local maybe-use-after-return | 1 | 1 | -| `flowlocal_fallback` | core-diagnostic | flow-local fallback: the core message, verbatim — **not replayed**: unreachable from any facts document (the nine-op flow vocabulary raises only codes that HAVE a wording); pinned by a `verdict::tests` control driven through `map_core`, whose expected text is read from the recorded probe `tests/fixtures/unreachable_branches.json`. The core message it interpolates is checkpoint 5.2's | 0 | 0 | -| `flowlocal_fallback_pool` | core-diagnostic | flow-local pooled fallback: the core message, verbatim — **not replayed**: unreachable from any facts document (the nine-op flow vocabulary raises only codes that HAVE a wording); pinned by a `verdict::tests` control driven through `map_core`, whose expected text is read from the recorded probe `tests/fixtures/unreachable_branches.json`. The core message it interpolates is checkpoint 5.2's | 0 | 0 | +| `flowlocal_own005` | bridge | flow-local use after move | 3 | 3 | +| `flowlocal_own007` | bridge | flow-local consume/return while borrowed | 2 | 2 | +| `flowlocal_own008` | bridge | flow-local release while borrowed | 1 | 1 | +| `flowlocal_own011` | bridge | flow-local exclusive re-borrow | 4 | 4 | +| `flowlocal_own012` | bridge | flow-local shared borrow under an exclusive one | 2 | 2 | +| `flowlocal_own013` | bridge | flow-local direct use under an exclusive borrow | 5 | 5 | +| `flowlocal_own005_pool` | bridge | flow-local use after move on a pooled buffer | 1 | 1 | +| `flowlocal_own007_pool` | bridge | flow-local consume/return while borrowed on a pooled buffer | 1 | 1 | +| `flowlocal_own008_pool` | bridge | flow-local release while borrowed on a pooled buffer | 1 | 1 | +| `flowlocal_own011_pool` | bridge | flow-local exclusive re-borrow on a pooled buffer | 1 | 1 | +| `flowlocal_own012_pool` | bridge | flow-local shared borrow under an exclusive one on a pooled buffer | 1 | 1 | +| `flowlocal_own013_pool` | bridge | flow-local direct use under an exclusive borrow on a pooled buffer | 1 | 1 | +| `flowlocal_fallback` | core-diagnostic | flow-local fallback: the core message, verbatim — **not replayed**: unreachable from any facts document (the eleven-op flow vocabulary raises only codes that HAVE a wording); pinned by a `verdict::tests` control driven through `map_core`, whose expected text is read from the recorded probe `tests/fixtures/unreachable_branches.json`. The core message it interpolates is checkpoint 5.2's | 0 | 0 | +| `flowlocal_fallback_pool` | core-diagnostic | flow-local pooled fallback: the core message, verbatim — **not replayed**: unreachable from any facts document (the eleven-op flow vocabulary raises only codes that HAVE a wording); pinned by a `verdict::tests` control driven through `map_core`, whose expected text is read from the recorded probe `tests/fixtures/unreachable_branches.json`. The core message it interpolates is checkpoint 5.2's | 0 | 0 | | `own025_view` | bridge | OWN025 pooled-view wording | 2 | 2 | | `own014_di_singleton` | bridge | OWN014 captive, source registered singleton | 6 | 6 | | `own014_di_scoped` | bridge | OWN014 captive, source registered scoped | 1 | 1 | @@ -89,9 +101,9 @@ One row per `related`/`flow` family; a slice matching no family (or two) fails t | `di005_registration_related` | related | DI005 registration beside the store site | 4 | 4 | | `capture_escape_flow` | flow | OWN014 subscribe site → source registration site | 5 | 5 | | `effect_flow` | flow | EFF001 re-run site → identity-mint site | 5 | 4 | -| `flowlocal_flow_own002` | flow | flow-local OWN002 origin → violation | 4 | 4 | +| `flowlocal_flow_own002` | flow | flow-local OWN002 origin → violation | 6 | 6 | | `flowlocal_flow_own003` | flow | flow-local OWN003 origin → violation | 1 | 1 | -| `flowlocal_flow_own009` | flow | flow-local OWN009 origin → violation | 1 | 1 | +| `flowlocal_flow_own009` | flow | flow-local OWN009 origin → violation | 2 | 2 | | `flowlocal_flow_own002_pool` | flow | flow-local OWN002 origin → violation (pooled) | 1 | 1 | | `flowlocal_flow_own003_pool` | flow | flow-local OWN003 origin → violation (pooled) | 1 | 1 | | `flowlocal_flow_own009_pool` | flow | flow-local OWN009 origin → violation (pooled) | 1 | 1 | @@ -114,7 +126,7 @@ The rules that produce an EMPTY slice: a step whose line is unknown is omitted, | `capture_escape_flow_dropped` | flow | DI-sourced OWN014 with no escape slice (source registration unknown → < 2 steps) | 3 | 3 | | `capture_flow_absent` | flow | OWN014 from the capture route: no escape slice by design (only the DI-sourced branch builds one) | 6 | 6 | | `effect_flow_dropped` | flow | EFF001 with no slice (a re-run or mint line < 1) | 3 | 3 | -| `flowlocal_flow_absent` | flow | OWN001 on a local/pooled record: a single-point finding, no slice by design | 45 | 45 | +| `flowlocal_flow_absent` | flow | OWN001 on a local/pooled record: a single-point finding, no slice by design | 48 | 48 | | `protocol_flow_absent` | flow | an OBL finding with no slice at all: the anchorless OBL005 by design, and a leak whose only step has an unknown line | 4 | 4 | ## BR-V9 — rendered surfaces diff --git a/docs/generated/p022-shadow-census.md b/docs/generated/p022-shadow-census.md index 1f007f08..a13b64ef 100644 --- a/docs/generated/p022-shadow-census.md +++ b/docs/generated/p022-shadow-census.md @@ -24,12 +24,12 @@ acceptance work. | corpus | documents | |---|---| -| `tests/fixtures/lowered` | 27 | +| `tests/fixtures/lowered` | 64 | | `tests/fixtures/ownir` | 22 | | `tests/fixtures/repro` | 3 | | `tests/fixtures/summaries` | 9 | | `tests/fixtures/verdicts` | 38 | -| **total** | **99** | +| **total** | **136** | Every one of those documents is canonicalized and hashed by the reference (`ownlang/repro.py`) and re-hashed from the same file by the port @@ -43,8 +43,8 @@ refuses to carry a foreign entry that has none rather than filling one in. | surface | count | |---|---| -| documents captured and digest-pinned | 99 | -| tamper controls (one changed character per document, refusal required) | 99 | +| documents captured and digest-pinned | 136 | +| tamper controls (one changed character per document, refusal required) | 136 | | documents both engines must REFUSE to name (`domain_refusals`) | 6 | | reproduction artifacts committed and replayed byte-for-byte | 10 | | structural negative controls on `verify` (each side) | 34 | diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index 174c1ac6..9b79fbe8 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -28,6 +28,12 @@ Status: Amendments after this line are a new state of the contract, never an edit of this one. This commit is not to be amended, rebased or force-pushed. + + AMENDMENT 1 (2026-10-01) is such a state — see "Amendments" at the end: + the accepted harness identity moved 104c384d01bf -> 1a26aa63fd5f when the + instrument's generated facts moved to OwnIR v1, and steps 4, 5 and 6 were + re-bound to it. The freeze and the authorisation above are unchanged, and so + is every rule, budget, population and predicate below. ``` **What this is.** The contract that fixes *how numbers will be judged*, before any @@ -164,9 +170,13 @@ Doing so edits `scripts/perf_baseline.py`, which is one of the two files in the harness source set, so it moves the harness identity measurement_harness_digest - 104c384d01bf6060bdec1e7c916053ddb04b97fcbd0b39f8a4fc57b8f139672f + 1a26aa63fd5fbbe06e7ae72dd5e1c8f2d611bff8856af4a5b93ae36d2d23a9b1 -to which steps 4, 5 and 6 were **re-bound** after the S8 memory-semantics repair. +to which steps 4, 5 and 6 are bound. The identity has moved twice, each time by +a recorded act and never as a side effect: steps 4, 5 and 6 were **re-bound** +after the S8 memory-semantics repair (`562a7f7232da` → `104c384d01bf`), and +re-bound again by Amendment 1, when the instrument's generated facts moved to +OwnIR v1 (`104c384d01bf` → `1a26aa63fd5f`). Moving it again is a new instrument and a re-evaluation of accepted instrumentation evidence, not a T0 detail. @@ -1240,3 +1250,79 @@ outcome. T0_CONTENT_COMPLETE_READY_FOR_FREEZE_REVIEW status: NOT_FROZEN — collection_authorized: false + +--- + +## Amendments + +Each entry is a **new state of the contract**. The state it replaces is not +edited: the freeze commit stays an ancestor of every later state, and what it +said is what it said. An amendment names exactly what moved and what did not. + +### Amendment 1 — the harness identity follows OwnIR v1 (2026-10-01) + +```text +Status after this amendment: + FROZEN, collection_authorized: true unchanged + accepted harness identity 104c384d01bf -> 1a26aa63fd5f + rules, budgets, populations, statistic, + roll-ups, host predicate, retry budget unchanged, every one of them +``` + +**The owner's ruling.** OwnIR's flow vocabulary gained `move` and the compound +`borrow_mut`, which is an incompatible vocabulary change, so `OWNIR_VERSION` +moved 0 → 1 ([OwnIR.md §2, §5.3](../../spec/OwnIR.md)). The instrument generates +its `facts` calibration workloads itself and stamps the version on each, so an +instrument left on v0 writes documents both engines refuse at the door: every +`facts` rung would be a cell that times the version gate. The owner ruled that +the instrument is repaired and officially re-bound on the S8 precedent, and +ruled out a compatibility shim on either side — a v1 core that also accepts v0, +or an instrument arranged so that the re-binding could be skipped. + +**What changed in the instrument.** One literal in the `facts` generator of +`scripts/perf_baseline.py`: `"ownir_version": 0` became `"ownir_version": 1`. +Nothing else in the harness source set moved: the workload manifest, the rung +ladder, the clock, the memory accounting, the identity gate and +`HARNESS_VERSION` are byte-for-byte what they were. + + harness identity before 104c384d01bf6060bdec1e7c916053ddb04b97fcbd0b39f8a4fc57b8f139672f + harness identity after 1a26aa63fd5fbbe06e7ae72dd5e1c8f2d611bff8856af4a5b93ae36d2d23a9b1 + +**What was re-bound**, in the order the chain runs: the policy freeze (step 4), +the ratified design constants (step 5), and the training preregistration's +bindings (step 6) — and with the last, `design_constants_blob_sha1` +(`fa02f43bdf79` → `0ff316d5aea6`), which moved because the design-constants +artifact itself was re-bound. T0-1 above names the new identity; the merge gate +reads it there and recomputes it from the instrument sources of the tree being +merged. + +**What was not touched.** The committed evidence of runs that actually +happened. The sizing, calibration and Round-7 datasets were produced by earlier +instruments and record what those produced; rewriting them would be forging a +record, not re-accepting a binding. No T0-governed clock has run under any +identity, so there is no training or decisive observation for this amendment to +re-evaluate, keep or discard. + +**The re-evaluation T0-1 says a moved identity owes.** The instrumentation +controls were re-run on the amended tree, and all hold: perf instrument 17/17, +Round 7 apparatus 10/10, calibration policy 10/10, calibration freeze 7/7, +calibration constants 4/4, training preregistration 9/9, step 7 environment +capture 12/12, host qualification 26/26, merge gate 15/15, merge gate wiring +12/12. Four of them named the move before the re-binding, each for its own +reason — `freeze-harness-untouched`, `constants-bound-to-freeze`, +`training-prereg-bindings`, `envcapture-frozen-untouched` — which is the +provenance system delivering its inconvenience on purpose. + +One control is new, because none of the existing ones could see the defect that +made this amendment necessary: with the core on v1 and the generator still on +v0, every control was green. `perf-calibration-facts-current` runs the reference +on what the generator writes and requires the `facts` workloads to be analysed +and the `refused` workload to be refused — the two generators on opposite sides +of the door. It lives in the control suite, outside the harness source set, so +adding it moves no identity. + +**What this amendment does not do.** It authorises nothing new: host +qualification, an exact execution binding, the campaign link and the session +preflight are still required, and each may still refuse. It changes no number a +verdict is computed from. And it is not a precedent for moving the identity as a +side effect: the next move is a new amendment or it is a defect. diff --git a/docs/notes/p022-263a-instrument.md b/docs/notes/p022-263a-instrument.md index bb066805..627dd2fd 100644 --- a/docs/notes/p022-263a-instrument.md +++ b/docs/notes/p022-263a-instrument.md @@ -266,6 +266,16 @@ commit; the committed evidence of runs that already happened was **not** rewritt and still carries the old field name, because it records what the old instrument produced. +The identity moved a second time, from `104c384d01bf` to `1a26aa63fd5f`, when +OwnIR's vocabulary moved to v1: the `facts` generator stamps `ownir_version` on +every document it writes, and a generator left on v0 would have handed both +engines a document they refuse at the door. One literal changed, steps 4, 5 and 6 +were re-bound again, and the frozen T0 records it as its Amendment 1 +([the T0 contract](p022-263-t0-protocol-freeze.md)). The control that would have +caught it is `perf-calibration-facts-current`: it runs the reference on the +generator's output and requires the `facts` workloads to be analysed and the +`refused` one to be refused. + On POSIX the same `wait4` call also carries the child's CPU split, fault counts and context-switch counts. Those are now kept rather than discarded — see *The interval kept its meaning and gave up its secrets* — under the same rule: off diff --git a/docs/proposals/P-010-type-disciplines.md b/docs/proposals/P-010-type-disciplines.md index 10222da3..6143e377 100644 --- a/docs/proposals/P-010-type-disciplines.md +++ b/docs/proposals/P-010-type-disciplines.md @@ -1,6 +1,8 @@ # P-010 — Richer type disciplines (`Own.Types`) -- **Status:** draft (horizon) +- **Status:** draft (horizon); pillar 9 (typestate / protocols) has a first slice built — + the C# state-protocol profile over OwnIR v1 (`move`, `borrow_mut`), see + [the extractor's README](../../frontend/roslyn/README.md#state-protocols---flow-locals-ownir-v1) - **Depends on:** `spec/OwnCore.md` (the ownership/affine core and its fact vocabulary), `spec/Lifetimes.md`; relates to P-005 (`IDisposable` typestate — the first concrete protocol), P-006 (DI lifetimes — a region contract, not a @@ -173,6 +175,20 @@ directly, rather than making every call site spell out a bespoke `union`. Typestate is also the generalization that subsumes **session types** (typed message-ordering protocols) as the special case where the object is a channel. + **First slice, built.** Not the `protocol` declaration above but its C# + surface: a state is a `[ProtocolToken]` ref struct over an ordinary entity, a + `[ProtocolRegion]` method opens an exclusive region and hands out the token, + and a transition is a method on the token. The Roslyn frontend lowers a + region to `borrow_mut` and a token copy to `move` (OwnIR v1, + [`spec/OwnIR.md` §5.3](../../spec/OwnIR.md)); the existing ownership core + gives the verdicts — a stale token is OWN002, a copied one OWN005, a raw + touch of the entity inside the region OWN013 — on both engines. It works on + the instance an ORM tracks, with no base class, repository or custom LINQ + (`frontend/roslyn/protocol-samples/efcore`). What the slice does **not** have: a declared + state graph (the transitions are whatever the tokens' methods are), a + generator for the tokens, the affine view of a token (an unspent one is + OWN001 today), and any claim over writes that bypass the entity's C# surface. + 10. **Owned / borrowed / must-dispose.** Already built as a standalone diagnostic in [P-005](P-005-idisposable-ownership.md) — Own.NET already treats `IDisposable` as typestate C# lacks. This pillar's job is *not* to diff --git a/docs/proposals/README.md b/docs/proposals/README.md index d1381252..e7d6fbe0 100644 --- a/docs/proposals/README.md +++ b/docs/proposals/README.md @@ -31,7 +31,7 @@ proposal is marked `done` with a pointer. | [P-007](P-007-arraypool-span.md) | ArrayPool / Span borrow-view | in progress (POOL001–003 built; 004/005 first slices) | | [P-008](P-008-effects-and-resources.md) | Effects & resources (`Own.Effects`) | draft | | [P-009](P-009-nogc-regions.md) | No-GC / allocation-free regions | draft | -| [P-010](P-010-type-disciplines.md) | Richer type disciplines (`Own.Types`) | draft | +| [P-010](P-010-type-disciplines.md) | Richer type disciplines (`Own.Types`) | draft; pillar 9 first slice built (C# state protocols over OwnIR v1) | | [P-011](P-011-editor-tooling.md) | Editor tooling & syntax highlighting | draft | | [P-012](P-012-bug-corpus-mining.md) | Real-world bug corpus & mining | in progress (corpus benchmark + real-world cases, CI-gated) | | [P-013](P-013-distribution-surface.md) | Distribution surface (how people run Own.NET) | v0 built (CI/Action + dotnet tool) | diff --git a/frontend/ownts/ownts.py b/frontend/ownts/ownts.py index a93a92cd..06ee6b70 100644 --- a/frontend/ownts/ownts.py +++ b/frontend/ownts/ownts.py @@ -577,7 +577,7 @@ def extract(path: str) -> list[Component]: def to_ownir(comps: list[Component], module: str, effects: list[dict] | None = None) -> dict: facts = { - "ownir_version": 0, + "ownir_version": 1, "module": module, "components": [ { diff --git a/frontend/roslyn/OwnSharp.Extractor/Program.cs b/frontend/roslyn/OwnSharp.Extractor/Program.cs index 4d75cd46..10e5074d 100644 --- a/frontend/roslyn/OwnSharp.Extractor/Program.cs +++ b/frontend/roslyn/OwnSharp.Extractor/Program.cs @@ -5672,6 +5672,11 @@ static bool IsPublicCtor(SyntaxTokenList modifiers) var components = new List(); // P-016 B0b/B2: per-method flow bodies (only when --flow-locals). var flowFunctions = new List(); +// The names the IDisposable flow pass emitted a record for. The protocol lowering +// (ProtocolLowering.cs) reads it so that a method with BOTH readings keeps both under +// distinct names: the two are not merged, and two records under one name would read +// as an overload. +var flowRecordNames = new HashSet(StringComparer.Ordinal); // Parse every input into a syntax tree first (keeping the file path we report // it under), then build ONE compilation over all of them so the SemanticModel @@ -7221,6 +7226,7 @@ or ImplicitObjectCreationExpressionSyntax } init if (guardedFacts is not null) record["guarded_facts"] = guardedFacts; flowFunctions.Add(record); + flowRecordNames.Add(fname); } if (subs.Count > 0) @@ -7251,6 +7257,22 @@ or ImplicitObjectCreationExpressionSyntax } init // `stats` is additive coverage metadata — the core's load() ignores unknown keys. // P-006: the DI registration + ctor graph (empty when the scan has no // Add{Singleton,Scoped,Transient} calls). ownlang/di.py turns it into DI001. +// P-010 pillar 9: state-protocol regions -> `borrow_mut` / `move` flow records (OwnIR v1). A +// lowering, not an analysis (see ProtocolLowering.cs). A shape it cannot lower is a +// REFUSAL of the whole run (exit 2, the same tier as the guarded-fact self-check below): +// the alternative is a region that silently drops out of the facts and reads as clean. +if (flowLocals) +{ + var protocol = ProtocolLowering.Lower(compilation, parsed, flowRecordNames); + if (protocol.Refusals.Count > 0) + { + foreach (var refusal in protocol.Refusals) + Console.Error.WriteLine($"extractor: protocol lowering refused: {refusal}"); + return 2; + } + flowFunctions.AddRange(protocol.Functions); +} + var factServices = ExtractServices(parsed); var factStats = new { @@ -7259,13 +7281,16 @@ or ImplicitObjectCreationExpressionSyntax } init methods_skipped_unmodelled = statMethodsSkipped, }; // `fix_candidates_version` is a top-level ADDITIVE metadata field, present ONLY under -// --fix-candidates; `ownir_version` stays 0 (the fact-schema vocabulary is unchanged — -// no new resource-kind or analysis-routing value). Without the flag the object is -// byte-for-byte the pre-S0 shape. +// --fix-candidates; it does not move `ownir_version` (the fact-schema vocabulary is +// unchanged — no new resource-kind or analysis-routing value). Without the flag the +// object is byte-for-byte the pre-S0 shape. +// +// Every envelope below stamps the SAME `ownir_version`, the core's current one +// (ownlang/ownir.py OWNIR_VERSION; tests/test_ownir.py reads every stamp in this file). object facts = emitFixCandidates ? new { - ownir_version = 0, + ownir_version = 1, fix_candidates_version = 1, module = "Extracted", components, @@ -7275,11 +7300,11 @@ or ImplicitObjectCreationExpressionSyntax } init } // OWN053 (promoted from ownership-semantics-lab H-29): an ADDITIVE top-level list of orphaned awaitables from which // both engines mint the advisory; absent when there is no site, so such a document stays byte-identical to the - // pre-OWN053 shape (and `ownir_version` stays 0: the field is additive, like `fix_candidates_version`). + // pre-OWN053 shape (and `ownir_version` does not move: the field is additive, like `fix_candidates_version`). : OrphanedAwaitables.Sites.Count > 0 ? new { - ownir_version = 0, + ownir_version = 1, module = "Extracted", components, services = factServices, @@ -7289,7 +7314,7 @@ or ImplicitObjectCreationExpressionSyntax } init } : new { - ownir_version = 0, + ownir_version = 1, module = "Extracted", components, services = factServices, diff --git a/frontend/roslyn/OwnSharp.Extractor/ProtocolLowering.cs b/frontend/roslyn/OwnSharp.Extractor/ProtocolLowering.cs new file mode 100644 index 00000000..35cedcc9 --- /dev/null +++ b/frontend/roslyn/OwnSharp.Extractor/ProtocolLowering.cs @@ -0,0 +1,1198 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +// State protocols (P-010, pillar 9): lowering a C# state-protocol surface into OwnIR `move` / +// `borrow_mut` (OwnIR v1, spec/OwnIR.md §5.3; the bridge's side is spec/Bridge.md BR-L12/L13). +// +// The surface is recognised by two attributes, matched by NAME (so an API carries no +// dependency on this project): +// +// [ProtocolRegion] a method `(entity, callback)`: the callback's body is an exclusive +// region over the entity, and its one parameter is the state token; +// [ProtocolToken] a ref struct: every instance METHOD is a transition that consumes the +// token (and borrows the entity for the call); a PROPERTY is a read. +// +// This is a LOWERING, not an analysis. It reads the syntax of one method at a time and looks +// symbols up; it never tracks state across statements, never follows aliases, and never +// decides whether a program is right. Everything it emits is checked by the core: +// +// region entry acquire ; borrow_mut as { acquire ; ... }; release +// token.Transition() call [, ] (+ acquire ) +// var copy = token move <- +// token.Property use +// a value of the entity's TYPE mentioned inside the region +// use (exclusivity by type) +// +// WHAT IS CLAIMED. The profile protects the local C# capabilities and aliases of an entity +// that already exists: inside a region nothing but its token changes it, and a token is spent +// once. It does not protect the persisted row from other ways of changing it — a set-based +// update, a change-tracker metadata write, raw SQL, another process. Those belong to +// concurrency tokens, constraints and transactions. +// +// THE TRUST BOUNDARY. The types that DECLARE a protocol (the tokens, the type holding a +// region entry) are the trusted definition surface: token construction, region entry and +// transition plumbing live there, and their bodies are not lowered. Everything else is +// consumer code — the analysed surface. A type is one or the other, never both: consumer code +// inside a declaring type would simply be absent from the analysed program, so a region +// opened there is refused rather than guessed about. +// +// OUTSIDE a region nothing protocol-relevant is live, and a region lowers to a self-contained +// unit (the entity is acquired and released around it). So whatever surrounds a region — +// `try`/`catch`, `using`, a loop, a branch, `await` — is walked through and ignored. +// +// INSIDE a region the rule is the opposite: default-deny. The region is exclusive, and code +// the lowering cannot read is code that may reach the entity some other way. So the body may +// contain transitions, token reads, copies of a token, `if`, locals, and expressions made of +// literals, locals, fields and built-in operators — and nothing else. Every other construct is +// REFUSED (the run exits 2 and writes no facts), most importantly anything that runs code with +// no stated contract: a call, a constructor, a property getter or setter, an indexer, a +// user-defined operator or conversion. The one exception is a construct that visibly touches +// the entity: that is lowered as a use of it, and the core rejects it with a verdict rather +// than a refusal. When effect summaries (P-036/P-037) can prove a call harmless, this rule is +// the one to relax; until then an unprovable call is not analysed as safe. +// +// Also refused, anywhere: a token with no lowerable origin (`default`, `new`), a token +// parameter or return type, a token type that is not a ref struct, a region whose body is not +// a lambda written in place, a region over something that is not a local or a parameter, and +// a region entry in a position the statement walk does not reach. Those keep the shapes the +// core cannot check (a token minted outside a region, two tokens for one entity, a token spent +// against another entity) from having any spelling that lowers. +// +// And refused across the whole scan, region or no region: a protocol that is not ADMITTED (a +// public mutator of the state its transitions own), and reaching past an admitted one (see +// `CheckBoundary`). A refusal is the whole scan's: a recognised protocol construct that +// cannot be lowered safely is not reported next to findings that would read as "the rest is +// checked". +// +// BINDING. The scan is not an MSBuild compilation: it does not read `obj/`, so the usings a +// project gets implicitly are not there. A region whose entity does not bind is refused, not +// skipped; a project that relies on implicit usings writes them out (or qualifies the API). +internal static class ProtocolLowering +{ + internal sealed record Result(List Functions, List Refusals); + + private sealed class Refused(string message) : Exception(message); + + private sealed class Region + { + public required ISymbol Entity { get; init; } + public required ITypeSymbol? EntityType { get; init; } + public required string Owner { get; init; } + public required string Binding { get; init; } + } + + private sealed class Ctx + { + public required SemanticModel Model { get; init; } + public required string File { get; init; } + public required Dictionary Files { get; init; } + public required SortedDictionary Contracts { get; init; } + public required ISet LegacyNames { get; init; } + public List Regions { get; } = new(); + public Dictionary Tokens { get; } = + new(SymbolEqualityComparer.Default); + public HashSet LoweredEntries { get; } = new(); + public int Counter; + /// How many times the scan has lowered a mention of a borrowed entity. A construct + /// that runs unknown code is refused UNLESS it moved this counter: then the core + /// already has a use to reject, and a verdict is better than a refusal. + public int EntityTouches; + } + + public static Result Lower(Compilation compilation, + IReadOnlyList<(string file, SyntaxTree tree)> parsed, + ISet legacyNames) + { + var functions = new List(); + var refusals = new List(); + var contracts = new SortedDictionary(StringComparer.Ordinal); + var files = new Dictionary(); + foreach (var (file, tree) in parsed) + files[tree] = file; + + CheckBoundary(compilation, parsed, files, refusals); + + foreach (var (file, tree) in parsed) + { + var model = compilation.GetSemanticModel(tree); + var root = tree.GetRoot(); + var loweredEntries = new HashSet(); + + foreach (var method in root.DescendantNodes().OfType()) + { + if (model.GetDeclaredSymbol(method) is not IMethodSymbol msym) + continue; + if (IsApiType(msym.ContainingType)) + { + // The trust boundary (see the header): a declaring type's bodies + // implement the protocol and are not lowered. So a region OPENED in one + // of them — a handler written next to the region entry it calls — would + // not be a violation the core missed but a program it never saw, and + // would read as clean. Trusted is not the same as checked. + foreach (var opened in method.DescendantNodes().OfType() + .Where(i => IsRegionEntry(MethodOf(model, i)))) + refusals.Add(At(file, opened, + $"a protocol region is opened inside '{msym.ContainingType.Name}', one of the protocol's own types: code there implements the protocol and is not analysed, so this region would read as clean. Use the protocol from outside the types that declare it")); + continue; + } + try + { + foreach (var p in msym.Parameters) + if (IsToken(p.Type)) + throw new Refused(At(file, method, + $"protocol token parameter '{p.Name}': a token does not cross a method boundary in this profile")); + if (IsToken(msym.ReturnType)) + throw new Refused(At(file, method, + "a method returns a protocol token: a token does not cross a method boundary in this profile")); + + SyntaxNode? body = (SyntaxNode?)method.Body ?? method.ExpressionBody; + if (body is null) + continue; + var entries = body.DescendantNodes().OfType() + .Where(i => IsRegionEntry(MethodOf(model, i))).ToList(); + var tokenLocals = body.DescendantNodes().OfType() + .Where(v => model.GetDeclaredSymbol(v) is ILocalSymbol l && IsToken(l.Type)) + .ToList(); + if (entries.Count == 0 && tokenLocals.Count == 0) + continue; + if (method.Body is null) + throw new Refused(At(file, method, + "a method that opens a protocol region needs a block body")); + + // A method the IDisposable flow pass ALSO has a record for keeps both: the + // two track disjoint resources (a disposable captured by the callback is + // already an escape there), so they are two independent readings of one + // method. They cannot share a name — two records under one name read as + // an overload — so this one says which reading it is. + var name = $"{msym.ContainingType.ToDisplayString()}.{msym.Name}"; + if (legacyNames.Contains(name)) + name += "$protocol"; + + var ctx = new Ctx + { + Model = model, File = file, Files = files, Contracts = contracts, + LegacyNames = legacyNames, + }; + var ops = new List(); + foreach (var st in method.Body.Statements) + LowerOutside(ctx, st, ops); + + // Fail closed on anything the statement walk did not reach: a region entry + // or a token local it never saw would otherwise vanish from the facts. + foreach (var e in entries) + if (!ctx.LoweredEntries.Contains(e)) + throw new Refused(At(file, e, + "a protocol region entry in a position the lowering does not model (it must be a statement of its own, outside any lambda or local function)")); + foreach (var v in tokenLocals) + if (model.GetDeclaredSymbol(v) is ILocalSymbol l && !ctx.Tokens.ContainsKey(l)) + throw new Refused(At(file, v, + $"protocol token '{l.Name}' is declared outside a protocol region")); + loweredEntries.UnionWith(ctx.LoweredEntries); + + if (ops.Count > 0) + functions.Add(new Dictionary + { + ["name"] = name, ["file"] = file, ["body"] = ops, + }); + } + catch (Refused r) + { + refusals.Add(r.Message); + } + } + + // A region entry outside any method body (an accessor, a field initializer, a + // top-level statement) is not modelled either. + foreach (var inv in root.DescendantNodes().OfType()) + { + if (!IsRegionEntry(MethodOf(model, inv)) || loweredEntries.Contains(inv)) + continue; + if (inv.Ancestors().OfType().Any()) + continue; // inside a method: lowered above, or already refused there + refusals.Add(At(file, inv, + "a protocol region entry outside a method body is not modelled")); + } + } + + functions.AddRange(contracts.Values); + return new Result(functions, refusals); + } + + // ---- the protocol boundary ------------------------------------------------------------- + + /// What the region rules REST on: a token exists only because a region entry or a + /// transition handed it out, and the protocol's state changes only through a token. With + /// the protocol in its own assembly the C# compiler holds most of that through `internal`. + /// In ONE assembly — a minimal API with its domain beside the handlers — `internal` holds + /// nothing: `new ApprovedOrder(order).Ship()` and `order.MarkShipped()` compile in a method + /// with no region at all. A second assembly is not something this profile gets to demand, + /// so the scan holds the boundary itself, in two halves. + /// + /// ADMISSION — a property of the declarations. The protocol-owned state is what the + /// protocol's own types write on the entity, directly or through the entity methods they + /// call. An entity is admitted only if nothing PUBLIC on it writes that state: a public + /// setter or field, or a public method that reaches such a write. A public mutator is a + /// transition nobody declared, so the declaration is refused instead of the bypass being + /// allowed in silence. A write inside an object initializer is creation, not mutation. + /// + /// USE — a property of every other line of the scan. Outside the protocol's own types + /// three OPERATIONS are refused: creating a token value (`new`, `default`); invoking a + /// non-public method or constructor of the protocol or of the entity (a method group + /// counts — the delegate is the call); writing a field, property or event of either that + /// is not publicly writable. A MENTION is not an operation: `nameof`, `typeof`, a read. + /// + /// The entity types are read off the region entries' first parameter, with their base + /// classes (inherited state is state). Nothing is annotated. Both halves read bodies, so + /// the protocol and its entity must be in the scan as SOURCE: one that arrives only as a + /// compiled reference cannot be admitted, and a region over it is refused. The inside of a + /// region is left to the region's own scan, which already answers for every node there. + private static void CheckBoundary(Compilation compilation, + IReadOnlyList<(string file, SyntaxTree tree)> parsed, + Dictionary files, + List refusals) + { + var api = new HashSet(SymbolEqualityComparer.Default); + var entities = new HashSet(SymbolEqualityComparer.Default); + var regionBodies = new HashSet(); + + void AddToken(ITypeSymbol? type) + { + if (type?.OriginalDefinition is not INamedTypeSymbol named || !IsToken(named) + || !api.Add(named)) + return; + foreach (var m in named.GetMembers().OfType()) + AddToken(m.ReturnType); // what a transition hands back is a token too + } + + // Returns the protocol declarations this entry needs that are NOT in the scan as source. + List AddEntry(IMethodSymbol entry) + { + entry = (entry.ReducedFrom ?? entry).OriginalDefinition; + var compiled = new List(); + void NeedSource(ISymbol symbol) + { + if (symbol.DeclaringSyntaxReferences.IsEmpty) + compiled.Add(symbol.Name); + } + api.Add(entry.ContainingType.OriginalDefinition); + NeedSource(entry); + // the entity and what it inherits its state from + var first = true; + for (var entity = entry.Parameters.Length > 0 + ? entry.Parameters[0].Type.OriginalDefinition as INamedTypeSymbol : null; + entity is { TypeKind: not TypeKind.Error, SpecialType: not SpecialType.System_Object }; + entity = entity.BaseType?.OriginalDefinition, first = false) + { + entities.Add(entity); + if (first) + NeedSource(entity); + } + foreach (var p in entry.Parameters) + if (p.Type is INamedTypeSymbol { DelegateInvokeMethod: { } invoke }) + foreach (var q in invoke.Parameters) + { + AddToken(q.Type); + if (IsToken(q.Type)) + NeedSource(q.Type.OriginalDefinition); + } + return compiled; + } + + foreach (var (file, tree) in parsed) + { + var model = compilation.GetSemanticModel(tree); + foreach (var node in tree.GetRoot().DescendantNodes()) + { + switch (node) + { + case BaseTypeDeclarationSyntax type + when model.GetDeclaredSymbol(type) is INamedTypeSymbol declared: + AddToken(declared); + foreach (var m in declared.GetMembers().OfType()) + if (IsRegionEntry(m)) + AddEntry(m); + break; + case InvocationExpressionSyntax inv + when MethodOf(model, inv) is { } method && IsRegionEntry(method): + var compiled = AddEntry(method); + if (compiled.Count > 0) + refusals.Add(At(file, inv, + $"the state protocol behind this region is not in the scan as source ({string.Join(", ", compiled.Distinct())} come from a compiled reference): its admission cannot be checked, so the region is not analysed")); + foreach (var arg in inv.ArgumentList.Arguments) + if (Unparen(arg.Expression) is AnonymousFunctionExpressionSyntax body) + regionBodies.Add(body); + break; + } + } + } + if (api.Count == 0) + return; + + bool InFamily(ISymbol? member) => + member?.ContainingType?.OriginalDefinition is { } owner && entities.Contains(owner); + + string Where(ISymbol symbol) + { + var reference = symbol.DeclaringSyntaxReferences.FirstOrDefault(); + return reference is not null && files.TryGetValue(reference.SyntaxTree, out var f) + ? $"{f}:{Line(reference.GetSyntax())}" + : "?:0"; + } + + // ---- admission --------------------------------------------------------------------- + + // What one body does to the entity family: the state it writes and the family methods + // it reaches. Read from syntax, memoized, never across an object initializer. + var effects = new Dictionary Writes, HashSet Calls)>( + SymbolEqualityComparer.Default); + (HashSet Writes, HashSet Calls) Effects(IMethodSymbol method) + { + if (effects.TryGetValue(method, out var known)) + return known; + var writes = new HashSet(SymbolEqualityComparer.Default); + var calls = new HashSet(SymbolEqualityComparer.Default); + effects[method] = (writes, calls); + foreach (var reference in method.DeclaringSyntaxReferences) + { + var body = reference.GetSyntax(); + var model = compilation.GetSemanticModel(body.SyntaxTree); + foreach (var name in body.DescendantNodesAndSelf().OfType()) + { + if (InNameof(model, name)) + continue; + var symbol = Bound(model.GetSymbolInfo(name))?.OriginalDefinition; + if (!InFamily(symbol)) + continue; + switch (symbol) + { + case IMethodSymbol { MethodKind: not MethodKind.Constructor } callee: + calls.Add((callee.ReducedFrom ?? callee).OriginalDefinition); + break; + case IFieldSymbol or IPropertySymbol or IEventSymbol + when IsWrite(name) && !InObjectInitializer(name): + writes.Add(symbol); + if (symbol is IPropertySymbol { SetMethod: { } setter }) + calls.Add(setter.OriginalDefinition); // a setter with a body + break; + } + } + } + return (writes, calls); + } + + // Everything `root` writes, through the family methods it reaches. + HashSet Reach(IMethodSymbol root, List? unreadable = null) + { + var all = new HashSet(SymbolEqualityComparer.Default); + var seen = new HashSet(SymbolEqualityComparer.Default); + var queue = new Queue(); + queue.Enqueue(root); + while (queue.Count > 0) + { + var method = queue.Dequeue(); + if (!seen.Add(method)) + continue; + if (method.DeclaringSyntaxReferences.IsEmpty && !method.IsImplicitlyDeclared) + unreadable?.Add($"{method.ContainingType.Name}.{method.Name}"); + var (writes, calls) = Effects(method); + all.UnionWith(writes); + foreach (var callee in calls) + queue.Enqueue(callee); + } + return all; + } + + var owned = new HashSet(SymbolEqualityComparer.Default); + foreach (var type in api) + foreach (var member in type.GetMembers().OfType()) + { + var unreadable = new List(); + owned.UnionWith(Reach(member, unreadable)); + foreach (var name in unreadable.Distinct()) + refusals.Add($"{Where(member)}: the protocol calls '{name}', whose body is not in the scan: what it does to the entity cannot be read, so the protocol is not admitted"); + } + + string Open(ISymbol member, ISymbol state) => + $"{Where(member)}: '{member.ContainingType.Name}.{member.Name}' is public and writes '{state.Name}', state the protocol's transitions own: a public mutator is a transition nobody declared, and every token can be bypassed through it. Make it non-public, or make it a transition"; + + foreach (var entity in entities) + foreach (var member in entity.GetMembers()) + switch (member) + { + case IPropertySymbol property when owned.Contains(property) + && property.SetMethod is { DeclaredAccessibility: Accessibility.Public, IsInitOnly: false }: + refusals.Add(Open(property, property)); + break; + case IFieldSymbol { DeclaredAccessibility: Accessibility.Public, IsReadOnly: false, IsConst: false } field + when owned.Contains(field): + refusals.Add(Open(field, field)); + break; + case IMethodSymbol { DeclaredAccessibility: Accessibility.Public } method + when method.MethodKind is MethodKind.Ordinary or MethodKind.PropertySet + && !method.IsInitOnly + && Reach(method).FirstOrDefault(owned.Contains) is { } state: + // an auto-property's setter is the property case above + if (method.AssociatedSymbol is null || !owned.Contains(method.AssociatedSymbol)) + refusals.Add(Open(method.AssociatedSymbol ?? method, state)); + break; + } + + // ---- use --------------------------------------------------------------------------- + + // the names worth resolving: cheap, and exact enough to keep a large scan large + var guarded = new HashSet(StringComparer.Ordinal); + foreach (var type in api.Concat(entities)) + foreach (var member in type.GetMembers()) + if (member.DeclaredAccessibility != Accessibility.Public + || member is IPropertySymbol { SetMethod.DeclaredAccessibility: not Accessibility.Public }) + guarded.Add(member.Name); + + foreach (var (file, tree) in parsed) + { + var model = compilation.GetSemanticModel(tree); + foreach (var node in tree.GetRoot().DescendantNodes()) + { + var creates = node is BaseObjectCreationExpressionSyntax or DefaultExpressionSyntax + || node.IsKind(SyntaxKind.DefaultLiteralExpression); + var names = node is SimpleNameSyntax name && guarded.Contains(name.Identifier.Text); + if (!creates && !names) + continue; + if (node.Ancestors().Any(regionBodies.Contains)) + continue; // the region's own scan answers for this node + + var site = Enclosing(model, node); + bool Within(HashSet types) => site.Any(types.Contains); + // may code at this site reach a non-public member of `owner`? + bool Outside(INamedTypeSymbol? owner) + { + owner = owner?.OriginalDefinition; + if (owner is null) + return false; + if (api.Contains(owner)) + return !Within(api); + return entities.Contains(owner) && !Within(api) && !Within(entities); + } + + if (creates) + { + var info = model.GetTypeInfo(node); + var made = (node.IsKind(SyntaxKind.DefaultLiteralExpression) + ? info.ConvertedType : info.Type ?? info.ConvertedType)?.OriginalDefinition; + if (IsToken(made) && !Within(api)) + refusals.Add(At(file, node, + $"a protocol token '{made!.Name}' is created outside the protocol's own types: a token comes only from a region entry or a transition")); + else if (node is BaseObjectCreationExpressionSyntax + && Bound(model.GetSymbolInfo(node)) is IMethodSymbol + { DeclaredAccessibility: not Accessibility.Public } ctor + && Outside(ctor.ContainingType)) + refusals.Add(At(file, node, + Sealed(ctor.ContainingType, "the constructor", "it is invoked here"))); + continue; + } + if (InNameof(model, node)) + continue; // a mention, not an operation + + var member = Bound(model.GetSymbolInfo(node)); + member = member is IMethodSymbol method + ? (method.ReducedFrom ?? method).OriginalDefinition + : member?.OriginalDefinition; + var operation = member switch + { + IMethodSymbol { DeclaredAccessibility: not Accessibility.Public } => "it is called here", + IPropertySymbol property when IsWrite(node) + && (property.SetMethod?.DeclaredAccessibility ?? property.DeclaredAccessibility) + != Accessibility.Public => "it is written here", + IFieldSymbol or IEventSymbol + when IsWrite(node) && member.DeclaredAccessibility != Accessibility.Public + => "it is written here", + _ => null, // a read, or a public member: not this rule's business + }; + if (operation is not null && Outside(member!.ContainingType)) + refusals.Add(At(file, node, + Sealed(member.ContainingType, $"'{member.Name}'", operation))); + } + } + + static string Sealed(INamedTypeSymbol owner, string what, string operation) => + $"{what} of '{owner.Name}' is not public and belongs to a state protocol: {operation}, outside the protocol's own types, where it is reachable only through a token (the scan holds the protocol to the boundary a separate assembly would give it)"; + } + + private static ISymbol? Bound(SymbolInfo info) => + info.Symbol ?? (info.CandidateSymbols.Length == 1 ? info.CandidateSymbols[0] : null); + + /// The types `node` sits in, innermost first. + private static List Enclosing(SemanticModel model, SyntaxNode node) + { + var chain = new List(); + var symbol = model.GetEnclosingSymbol(node.SpanStart); + for (var type = symbol as INamedTypeSymbol ?? symbol?.ContainingType; + type is not null; type = type.ContainingType) + chain.Add(type.OriginalDefinition); + return chain; + } + + /// `nameof(x)` names a symbol and runs nothing. + private static bool InNameof(SemanticModel model, SyntaxNode node) => + node.Ancestors().OfType().Any(inv => + inv.Expression is IdentifierNameSyntax { Identifier.Text: "nameof" } + && model.GetConstantValue(inv).HasValue); + + /// The expression a name is the tail of: `a.b.Name` for `Name`, the name itself otherwise. + private static SyntaxNode Target(SyntaxNode name) + { + var target = name; + if (name.Parent is MemberAccessExpressionSyntax access && access.Name == name) + target = access; + while (target.Parent is ParenthesizedExpressionSyntax paren) + target = paren; + return target; + } + + /// Is this name the target of a write: an assignment (an object initializer's member is + /// one), `++`/`--`, or a `ref`/`out` argument. + private static bool IsWrite(SyntaxNode name) + { + var target = Target(name); + return target.Parent switch + { + AssignmentExpressionSyntax assignment => assignment.Left == target, + PrefixUnaryExpressionSyntax or PostfixUnaryExpressionSyntax => + target.Parent.IsKind(SyntaxKind.PreIncrementExpression) + || target.Parent.IsKind(SyntaxKind.PreDecrementExpression) + || target.Parent.IsKind(SyntaxKind.PostIncrementExpression) + || target.Parent.IsKind(SyntaxKind.PostDecrementExpression), + ArgumentSyntax argument => !argument.RefKindKeyword.IsKind(SyntaxKind.None) + && !argument.RefKindKeyword.IsKind(SyntaxKind.InKeyword), + _ => false, + }; + } + + /// A member assigned in `new T { Member = ... }` (or `with { ... }`): part of creating the + /// value, not a change to one that exists. + private static bool InObjectInitializer(SyntaxNode name) => + Target(name).Parent is AssignmentExpressionSyntax + { + Parent: InitializerExpressionSyntax initializer + } && (initializer.IsKind(SyntaxKind.ObjectInitializerExpression) + || initializer.IsKind(SyntaxKind.WithInitializerExpression)); + + // ---- recognition ---------------------------------------------------------------------- + + private static bool HasAttribute(ISymbol? symbol, string name) => + symbol is not null && symbol.GetAttributes().Any(a => + a.AttributeClass?.Name == name || a.AttributeClass?.Name == name + "Attribute"); + + private static bool IsToken(ITypeSymbol? type) => HasAttribute(type, "ProtocolToken"); + + private static bool IsRegionEntry(IMethodSymbol? method) => + method is not null && HasAttribute((method.ReducedFrom ?? method).OriginalDefinition, + "ProtocolRegion"); + + private static bool IsApiType(INamedTypeSymbol? type) => + type is not null && (IsToken(type) + || type.GetMembers().OfType().Any(IsRegionEntry)); + + /// The method an invocation names. When overload resolution FAILED (an argument did not + /// bind — typically a degraded compilation: a missing reference, a missing global using) + /// the single candidate still says which method was meant, and it is used: a region + /// entry that does not bind must not silently stop being a region entry. Whatever is + /// unresolved inside it is then refused by the region's default-deny scan. + private static IMethodSymbol? MethodOf(SemanticModel model, InvocationExpressionSyntax inv) + { + var info = model.GetSymbolInfo(inv); + if (info.Symbol is IMethodSymbol bound) + return bound; + var candidates = info.CandidateSymbols.OfType().ToList(); + return candidates.Count == 1 ? candidates[0] + : candidates.FirstOrDefault(c => IsRegionEntry(c) || IsToken(c.ContainingType)); + } + + private static ExpressionSyntax Unparen(ExpressionSyntax e) + { + while (e is ParenthesizedExpressionSyntax p) + e = p.Expression; + return e; + } + + private static int Line(SyntaxNode node) => + node.GetLocation().GetLineSpan().StartLinePosition.Line + 1; + + private static string At(string file, SyntaxNode node, string message) => + $"{file}:{Line(node)}: {message}"; + + private static Refused Refuse(Ctx ctx, SyntaxNode node, string message) => + new(At(ctx.File, node, message)); + + /// A type whose values carry no user code: formatting or concatenating one runs nothing + /// the lowering would have to read. + private static bool IsInert(ITypeSymbol? type) => + type is not null && (type.TypeKind == TypeKind.Enum || type.SpecialType is + SpecialType.System_Boolean or SpecialType.System_Char or SpecialType.System_String + or SpecialType.System_SByte or SpecialType.System_Byte + or SpecialType.System_Int16 or SpecialType.System_UInt16 + or SpecialType.System_Int32 or SpecialType.System_UInt32 + or SpecialType.System_Int64 or SpecialType.System_UInt64 + or SpecialType.System_Single or SpecialType.System_Double + or SpecialType.System_Decimal or SpecialType.System_DateTime); + + // ---- ops ------------------------------------------------------------------------------ + + private static Dictionary Acquire(string name, int line) => + new() { ["op"] = "acquire", ["var"] = name, ["line"] = line }; + + private static Dictionary Release(string name, int line) => + new() { ["op"] = "release", ["var"] = name, ["line"] = line }; + + private static Dictionary Use(string name, int line) => + new() { ["op"] = "use", ["var"] = name, ["line"] = line }; + + private static Dictionary Move(string name, string src, int line) => + new() { ["op"] = "move", ["var"] = name, ["src"] = src, ["line"] = line }; + + private static Dictionary Call(string callee, string[] args, int line) => + new() { ["op"] = "call", ["callee"] = callee, ["args"] = args, ["line"] = line }; + + private static void Touch(Ctx ctx, Region region, SyntaxNode at, List ops) + { + ops.Add(Use(region.Owner, Line(at))); + ctx.EntityTouches++; + } + + // ---- statements OUTSIDE a region ------------------------------------------------------ + + /// Outside a region nothing protocol-relevant is live, so the only statements that matter + /// are region entries — wherever they sit. A region is a self-contained unit, so the + /// control flow around it (a branch, a loop, `try`, `using`) changes no verdict inside + /// it, and the units are emitted in source order. + private static void LowerOutside(Ctx ctx, StatementSyntax st, List ops) + { + if (st is ExpressionStatementSyntax es + && Unparen(es.Expression) is InvocationExpressionSyntax entry + && IsRegionEntry(MethodOf(ctx.Model, entry))) + { + LowerRegion(ctx, entry, ops, st); + return; + } + if (st is LocalFunctionStatementSyntax) + return; // another body; an entry inside it is refused as "not reached" + if (st is LocalDeclarationStatementSyntax ld) + foreach (var v in ld.Declaration.Variables) + if (ctx.Model.GetDeclaredSymbol(v) is ILocalSymbol local && IsToken(local.Type)) + throw Refuse(ctx, v, + $"protocol token '{local.Name}' is declared outside a protocol region"); + foreach (var nested in NestedStatements(st)) + LowerOutside(ctx, nested, ops); + } + + /// The statements directly nested in `node` (through blocks, clauses and sections), in + /// source order, never crossing into a lambda or a local function. + private static IEnumerable NestedStatements(SyntaxNode node) + { + foreach (var child in node.ChildNodes()) + { + if (child is AnonymousFunctionExpressionSyntax) + continue; + if (child is StatementSyntax statement) + yield return statement; + else + foreach (var deeper in NestedStatements(child)) + yield return deeper; + } + } + + // ---- statements INSIDE a region ------------------------------------------------------- + + private static void LowerInside(Ctx ctx, StatementSyntax st, List ops) + { + switch (st) + { + case BlockSyntax block: + foreach (var inner in block.Statements) + LowerInside(ctx, inner, ops); + return; + case EmptyStatementSyntax: + return; + case ExpressionStatementSyntax es: + if (Unparen(es.Expression) is InvocationExpressionSyntax entry + && IsRegionEntry(MethodOf(ctx.Model, entry))) + { + LowerRegion(ctx, entry, ops, st); + return; + } + Scan(ctx, es.Expression, ops); + return; + case LocalDeclarationStatementSyntax ld: + if (!ld.UsingKeyword.IsKind(SyntaxKind.None) || !ld.AwaitKeyword.IsKind(SyntaxKind.None)) + throw Refuse(ctx, st, "a `using` declaration inside a protocol region is not modelled"); + foreach (var v in ld.Declaration.Variables) + { + var init = v.Initializer?.Value; + if (ctx.Model.GetDeclaredSymbol(v) is ILocalSymbol local && IsToken(local.Type)) + LowerTokenLocal(ctx, local, init, ops, v); + else if (init is not null) + Scan(ctx, init, ops); + } + return; + case IfStatementSyntax ifs: + Scan(ctx, ifs.Condition, ops); + var thenOps = new List(); + LowerInside(ctx, ifs.Statement, thenOps); + var elseOps = new List(); + if (ifs.Else is not null) + LowerInside(ctx, ifs.Else.Statement, elseOps); + ops.Add(new Dictionary + { + ["op"] = "if", ["line"] = Line(st), ["then"] = thenOps, ["else"] = elseOps, + }); + return; + case ReturnStatementSyntax: + throw Refuse(ctx, st, + "`return` inside a protocol region leaves the callback, not the method; not modelled"); + default: + throw Refuse(ctx, st, $"{st.Kind()} inside a protocol region is not modelled"); + } + } + + private static void LowerRegion(Ctx ctx, InvocationExpressionSyntax entry, List ops, + StatementSyntax st) + { + var args = entry.ArgumentList.Arguments; + if (args.Count != 2) + throw Refuse(ctx, entry, "a protocol region entry takes (entity, callback)"); + var entityExpr = Unparen(args[0].Expression); + var entity = ctx.Model.GetSymbolInfo(entityExpr).Symbol; + if (entityExpr is not IdentifierNameSyntax || entity is not (ILocalSymbol or IParameterSymbol)) + throw Refuse(ctx, entry, + "the entity of a protocol region must be a local or a parameter: that symbol is the resource identity"); + if (Unparen(args[1].Expression) is not LambdaExpressionSyntax lambda) + throw Refuse(ctx, entry, + "the body of a protocol region must be a lambda written in place"); + if (lambda.AsyncKeyword.IsKind(SyntaxKind.AsyncKeyword)) + throw Refuse(ctx, entry, "the body of a protocol region cannot be async"); + ParameterSyntax? parameter = lambda switch + { + SimpleLambdaExpressionSyntax s => s.Parameter, + ParenthesizedLambdaExpressionSyntax p when p.ParameterList.Parameters.Count == 1 => + p.ParameterList.Parameters[0], + _ => null, + }; + if (parameter is null + || ctx.Model.GetDeclaredSymbol(parameter) is not IParameterSymbol token + || !IsToken(token.Type)) + throw Refuse(ctx, entry, + "the callback of a protocol region takes exactly one protocol token"); + // A token that is not a ref struct can be captured by a nested lambda, stored in a + // field, or carried across an await — every one of which lets it reach ANOTHER + // region, the shape the core cannot check. The language forbids all three for a + // ref struct, so the lowering leans on that and refuses anything weaker. + if (!token.Type.IsRefLikeType) + throw Refuse(ctx, entry, + $"protocol token type '{token.Type.Name}' must be a ref struct"); + + var line = Line(st); + var entityType = TypeOf(entity); + // Exclusivity is BY TYPE, so an entity whose type does not resolve cannot be told + // from anything else that does not: the scan's compilation is degraded (a missing + // reference, an implicit using it never saw). Say so instead of guessing either way. + if (entityType is null or IErrorTypeSymbol) + throw Refuse(ctx, entry, + $"the type of '{entity.Name}' does not resolve, so the region cannot be lowered: the scan is missing a reference, or a `using` the project only gets implicitly (the scan does not read `obj/`: write the using out, or qualify the name)"); + var existing = ctx.Regions.LastOrDefault(r => + SymbolEqualityComparer.Default.Equals(r.Entity, entity)); + if (existing is null) + { + // exclusivity by type: another value of an already-borrowed entity's type + var clash = RegionByType(ctx, entityType); + if (clash is not null) + Touch(ctx, clash, entry, ops); + ops.Add(Acquire(entity.Name, line)); + } + var owner = existing?.Owner ?? entity.Name; + ctx.Counter++; + var region = new Region + { + Entity = entity, EntityType = entityType, Owner = owner, + Binding = $"{owner}.region{ctx.Counter}", + }; + var body = new List { Acquire(token.Name, line) }; + ctx.Tokens[token] = (token.Name, region); + ctx.Regions.Add(region); + if (lambda.Body is BlockSyntax block) + LowerInside(ctx, block, body); + else if (lambda.Body is ExpressionSyntax expression) + Scan(ctx, expression, body); + ctx.Regions.RemoveAt(ctx.Regions.Count - 1); + ops.Add(new Dictionary + { + ["op"] = "borrow_mut", ["owner"] = owner, ["binding"] = region.Binding, + ["line"] = line, ["body"] = body, + }); + if (existing is null) + ops.Add(Release(owner, line)); + ctx.LoweredEntries.Add(entry); + } + + private static void LowerTokenLocal(Ctx ctx, ILocalSymbol local, ExpressionSyntax? init, + List ops, SyntaxNode at) + { + if (init is not null) + { + var value = Unparen(init); + if (value is IdentifierNameSyntax id + && ctx.Model.GetSymbolInfo(id).Symbol is { } source + && ctx.Tokens.TryGetValue(source, out var live)) + { + // C# copies the struct; the model reads the copy as a MOVE. + ops.Add(Move(local.Name, live.Name, Line(at))); + ctx.Tokens[local] = (local.Name, live.Region); + return; + } + if (value is InvocationExpressionSyntax inv + && TryTransition(ctx, inv, ops, local.Name, out var region)) + { + ctx.Tokens[local] = (local.Name, region); + return; + } + } + throw Refuse(ctx, at, + $"protocol token '{local.Name}' has no lowerable origin: a token comes from a region entry, a transition, or a copy of a live token"); + } + + // ---- expressions ---------------------------------------------------------------------- + + /// A call on a token is a transition: it consumes the token and borrows the entity for + /// the call. `result`, when given, names the token the transition hands back. + private static bool TryTransition(Ctx ctx, InvocationExpressionSyntax inv, List ops, + string? result, out Region region) + { + region = null!; + if (inv.Expression is not MemberAccessExpressionSyntax access + || MethodOf(ctx.Model, inv) is not { IsStatic: false } method + || !IsToken(method.ContainingType)) + return false; + + string receiver; + var target = Unparen(access.Expression); + if (target is IdentifierNameSyntax id + && ctx.Model.GetSymbolInfo(id).Symbol is { } symbol + && ctx.Tokens.TryGetValue(symbol, out var live)) + { + receiver = live.Name; + region = live.Region; + } + else if (target is InvocationExpressionSyntax inner) + { + // a chain: `draft.Submit().Approve()` - the intermediate token is a temporary + ctx.Counter++; + receiver = $"$t{ctx.Counter}"; + if (!TryTransition(ctx, inner, ops, receiver, out region)) + throw Refuse(ctx, inv, + $"the receiver of transition '{method.Name}' is not a token this region minted"); + } + else + { + throw Refuse(ctx, inv, + $"the receiver of transition '{method.Name}' is not a token this region minted"); + } + + foreach (var arg in inv.ArgumentList.Arguments) + Scan(ctx, arg.Expression, ops); + + var callee = $"{method.ContainingType.ToDisplayString()}.{method.Name}"; + Contract(ctx, callee, method, inv); + ops.Add(Call(callee, new[] { receiver, region.Binding }, Line(inv))); + if (result is not null) + { + if (!IsToken(method.ReturnType)) + throw Refuse(ctx, inv, + $"transition '{method.Name}' does not return a protocol token"); + ops.Add(Acquire(result, Line(inv))); + } + return true; + } + + /// The contract of a transition, stated once per method: the token is consumed, the + /// entity is exclusively borrowed for the call. This is a FACT about the attribute's + /// meaning, not an inference from the method's body. + private static void Contract(Ctx ctx, string callee, IMethodSymbol method, SyntaxNode at) + { + if (ctx.Contracts.ContainsKey(callee)) + return; + if (ctx.LegacyNames.Contains(callee)) + throw Refuse(ctx, at, + $"transition '{callee}' already has a flow record; the two lowerings are not merged in this profile"); + var decl = method.DeclaringSyntaxReferences.FirstOrDefault(); + var file = decl is not null && ctx.Files.TryGetValue(decl.SyntaxTree, out var f) ? f : "?"; + var line = decl is not null ? Line(decl.GetSyntax()) : 0; + ctx.Contracts[callee] = new Dictionary + { + ["name"] = callee, + ["file"] = file, + ["params"] = new object[] + { + new Dictionary { ["name"] = "token", ["effect"] = "consume", ["line"] = line }, + new Dictionary { ["name"] = "entity", ["effect"] = "borrow_mut", ["line"] = line }, + }, + ["body"] = new object[] { Release("token", line) }, + }; + } + + private static ITypeSymbol? TypeOf(ISymbol symbol) => symbol switch + { + ILocalSymbol l => l.Type, + IParameterSymbol p => p.Type, + IFieldSymbol f => f.Type, + IPropertySymbol p => p.Type, + _ => null, + }; + + private static Region? RegionByType(Ctx ctx, ITypeSymbol? type) => + type is null ? null : ctx.Regions.LastOrDefault(r => + SymbolEqualityComparer.Default.Equals(r.EntityType, type)); + + private static Region? RegionFor(Ctx ctx, ISymbol symbol, ITypeSymbol? type) => + ctx.Regions.LastOrDefault(r => SymbolEqualityComparer.Default.Equals(r.Entity, symbol)) + ?? RegionByType(ctx, type); + + /// Exclusivity by type: an expression that PRODUCES a value of a borrowed entity's type + /// (a field read, a cast, an array element) may be that entity, so it counts as + /// touching it. + private static void NoteEntityTyped(Ctx ctx, ExpressionSyntax expression, List ops) + { + var region = RegionByType(ctx, ctx.Model.GetTypeInfo(expression).Type); + if (region is not null) + Touch(ctx, region, expression, ops); + } + + private static bool IsLiveToken(Ctx ctx, ExpressionSyntax expression, out string name) + { + name = ""; + if (Unparen(expression) is IdentifierNameSyntax id + && ctx.Model.GetSymbolInfo(id).Symbol is { } symbol + && ctx.Tokens.TryGetValue(symbol, out var token)) + { + name = token.Name; + return true; + } + return false; + } + + /// Code with no stated contract, inside an exclusive region. If lowering its operands + /// touched the entity the core has a use to reject; otherwise nothing says what the code + /// does, and the region is not analysed as safe. + private static void OpaqueCode(Ctx ctx, SyntaxNode node, string what, int touchesBefore) + { + if (ctx.EntityTouches > touchesBefore) + return; + throw Refuse(ctx, node, + $"{what} inside a protocol region runs code with no stated contract; an exclusive region admits only transitions and what the lowering can read"); + } + + /// An expression inside a region. DEFAULT-DENY: every kind is either read here or refused. + private static void Scan(Ctx ctx, SyntaxNode node, List ops) + { + if (node is ExpressionSyntax typed + && ctx.Model.GetConversion(typed).IsUserDefined) + throw Refuse(ctx, node, + "a user-defined conversion inside a protocol region runs code with no stated contract"); + + switch (node) + { + case LiteralExpressionSyntax: + case TypeOfExpressionSyntax: + case SizeOfExpressionSyntax: + case DefaultExpressionSyntax: + case PredefinedTypeSyntax: + return; + case ParenthesizedExpressionSyntax paren: + Scan(ctx, paren.Expression, ops); + return; + case CheckedExpressionSyntax @checked: + Scan(ctx, @checked.Expression, ops); + return; + case ThisExpressionSyntax or BaseExpressionSyntax: + NoteEntityTyped(ctx, (ExpressionSyntax)node, ops); + return; + case IdentifierNameSyntax id: + { + var symbol = ctx.Model.GetSymbolInfo(id).Symbol; + switch (symbol) + { + case null: + throw Refuse(ctx, id, + $"'{id.Identifier.Text}' does not resolve; an unresolved name inside a protocol region is not read as harmless"); + case INamespaceOrTypeSymbol: + return; + case ILocalSymbol or IParameterSymbol or IFieldSymbol: + if (ctx.Tokens.ContainsKey(symbol)) + throw Refuse(ctx, id, + $"protocol token '{id.Identifier.Text}' is used in a way the lowering does not model (transitions, property reads and copies are)"); + var region = RegionFor(ctx, symbol, TypeOf(symbol)); + if (region is not null) + Touch(ctx, region, id, ops); + return; + case IPropertySymbol property: + { + var before = ctx.EntityTouches; + var owner = RegionByType(ctx, property.Type); + if (owner is not null) + Touch(ctx, owner, id, ops); + OpaqueCode(ctx, id, $"property '{property.Name}'", before); + return; + } + default: + throw Refuse(ctx, id, + $"'{id.Identifier.Text}' ({symbol.Kind}) inside a protocol region is not modelled"); + } + } + case MemberAccessExpressionSyntax access: + { + if (IsLiveToken(ctx, access.Expression, out var token)) + { + ops.Add(Use(token, Line(access))); // a property read on the token + return; + } + var before = ctx.EntityTouches; + Scan(ctx, access.Expression, ops); + var member = ctx.Model.GetSymbolInfo(access).Symbol; + switch (member) + { + case IFieldSymbol: + NoteEntityTyped(ctx, access, ops); + return; + case INamespaceOrTypeSymbol: + return; + case IPropertySymbol property: + NoteEntityTyped(ctx, access, ops); + OpaqueCode(ctx, access, $"property '{property.Name}'", before); + return; + default: + throw Refuse(ctx, access, + $"'{access.Name.Identifier.Text}' inside a protocol region is not modelled"); + } + } + case InvocationExpressionSyntax inv: + { + // `nameof(x)` is a constant spelled as a call + if (ctx.Model.GetConstantValue(inv).HasValue) + return; + var method = MethodOf(ctx.Model, inv); + if (IsRegionEntry(method)) + throw Refuse(ctx, inv, + "a protocol region entry in a position the lowering does not model (it must be a statement of its own)"); + if (TryTransition(ctx, inv, ops, null, out _)) + return; + var before = ctx.EntityTouches; + foreach (var arg in inv.ArgumentList.Arguments) + { + if (IsLiveToken(ctx, arg.Expression, out var passed)) + throw Refuse(ctx, arg, + $"protocol token '{passed}' is handed to other code; a token does not leave its region"); + Scan(ctx, arg.Expression, ops); + } + // the receiver, never the method's own name + if (inv.Expression is MemberAccessExpressionSyntax target) + Scan(ctx, target.Expression, ops); + NoteEntityTyped(ctx, inv, ops); + var name = method is null + ? inv.Expression.ToString() + : $"{method.ContainingType.ToDisplayString()}.{method.Name}"; + OpaqueCode(ctx, inv, $"a call to '{name}'", before); + return; + } + case BaseObjectCreationExpressionSyntax creation: + { + var before = ctx.EntityTouches; + foreach (var arg in creation.ArgumentList?.Arguments ?? default) + Scan(ctx, arg.Expression, ops); + if (creation.Initializer is not null) + throw Refuse(ctx, creation, + "an object initializer inside a protocol region is not modelled"); + OpaqueCode(ctx, creation, "a constructor call", before); + return; + } + case ArrayCreationExpressionSyntax or ImplicitArrayCreationExpressionSyntax + or InitializerExpressionSyntax or TupleExpressionSyntax + or ArrayTypeSyntax or ArrayRankSpecifierSyntax or OmittedArraySizeExpressionSyntax + or ArgumentSyntax or ConditionalExpressionSyntax: + foreach (var child in node.ChildNodes()) + Scan(ctx, child, ops); + return; + case ElementAccessExpressionSyntax element: + { + var before = ctx.EntityTouches; + Scan(ctx, element.Expression, ops); + foreach (var arg in element.ArgumentList.Arguments) + Scan(ctx, arg.Expression, ops); + NoteEntityTyped(ctx, element, ops); + if (ctx.Model.GetTypeInfo(element.Expression).Type is not IArrayTypeSymbol) + OpaqueCode(ctx, element, "an indexer", before); + return; + } + case BinaryExpressionSyntax binary: + { + if (ctx.Model.GetSymbolInfo(binary).Symbol is IMethodSymbol + { MethodKind: not MethodKind.BuiltinOperator }) + throw Refuse(ctx, binary, + "a user-defined operator inside a protocol region runs code with no stated contract"); + // string concatenation formats its operands: only inert ones run no user code + if (binary.IsKind(SyntaxKind.AddExpression) + && ctx.Model.GetTypeInfo(binary).Type?.SpecialType == SpecialType.System_String + && !(IsInert(ctx.Model.GetTypeInfo(binary.Left).Type) + && IsInert(ctx.Model.GetTypeInfo(binary.Right).Type))) + throw Refuse(ctx, binary, + "string concatenation of a non-primitive value inside a protocol region calls its ToString(); not modelled"); + Scan(ctx, binary.Left, ops); + // the right operand of `is` / `as` is a type, not a value + if (!binary.IsKind(SyntaxKind.AsExpression) && !binary.IsKind(SyntaxKind.IsExpression)) + Scan(ctx, binary.Right, ops); + if (binary.IsKind(SyntaxKind.AsExpression)) + NoteEntityTyped(ctx, binary, ops); + return; + } + case PrefixUnaryExpressionSyntax or PostfixUnaryExpressionSyntax: + { + if (ctx.Model.GetSymbolInfo(node).Symbol is IMethodSymbol + { MethodKind: not MethodKind.BuiltinOperator }) + throw Refuse(ctx, node, + "a user-defined operator inside a protocol region runs code with no stated contract"); + foreach (var child in node.ChildNodes()) + Scan(ctx, child, ops); + return; + } + case AssignmentExpressionSyntax assignment: + { + if (ctx.Model.GetSymbolInfo(assignment).Symbol is IMethodSymbol + { MethodKind: not MethodKind.BuiltinOperator }) + throw Refuse(ctx, assignment, + "a user-defined operator inside a protocol region runs code with no stated contract"); + Scan(ctx, assignment.Left, ops); + Scan(ctx, assignment.Right, ops); + return; + } + case CastExpressionSyntax cast: + { + var target = ctx.Model.GetTypeInfo(cast.Type).Type; + if (target is null + || ctx.Model.ClassifyConversion(cast.Expression, target).IsUserDefined) + throw Refuse(ctx, cast, + "a user-defined conversion inside a protocol region runs code with no stated contract"); + Scan(ctx, cast.Expression, ops); + NoteEntityTyped(ctx, cast, ops); + return; + } + case InterpolatedStringExpressionSyntax interpolated: + foreach (var part in interpolated.Contents.OfType()) + { + if (!IsInert(ctx.Model.GetTypeInfo(part.Expression).Type)) + throw Refuse(ctx, part, + "interpolating a non-primitive value inside a protocol region calls its ToString(); not modelled"); + Scan(ctx, part.Expression, ops); + } + return; + default: + throw Refuse(ctx, node, $"{node.Kind()} inside a protocol region is not modelled"); + } + } +} diff --git a/frontend/roslyn/README.md b/frontend/roslyn/README.md index 12118e8e..cd7f340f 100644 --- a/frontend/roslyn/README.md +++ b/frontend/roslyn/README.md @@ -70,6 +70,88 @@ symbols instead of surfacing as OWN050. `--no-project-refs` opts out; an unbuilt project just contributes nothing. Run `dotnet run --project OwnSharp.Extractor -- --help` for the full option list. +## State protocols (`--flow-locals`, OwnIR v1) + +With `--flow-locals` the extractor also lowers a **state-protocol surface** — the +first slice of [P-010](../../docs/proposals/P-010-type-disciplines.md) pillar 9 — +into the OwnIR v1 ops `move` and `borrow_mut` ([OwnIR.md §5.3](../../spec/OwnIR.md)). +(These are *state* protocols — which state an entity is in. The *obligation* +protocols of P-025 / OwnIR §8 are a different mechanism with a similar name.) +It is recognised by two attributes matched by **name**, so a domain carries no +dependency on Own.NET: + +```csharp +[ProtocolToken] // a state: a ref struct over the entity +public readonly ref struct ApprovedOrder +{ + private readonly Order _order; + internal ApprovedOrder(Order order) => _order = order; + public void Ship(DateTime at) => _order.MarkShipped(at); // a transition: spends the token +} + +public static class OrderProtocol +{ + [ProtocolRegion] // a region entry: (entity, callback) + public static void WithApproved(Order order, ApprovedRegion body) { /* check, then */ body(new ApprovedOrder(order)); } +} + +// a handler: no attribute, no base class, no repository — the entity EF tracks +OrderProtocol.WithApproved(order, approved => +{ + approved.Ship(now); +}); +``` + +Inside the callback the entity is **exclusively borrowed**: only its token may +change it, a token is spent once (use after a transition is OWN002, a copy is a +move — OWN005), and any other mention of the entity is OWN013. The verdicts are +the core's; the extractor only lowers. A complete backend — ASP.NET Core minimal +API, EF Core, SQLite — is in +[`protocol-samples/efcore`](protocol-samples/efcore), and +`python scripts/protocol_gate.py` ties every committed fact back to the C# it came +from. + +**What is claimed.** The profile protects the local C# capabilities and aliases of +an entity that already exists. It does **not** protect the persisted row from +other ways of changing it: `ExecuteUpdate`, a change-tracker metadata write, raw +SQL, another process. Those belong to concurrency tokens, constraints and +transactions (two of them are pinned as stated limits under +`protocol-samples/efcore/known-gaps`). + +**The trust boundary.** The types that DECLARE a protocol — the tokens, and the +type holding a region entry — are its trusted definition surface: they construct +tokens, enter regions and implement transitions, and their bodies are not +lowered. Everything else is consumer code, and consumer code is what the profile +analyses. A type is one or the other, never both. A handler written inside a +declaring type would not be a violation the core missed; it would be a program +the core never saw, and it would read as clean. So a region opened inside a +declaring type is refused, and the profile does not try to guess which method of +such a type is plumbing and which is a business handler. + +**Refusals.** A recognised protocol construct that cannot be lowered safely is +not skipped: the extractor exits `2` and writes no facts, for the whole scan. + +- *Inside a region the rule is default-deny.* Transitions, token reads, `if`, + locals and built-in operators are read; a call, a constructor, a property + getter, an indexer, a loop, `return` are refused — nothing states what such code + does to the entity. Read what you need (`DateTime.UtcNow`, a logger call) before + the region. Around a region anything goes: `try`/`catch`, `await using`, loops. +- *Admission.* The state a transition writes must have no **public** mutator on + the entity (a public setter, or a public method reaching the same write): that + would be a transition nobody declared. +- *Boundary.* Outside the protocol's own types, creating a token (`new`, + `default`), calling a non-public method of the entity or the protocol, and + writing their non-publicly-writable state are refused — one assembly or two. + `nameof`, `typeof` and reads are mentions, not operations. +- *Source.* The protocol and its entity must be in the scan as source; one that + arrives only as a compiled reference cannot be admitted. +- *Trust boundary.* A region opened inside a type that declares the protocol + (see above): write the code that uses a protocol outside the types that + declare it. +- *Binding.* The scan does not read `obj/`, so usings a project only gets + **implicitly** are not there. A region whose entity does not bind is refused; + write the usings out in the files that open regions (or qualify the names). + ## Use it on a real repo / in CI (P-013) The two stages are chained by one orchestrator script, so you don't run them by diff --git a/frontend/roslyn/protocol-samples/Api/ProtocolApi.cs b/frontend/roslyn/protocol-samples/Api/ProtocolApi.cs new file mode 100644 index 00000000..f4e3b030 --- /dev/null +++ b/frontend/roslyn/protocol-samples/Api/ProtocolApi.cs @@ -0,0 +1,128 @@ +using System; +using System.Threading.Tasks; + +namespace Own.Protocols.Sample; + +// The sample state protocol behind `protocol-samples/cases` (C# -> OwnIR v1 lowering, +// see frontend/roslyn/README.md). Deliberately minimal: one entity, three state tokens, +// two region entries, no persistence. It is a fixture, not an API proposal — the +// realistic shape, on an entity EF Core tracks, is `protocol-samples/efcore`. What it +// has to be is honestly lowerable: +// +// * a region entry is a method marked [ProtocolRegion]: (entity, callback); +// * a state token is a `ref struct` marked [ProtocolToken]; every instance METHOD +// on it is a transition and consumes the token, a PROPERTY is a read; +// * a token can only be obtained from a region entry or from a transition, so the +// shapes the core cannot check (a token minted outside a region, two tokens for +// one entity, a token spent against another entity) have no spelling here. +// +// The two attributes are matched by NAME, so this file has no dependency on Own.NET. + +[AttributeUsage(AttributeTargets.Struct)] +public sealed class ProtocolTokenAttribute : Attribute { } + +[AttributeUsage(AttributeTargets.Method)] +public sealed class ProtocolRegionAttribute : Attribute { } + +public enum OrderStatus { Draft, Submitted, Approved, Shipped, Cancelled } + +public sealed class Order +{ + public int Id { get; internal set; } + public OrderStatus Status { get; internal set; } + public string Note { get; private set; } = ""; + + public static Order Load(int id) => new() { Id = id }; + + // Ordinary public behaviour that is NOT protocol state: free outside a region, and a raw + // access the region must exclude inside one. (A public member that wrote `Status` would + // be a transition nobody declared; the protocol would not be admitted with it.) + public void Annotate(string note) => Note = note; +} + +[ProtocolToken] +public readonly ref struct DraftOrder +{ + private readonly Order _order; + internal DraftOrder(Order order) => _order = order; + + public int Id => _order.Id; + + public SubmittedOrder Submit() + { + _order.Status = OrderStatus.Submitted; + return new SubmittedOrder(_order); + } + + public void Cancel() => _order.Status = OrderStatus.Cancelled; +} + +[ProtocolToken] +public readonly ref struct SubmittedOrder +{ + private readonly Order _order; + internal SubmittedOrder(Order order) => _order = order; + + public int Id => _order.Id; + + // Returns nothing: the token is spent and no further capability is handed out. + public void Approve() => _order.Status = OrderStatus.Approved; +} + +[ProtocolToken] +public readonly ref struct ApprovedOrder +{ + private readonly Order _order; + internal ApprovedOrder(Order order) => _order = order; + + public int Id => _order.Id; + + public void Ship() => _order.Status = OrderStatus.Shipped; +} + +public delegate void DraftRegion(DraftOrder draft); + +public delegate void ApprovedRegion(ApprovedOrder approved); + +public static class Protocol +{ + [ProtocolRegion] + public static void WithDraft(Order order, DraftRegion body) + { + if (order.Status != OrderStatus.Draft) + throw new InvalidOperationException("the order is not a draft"); + body(new DraftOrder(order)); + } + + [ProtocolRegion] + public static void WithApproved(Order order, ApprovedRegion body) + { + if (order.Status != OrderStatus.Approved) + throw new InvalidOperationException("the order is not approved"); + body(new ApprovedOrder(order)); + } +} + +// Stand-ins so the cases look like a handler without pulling EF Core into the gate. +public sealed class Db +{ + public Task SingleAsync(int id) => Task.FromResult(Order.Load(id)); + + public Task SaveChangesAsync() => Task.FromResult(1); +} + +public static class Audit +{ + public static void Record(Order order) { } +} + +// Code that reaches an entity WITHOUT naming it at the call site: the shape an exclusive +// region cannot be allowed to wave through. +public static class Backdoor +{ + private static Order? _last; + + public static void Remember(Order order) => _last = order; + + public static void AnnotateLast() => _last?.Annotate("behind the call"); +} diff --git a/frontend/roslyn/protocol-samples/cases/A1_alias_of_entity.cs b/frontend/roslyn/protocol-samples/cases/A1_alias_of_entity.cs new file mode 100644 index 00000000..6beffdc9 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/A1_alias_of_entity.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// An alias made BEFORE the region, used inside it -> reject. +// No alias analysis: inside a region every value of the entity's type is treated as +// the borrowed entity (exclusivity by type). +public static class A1AliasOfEntity +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + var same = order; + Protocol.WithApproved(order, approved => + { + same.Annotate("x"); // MUST FAIL + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/A2_entity_through_indexer.cs b/frontend/roslyn/protocol-samples/cases/A2_entity_through_indexer.cs new file mode 100644 index 00000000..bf7ee652 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/A2_entity_through_indexer.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The borrowed entity reached through an indexer -> reject. +// Still no alias analysis: `all[0]` PRODUCES a value of the entity's type, and inside a +// region every such value is treated as the borrowed entity. +public static class A2EntityThroughIndexer +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + var all = new[] { order }; + Protocol.WithApproved(order, approved => + { + all[0].Annotate("x"); // MUST FAIL + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/G6_capability_not_spent.cs b/frontend/roslyn/protocol-samples/cases/G6_capability_not_spent.cs new file mode 100644 index 00000000..8442fc86 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/G6_capability_not_spent.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// KNOWN GAP (not part of this gate): a capability that is never spent. +// Today: OWN001. Expected once tokens are affine: clean. +public static class G6CapabilityNotSpent +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, approved => + { + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L10_region_inside_try.cs b/frontend/roslyn/protocol-samples/cases/L10_region_inside_try.cs new file mode 100644 index 00000000..0f711b86 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L10_region_inside_try.cs @@ -0,0 +1,39 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// Whatever SURROUNDS a region is walked through: try/catch/finally, a loop, a branch, +// a `return` after it. A region is a self-contained unit. +public static class L10RegionInsideTry +{ + public static async Task Run(Db db, int[] ids) + { + foreach (var id in ids) + { + var order = await db.SingleAsync(id); + try + { + if (order.Id > 0) + { + Protocol.WithApproved(order, approved => + { + approved.Ship(); + }); + } + } + catch (InvalidOperationException) + { + return false; + } + finally + { + Audit.Record(order); + } + } + await db.SaveChangesAsync(); + return true; + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L11_region_beside_disposable.cs b/frontend/roslyn/protocol-samples/cases/L11_region_beside_disposable.cs new file mode 100644 index 00000000..97057bfd --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L11_region_beside_disposable.cs @@ -0,0 +1,23 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A method that opens a region AND owns an IDisposable. The two lowerings are independent +// readings of one method (they track disjoint resources), so each gets its own record. +// The stream here is disposed, so both are clean. +public static class L11RegionBesideDisposable +{ + public static void Run(Order order) + { + var log = new MemoryStream(); + log.WriteByte(1); + Protocol.WithApproved(order, approved => + { + approved.Ship(); + }); + log.Dispose(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs b/frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs new file mode 100644 index 00000000..0de6646f --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs @@ -0,0 +1,21 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The same shape with the stream LEAKED: the IDisposable reading still reports it, which +// is the proof that a region in the method does not switch the other analysis off. +public static class L12RegionBesideLeakedDisposable +{ + public static void Run(Order order) + { + var log = new MemoryStream(); + log.WriteByte(1); + Protocol.WithApproved(order, approved => + { + approved.Ship(); + }); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L13_values_captured_into_region.cs b/frontend/roslyn/protocol-samples/cases/L13_values_captured_into_region.cs new file mode 100644 index 00000000..fcb20c69 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L13_values_captured_into_region.cs @@ -0,0 +1,28 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// What a region MAY contain besides transitions: locals captured from outside, literals, +// built-in operators, token reads, `if`. Everything that needs a call is computed before. +public static class L13ValuesCapturedIntoRegion +{ + public static void Run(Order order, int limit) + { + var threshold = limit * 2; + Protocol.WithApproved(order, approved => + { + var over = approved.Id > threshold; + if (over && limit != 0) + { + approved.Ship(); + } + else + { + approved.Ship(); + } + }); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs b/frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs new file mode 100644 index 00000000..581aa5fd --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// 1. stale capability -> reject. +// `draft` is spent by Submit(); using it again is a use of a consumed token. +public static class L1StaleCapability +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithDraft(order, draft => + { + var submitted = draft.Submit(); + draft.Cancel(); // MUST FAIL + submitted.Approve(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L2_copied_capability.cs b/frontend/roslyn/protocol-samples/cases/L2_copied_capability.cs new file mode 100644 index 00000000..37364b39 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L2_copied_capability.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// 2. copied capability -> reject. +// C# copies a struct; the lowering reads the copy as a MOVE, so the source is dead. +public static class L2CopiedCapability +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithDraft(order, draft => + { + var copy = draft; + draft.Cancel(); // MUST FAIL + copy.Cancel(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L3_raw_mutation.cs b/frontend/roslyn/protocol-samples/cases/L3_raw_mutation.cs new file mode 100644 index 00000000..aabe5f63 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L3_raw_mutation.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// 3. raw mutation -> reject. +// The entity is exclusively borrowed for the region; touching it directly is a violation. +public static class L3RawMutation +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, approved => + { + order.Annotate("x"); // MUST FAIL + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L4_raw_escape.cs b/frontend/roslyn/protocol-samples/cases/L4_raw_escape.cs new file mode 100644 index 00000000..d587cbd8 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L4_raw_escape.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// 4. raw escape -> refuse/reject. +// Handing the raw entity to other code inside the region is the same violation. +public static class L4RawEscape +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, approved => + { + Audit.Record(order); // MUST FAIL + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L5_normal_transition.cs b/frontend/roslyn/protocol-samples/cases/L5_normal_transition.cs new file mode 100644 index 00000000..fa9dcb71 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L5_normal_transition.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// 5. normal transition -> clean. +public static class L5NormalTransition +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, approved => + { + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L6_two_transitions.cs b/frontend/roslyn/protocol-samples/cases/L6_two_transitions.cs new file mode 100644 index 00000000..7c244e0f --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L6_two_transitions.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// 6. two transitions -> clean. Draft -> Submitted -> (approved, token spent). +public static class L6TwoTransitions +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithDraft(order, draft => + { + var submitted = draft.Submit(); + submitted.Approve(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L6b_chained_transitions.cs b/frontend/roslyn/protocol-samples/cases/L6b_chained_transitions.cs new file mode 100644 index 00000000..0e7a7ed0 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L6b_chained_transitions.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The same two transitions written as a chain: the intermediate token is a temporary. +public static class L6bChainedTransitions +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithDraft(order, draft => draft.Submit().Approve()); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L7_read_after_region.cs b/frontend/roslyn/protocol-samples/cases/L7_read_after_region.cs new file mode 100644 index 00000000..4ca067d0 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L7_read_after_region.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The entity is free again once the region closes: `return Ok(order)` territory. +public static class L7ReadAfterRegion +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, approved => + { + approved.Ship(); + }); + Audit.Record(order); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L8_branch_inside_region.cs b/frontend/roslyn/protocol-samples/cases/L8_branch_inside_region.cs new file mode 100644 index 00000000..2fb5ebd9 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L8_branch_inside_region.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A transition on one branch only, then again after the merge -> reject (maybe-consumed). +public static class L8BranchInsideRegion +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, approved => + { + if (approved.Id > 0) + { + approved.Ship(); + } + approved.Ship(); // MUST FAIL on the path that already shipped + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/L9_opaque_calls_around_region.cs b/frontend/roslyn/protocol-samples/cases/L9_opaque_calls_around_region.cs new file mode 100644 index 00000000..bebea825 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/L9_opaque_calls_around_region.cs @@ -0,0 +1,26 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The SAME opaque calls that are refused inside a region are ordinary code outside it: +// before the region the entity is not borrowed, after it the borrow is over. +public static class L9OpaqueCallsAroundRegion +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Backdoor.Remember(order); + Backdoor.AnnotateLast(); + var now = DateTime.UtcNow; + Protocol.WithApproved(order, approved => + { + approved.Ship(); + }); + Backdoor.AnnotateLast(); + Console.WriteLine(now); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/X1_nested_region_same_entity.cs b/frontend/roslyn/protocol-samples/cases/X1_nested_region_same_entity.cs new file mode 100644 index 00000000..0d2231c6 --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/X1_nested_region_same_entity.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A second region on the entity that is already borrowed -> reject. +// This is the only way the surface can ASK for a second capability. +public static class X1NestedRegionSameEntity +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, approved => + { + Protocol.WithDraft(order, draft => draft.Cancel()); // MUST FAIL + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/cases/expected.json b/frontend/roslyn/protocol-samples/cases/expected.json new file mode 100644 index 00000000..15a8cb6e --- /dev/null +++ b/frontend/roslyn/protocol-samples/cases/expected.json @@ -0,0 +1,40 @@ +{ + "A1_alias_of_entity": [ + "OWN013" + ], + "A2_entity_through_indexer": [ + "OWN013" + ], + "G6_capability_not_spent": [ + "OWN001" + ], + "L10_region_inside_try": [], + "L11_region_beside_disposable": [], + "L12_region_beside_leaked_disposable": [ + "OWN001" + ], + "L13_values_captured_into_region": [], + "L1_stale_capability": [ + "OWN002" + ], + "L2_copied_capability": [ + "OWN005" + ], + "L3_raw_mutation": [ + "OWN013" + ], + "L4_raw_escape": [ + "OWN013" + ], + "L5_normal_transition": [], + "L6_two_transitions": [], + "L6b_chained_transitions": [], + "L7_read_after_region": [], + "L8_branch_inside_region": [ + "OWN009" + ], + "L9_opaque_calls_around_region": [], + "X1_nested_region_same_entity": [ + "OWN011" + ] +} diff --git a/frontend/roslyn/protocol-samples/does-not-compile/C1_construct_token.cs.txt b/frontend/roslyn/protocol-samples/does-not-compile/C1_construct_token.cs.txt new file mode 100644 index 00000000..4cde527c --- /dev/null +++ b/frontend/roslyn/protocol-samples/does-not-compile/C1_construct_token.cs.txt @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// N2: a second token cannot be minted - the constructor is internal to the API. +public static class C1ConstructToken +{ + public static void Run(Order order) + { + var forged = new ApprovedOrder(order); + forged.Ship(); + } +} diff --git a/frontend/roslyn/protocol-samples/does-not-compile/C2_capture_token_in_nested_lambda.cs.txt b/frontend/roslyn/protocol-samples/does-not-compile/C2_capture_token_in_nested_lambda.cs.txt new file mode 100644 index 00000000..a2644493 --- /dev/null +++ b/frontend/roslyn/protocol-samples/does-not-compile/C2_capture_token_in_nested_lambda.cs.txt @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// N1: a token cannot be carried into ANOTHER region - a ref struct cannot be captured. +public static class C2CaptureToken +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + var other = await db.SingleAsync(id + 1); + Protocol.WithApproved(order, approved => + { + Protocol.WithDraft(other, draft => + { + approved.Ship(); // a token of `order` inside the region of `other` + draft.Cancel(); + }); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/does-not-compile/C3_token_escapes_to_outer_local.cs.txt b/frontend/roslyn/protocol-samples/does-not-compile/C3_token_escapes_to_outer_local.cs.txt new file mode 100644 index 00000000..0bcd4976 --- /dev/null +++ b/frontend/roslyn/protocol-samples/does-not-compile/C3_token_escapes_to_outer_local.cs.txt @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A token cannot outlive its region through an outer variable. +public static class C3TokenEscapes +{ + public static void Run(Order order) + { + ApprovedOrder saved = default; + Protocol.WithApproved(order, approved => + { + saved = approved; + }); + saved.Ship(); + } +} diff --git a/frontend/roslyn/protocol-samples/does-not-compile/C4_token_in_field.cs.txt b/frontend/roslyn/protocol-samples/does-not-compile/C4_token_in_field.cs.txt new file mode 100644 index 00000000..67d6545e --- /dev/null +++ b/frontend/roslyn/protocol-samples/does-not-compile/C4_token_in_field.cs.txt @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A token cannot be stored in an object. +public sealed class C4TokenInField +{ + private ApprovedOrder _kept; +} diff --git a/frontend/roslyn/protocol-samples/does-not-compile/C5_async_region.cs.txt b/frontend/roslyn/protocol-samples/does-not-compile/C5_async_region.cs.txt new file mode 100644 index 00000000..41111b12 --- /dev/null +++ b/frontend/roslyn/protocol-samples/does-not-compile/C5_async_region.cs.txt @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A token cannot survive an await: the callback cannot be async. +public static class C5AsyncRegion +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, async approved => + { + await db.SaveChangesAsync(); + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/does-not-compile/expected.json b/frontend/roslyn/protocol-samples/does-not-compile/expected.json new file mode 100644 index 00000000..455f8401 --- /dev/null +++ b/frontend/roslyn/protocol-samples/does-not-compile/expected.json @@ -0,0 +1,24 @@ +{ + "C1_construct_token": [ + "CS1729", + "CS0122" + ], + "C2_capture_token_in_nested_lambda": [ + "CS8175", + "CS9108" + ], + "C3_token_escapes_to_outer_local": [ + "CS8175", + "CS9108", + "CS4012" + ], + "C4_token_in_field": [ + "CS8345" + ], + "C5_async_region": [ + "CS4012", + "CS1988", + "CS9202", + "CS8177" + ] +} diff --git a/frontend/roslyn/protocol-samples/efcore/.gitignore b/frontend/roslyn/protocol-samples/efcore/.gitignore new file mode 100644 index 00000000..cd42ee34 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/.gitignore @@ -0,0 +1,2 @@ +bin/ +obj/ diff --git a/frontend/roslyn/protocol-samples/efcore/Acceptance/Acceptance.csproj b/frontend/roslyn/protocol-samples/efcore/Acceptance/Acceptance.csproj new file mode 100644 index 00000000..773569a9 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/Acceptance/Acceptance.csproj @@ -0,0 +1,16 @@ + + + + Exe + net8.0 + 12 + enable + enable + OrderBackend.Acceptance + + + + + + + diff --git a/frontend/roslyn/protocol-samples/efcore/Acceptance/Program.cs b/frontend/roslyn/protocol-samples/efcore/Acceptance/Program.cs new file mode 100644 index 00000000..4f023cee --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/Acceptance/Program.cs @@ -0,0 +1,138 @@ +using System.Net; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using OrderBackend; +using OrderBackend.Data; +using OrderBackend.Domain; + +// Backend acceptance: the real backend, over a real HTTP listener and a real SQLite file. +// Exit code 0 only when every check holds. + +var failures = 0; +void Check(string id, bool holds, string detail) +{ + Console.WriteLine($"{(holds ? "ok" : "FAIL")}[{id}]: {detail}"); + if (!holds) + failures++; +} + +var dbPath = Path.Combine(Path.GetTempPath(), $"own-protocol-{Guid.NewGuid():N}.db"); +var sql = new List(); +void Database(DbContextOptionsBuilder options) => options + .UseSqlite($"Data Source={dbPath}") + .LogTo(text => { lock (sql) sql.Add(text); }, + new[] { RelationalEventId.CommandExecuted }); + +AppDbContext FreshContext() +{ + var options = new DbContextOptionsBuilder(); + Database(options); + return new AppDbContext(options.Options); +} + +var app = Backend.Build(new[] { "--urls", "http://127.0.0.1:0" }, Database); +await using (var setup = FreshContext()) + await setup.Database.EnsureCreatedAsync(); +await app.StartAsync(); +try +{ + using var http = new HttpClient { BaseAddress = new Uri(app.Urls.First()) }; + + async Task Create(string customer) + { + var response = await http.PostAsync($"/orders?customer={customer}", null); + response.EnsureSuccessStatusCode(); + return int.Parse(response.Headers.Location!.OriginalString.Split('/')[^1]); + } + + async Task StoredStatus(int id) + { + // a SEPARATE context and connection: what this reads is what was committed + await using var db = FreshContext(); + return (await db.Orders.AsNoTracking().SingleAsync(o => o.Id == id)).Status; + } + + // ---- 1. the happy path over HTTP: Draft -> (Submit, Approve) -> Ship ---------------- + var a = await Create("alice"); + Check("http-created-draft", await StoredStatus(a) == OrderStatus.Draft, + "POST /orders stores a Draft"); + var step = await http.PostAsync($"/orders/{a}/submit-and-approve", null); + Check("http-two-transitions", step.StatusCode == HttpStatusCode.OK + && await StoredStatus(a) == OrderStatus.Approved, + "two transitions inside one region are saved: Draft -> Approved"); + step = await http.PostAsync($"/orders/{a}/ship", null); + Check("http-ship", step.StatusCode == HttpStatusCode.OK + && await StoredStatus(a) == OrderStatus.Shipped, + "POST /orders/{id}/ship commits Shipped inside the handler's transaction"); + + // ---- 2. the runtime refinement refuses the wrong state, and nothing is written ------- + var b = await Create("bob"); + step = await http.PostAsync($"/orders/{b}/ship", null); + Check("http-ship-refused", step.StatusCode == HttpStatusCode.Conflict + && await StoredStatus(b) == OrderStatus.Draft, + "shipping a Draft is 409 (the region entry's check), and the row is untouched"); + step = await http.PostAsync($"/orders/{a}/submit-and-approve", null); + Check("http-resubmit-refused", step.StatusCode == HttpStatusCode.Conflict + && await StoredStatus(a) == OrderStatus.Shipped, + "submitting a Shipped order is 409, and the row is untouched"); + step = await http.PostAsync("/orders/999999/ship", null); + Check("http-missing", step.StatusCode == HttpStatusCode.NotFound, "an unknown id is 404"); + + // ---- 3. the token mutates the instance EF tracks ----------------------------------- + var c = await Create("carol"); + (await http.PostAsync($"/orders/{c}/submit-and-approve", null)).EnsureSuccessStatusCode(); + await using (var db = FreshContext()) + { + var order = await db.Orders.SingleAsync(o => o.Id == c); + var entry = db.ChangeTracker.Entries().Single(); + Check("ef-same-instance", ReferenceEquals(entry.Entity, order), + "the queried Order IS the instance the ChangeTracker holds"); + Check("ef-unchanged-before", entry.State == EntityState.Unchanged, + "it is Unchanged before the region"); + + var now = DateTime.UtcNow; + OrderProtocol.WithApproved(order, approved => + { + approved.Ship(now); + }); + + db.ChangeTracker.DetectChanges(); + Check("ef-change-tracked", entry.State == EntityState.Modified + && entry.Property(o => o.Status).IsModified + && entry.Property(o => o.ShippedAt).IsModified + && !entry.Property(o => o.Customer).IsModified, + "the transition is visible to the ChangeTracker as Status + ShippedAt, nothing else"); + Check("ef-no-reattach", db.ChangeTracker.Entries().Count() == 1, + "no second entry appeared: nothing was attached, copied or re-materialized"); + var written = await db.SaveChangesAsync(); + Check("ef-saved", written == 1 && await StoredStatus(c) == OrderStatus.Shipped, + "SaveChangesAsync writes one row and a separate context reads Shipped"); + } + + // ---- 4. plain EF queries: translated by the provider, nothing custom ---------------- + await using (var db = FreshContext()) + { + var text = db.Orders.Where(o => o.Id == c).ToQueryString(); + Check("ef-query-translated", text.Contains("WHERE", StringComparison.Ordinal) + && text.Contains("\"Id\"", StringComparison.Ordinal), + "the handler's predicate is a server-side WHERE on Id"); + } + string[] executed; + lock (sql) + executed = sql.ToArray(); + Check("ef-update-emitted", executed.Any(t => t.Contains("UPDATE \"Orders\" SET", StringComparison.Ordinal) + && t.Contains("\"Status\"", StringComparison.Ordinal)), + "the transitions reach the database as ordinary UPDATE statements"); +} +finally +{ + await app.StopAsync(); + await app.DisposeAsync(); + Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools(); + try { File.Delete(dbPath); } catch (IOException) { } +} + +Console.WriteLine(failures == 0 + ? "backend acceptance: all checks hold" + : $"backend acceptance: {failures} check(s) FAILED"); +return failures == 0 ? 0 : 1; diff --git a/frontend/roslyn/protocol-samples/efcore/OrderBackend/Data/AppDbContext.cs b/frontend/roslyn/protocol-samples/efcore/OrderBackend/Data/AppDbContext.cs new file mode 100644 index 00000000..f2c39a86 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/OrderBackend/Data/AppDbContext.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore; +using OrderBackend.Domain; + +namespace OrderBackend.Data; + +/// A plain DbContext: no custom base, no repository, no interceptor. +public sealed class AppDbContext(DbContextOptions options) : DbContext(options) +{ + public DbSet Orders => Set(); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(order => + { + order.HasKey(o => o.Id); + order.Property(o => o.Status).HasConversion(); + }); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/Order.cs b/frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/Order.cs new file mode 100644 index 00000000..b04e0bf2 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/Order.cs @@ -0,0 +1,55 @@ +using System; + +namespace OrderBackend.Domain; + +public enum OrderStatus +{ + Draft, + Submitted, + Approved, + Shipped, +} + +/// An ordinary EF Core entity: no base class, no interface, no attribute. EF materializes it +/// through the private constructor and tracks THIS instance; the state tokens in +/// OrderProtocol.cs wrap the same reference and mutate it in place. +public sealed class Order +{ + private Order() + { + } + + public int Id { get; private set; } + + public string Customer { get; private set; } = ""; + + public OrderStatus Status { get; private set; } + + public DateTime? SubmittedAt { get; private set; } + + public DateTime? ApprovedAt { get; private set; } + + public DateTime? ShippedAt { get; private set; } + + public static Order NewDraft(string customer) => + new() { Customer = customer, Status = OrderStatus.Draft }; + + // The transitions themselves. Reachable only through a state token (same assembly). + internal void MarkSubmitted(DateTime at) + { + Status = OrderStatus.Submitted; + SubmittedAt = at; + } + + internal void MarkApproved(DateTime at) + { + Status = OrderStatus.Approved; + ApprovedAt = at; + } + + internal void MarkShipped(DateTime at) + { + Status = OrderStatus.Shipped; + ShippedAt = at; + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs b/frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs new file mode 100644 index 00000000..12c45d76 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs @@ -0,0 +1,102 @@ +using System; + +namespace OrderBackend.Domain; + +// The state protocol of Order, written by hand (a source generator could emit this file; +// none exists yet, and the profile does not need one). +// +// No reflection, no base class, no runtime library: two marker attributes, three ref +// structs, three delegates, three region entries. + +[AttributeUsage(AttributeTargets.Struct)] +public sealed class ProtocolTokenAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Method)] +public sealed class ProtocolRegionAttribute : Attribute +{ +} + +/// The runtime half of the refinement: the fact came from the database, so it is checked +/// once, at the region entry. +public sealed class InvalidOrderStateException(int id, OrderStatus actual, OrderStatus required) + : InvalidOperationException($"order {id} is {actual}, not {required}") +{ +} + +[ProtocolToken] +public readonly ref struct DraftOrder +{ + private readonly Order _order; + + internal DraftOrder(Order order) => _order = order; + + public int Id => _order.Id; + + public SubmittedOrder Submit(DateTime at) + { + _order.MarkSubmitted(at); + return new SubmittedOrder(_order); + } +} + +[ProtocolToken] +public readonly ref struct SubmittedOrder +{ + private readonly Order _order; + + internal SubmittedOrder(Order order) => _order = order; + + public int Id => _order.Id; + + public void Approve(DateTime at) => _order.MarkApproved(at); +} + +[ProtocolToken] +public readonly ref struct ApprovedOrder +{ + private readonly Order _order; + + internal ApprovedOrder(Order order) => _order = order; + + public int Id => _order.Id; + + public void Ship(DateTime at) => _order.MarkShipped(at); +} + +public delegate void DraftRegion(DraftOrder draft); + +public delegate void SubmittedRegion(SubmittedOrder submitted); + +public delegate void ApprovedRegion(ApprovedOrder approved); + +public static class OrderProtocol +{ + [ProtocolRegion] + public static void WithDraft(Order order, DraftRegion body) + { + Require(order, OrderStatus.Draft); + body(new DraftOrder(order)); + } + + [ProtocolRegion] + public static void WithSubmitted(Order order, SubmittedRegion body) + { + Require(order, OrderStatus.Submitted); + body(new SubmittedOrder(order)); + } + + [ProtocolRegion] + public static void WithApproved(Order order, ApprovedRegion body) + { + Require(order, OrderStatus.Approved); + body(new ApprovedOrder(order)); + } + + private static void Require(Order order, OrderStatus required) + { + if (order.Status != required) + throw new InvalidOrderStateException(order.Id, order.Status, required); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderBackend.csproj b/frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderBackend.csproj new file mode 100644 index 00000000..e7903e27 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderBackend.csproj @@ -0,0 +1,15 @@ + + + + net8.0 + 12 + enable + enable + OrderBackend + + + + + + + diff --git a/frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs b/frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs new file mode 100644 index 00000000..9508e731 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs @@ -0,0 +1,91 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.EntityFrameworkCore; +using OrderBackend.Data; +using OrderBackend.Domain; + +namespace OrderBackend; + +/// The endpoints. Ordinary ASP.NET Core + EF Core code: there is no annotation in this file, +/// and nothing here knows that an analyzer exists. +public static class OrderHandlers +{ + public static async Task Create(string customer, AppDbContext db, CancellationToken ct) + { + var order = Order.NewDraft(customer); + db.Orders.Add(order); + await db.SaveChangesAsync(ct); + return Results.Created($"/orders/{order.Id}", new { order.Id, Status = order.Status.ToString() }); + } + + public static async Task Ship( + int id, + AppDbContext db, + ILogger logger, + CancellationToken ct) + { + await using var tx = await db.Database.BeginTransactionAsync(ct); + + var order = await db.Orders.SingleOrDefaultAsync(x => x.Id == id, ct); + if (order is null) + return Results.NotFound(); + + // Everything that needs a call is done OUTSIDE the region: the clock is read here + // and captured, the log lines sit before and after. + var now = DateTime.UtcNow; + logger.LogInformation("shipping order {OrderId}", order.Id); + try + { + OrderProtocol.WithApproved(order, approved => + { + approved.Ship(now); + }); + } + catch (InvalidOrderStateException refused) + { + return Results.Conflict(refused.Message); + } + + await db.SaveChangesAsync(ct); + await tx.CommitAsync(ct); + logger.LogInformation("shipped order {OrderId}", order.Id); + + return Results.Ok(new { order.Id, Status = order.Status.ToString() }); + } + + public static async Task SubmitAndApprove(int id, AppDbContext db, CancellationToken ct) + { + var order = await db.Orders.SingleOrDefaultAsync(x => x.Id == id, ct); + if (order is null) + return Results.NotFound(); + + var now = DateTime.UtcNow; + try + { + // two transitions inside ONE region: Draft -> Submitted -> Approved + OrderProtocol.WithDraft(order, draft => + { + var submitted = draft.Submit(now); + submitted.Approve(now); + }); + } + catch (InvalidOrderStateException refused) + { + return Results.Conflict(refused.Message); + } + + await db.SaveChangesAsync(ct); + return Results.Ok(new { order.Id, Status = order.Status.ToString() }); + } + + public static async Task Get(int id, AppDbContext db, CancellationToken ct) + { + var order = await db.Orders.AsNoTracking().SingleOrDefaultAsync(x => x.Id == id, ct); + return order is null + ? Results.NotFound() + : Results.Ok(new { order.Id, Status = order.Status.ToString(), order.ShippedAt }); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/OrderBackend/Program.cs b/frontend/roslyn/protocol-samples/efcore/OrderBackend/Program.cs new file mode 100644 index 00000000..f6677b8c --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/OrderBackend/Program.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore; +using OrderBackend; +using OrderBackend.Data; + +var app = Backend.Build(args, options => + options.UseSqlite("Data Source=orders.db")); + +using (var scope = app.Services.CreateScope()) + scope.ServiceProvider.GetRequiredService().Database.EnsureCreated(); + +app.Run(); + +public partial class Program +{ +} + +namespace OrderBackend +{ + /// The composition root, shared by `Program` and the acceptance runner so both serve + /// exactly the same endpoints over a real HTTP listener. + public static class Backend + { + public static WebApplication Build(string[] args, Action database) + { + var builder = WebApplication.CreateBuilder(args); + builder.Services.AddDbContext(database); + + var app = builder.Build(); + app.MapPost("/orders", OrderHandlers.Create); + app.MapGet("/orders/{id:int}", OrderHandlers.Get); + app.MapPost("/orders/{id:int}/submit-and-approve", OrderHandlers.SubmitAndApprove); + app.MapPost("/orders/{id:int}/ship", OrderHandlers.Ship); + return app; + } + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/accepted/MentionsOnly.cs.txt b/frontend/roslyn/protocol-samples/efcore/accepted/MentionsOnly.cs.txt new file mode 100644 index 00000000..fcf2e12f --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/accepted/MentionsOnly.cs.txt @@ -0,0 +1,22 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using OrderBackend.Data; +using OrderBackend.Domain; + +namespace OrderBackend.Accepted; + +// The boundary refuses OPERATIONS, not mentions. Naming the internal mutator, naming the +// token type and reading the state change nothing, so nothing here is refused. +public static class MentionsOnly +{ + public static async Task Describe(int id, AppDbContext db, CancellationToken ct) + { + var order = await db.Orders.AsNoTracking().SingleAsync(x => x.Id == id, ct); + var transition = nameof(Order.MarkShipped); + var token = typeof(ApprovedOrder).Name; + return Results.Ok(new { order.Id, order.Status, transition, token }); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/accepted/expected.json b/frontend/roslyn/protocol-samples/efcore/accepted/expected.json new file mode 100644 index 00000000..13c59475 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/accepted/expected.json @@ -0,0 +1,3 @@ +{ + "MentionsOnly": "nameof / typeof / a read of the state: mentions, not operations" +} diff --git a/frontend/roslyn/protocol-samples/efcore/known-gaps/StateWrittenByBulkUpdate.cs.txt b/frontend/roslyn/protocol-samples/efcore/known-gaps/StateWrittenByBulkUpdate.cs.txt new file mode 100644 index 00000000..47842942 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/known-gaps/StateWrittenByBulkUpdate.cs.txt @@ -0,0 +1,23 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using OrderBackend.Data; +using OrderBackend.Domain; + +namespace OrderBackend.KnownGaps; + +// KNOWN GAP, pinned: a set-based UPDATE never materializes an Order at all, so there is no +// instance for a token to guard. The row changes state in the database. +public static class StateWrittenByBulkUpdate +{ + public static async Task Ship(int id, AppDbContext db, CancellationToken ct) + { + await db.Orders + .Where(o => o.Id == id) + .ExecuteUpdateAsync(s => s.SetProperty(o => o.Status, OrderStatus.Shipped), ct); + return Results.Ok(); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/known-gaps/StateWrittenThroughChangeTracker.cs.txt b/frontend/roslyn/protocol-samples/efcore/known-gaps/StateWrittenThroughChangeTracker.cs.txt new file mode 100644 index 00000000..12ab7577 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/known-gaps/StateWrittenThroughChangeTracker.cs.txt @@ -0,0 +1,24 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using OrderBackend.Data; +using OrderBackend.Domain; + +namespace OrderBackend.KnownGaps; + +// KNOWN GAP, pinned so it cannot be forgotten: EF Core's own metadata API writes the state +// property by NAME, through its public surface. No member of Order is touched in source, no +// token exists, no region is open — and a Draft is saved as Shipped. The protocol constrains +// the entity's C# API, not every path to the row. +public static class StateWrittenThroughChangeTracker +{ + public static async Task Ship(int id, AppDbContext db, CancellationToken ct) + { + var order = await db.Orders.SingleAsync(x => x.Id == id, ct); + db.Entry(order).Property(o => o.Status).CurrentValue = OrderStatus.Shipped; + await db.SaveChangesAsync(ct); + return Results.Ok(); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/known-gaps/expected.json b/frontend/roslyn/protocol-samples/efcore/known-gaps/expected.json new file mode 100644 index 00000000..7b47eab3 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/known-gaps/expected.json @@ -0,0 +1,4 @@ +{ + "StateWrittenByBulkUpdate": "ExecuteUpdate: no entity instance exists for a token to guard", + "StateWrittenThroughChangeTracker": "EF metadata API writes the state property by name through public surface" +} diff --git a/frontend/roslyn/protocol-samples/efcore/nuget.config b/frontend/roslyn/protocol-samples/efcore/nuget.config new file mode 100644 index 00000000..88397e92 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/nuget.config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/roslyn/protocol-samples/efcore/refused/DirectMutator.cs.txt b/frontend/roslyn/protocol-samples/efcore/refused/DirectMutator.cs.txt new file mode 100644 index 00000000..4dc11fd7 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/refused/DirectMutator.cs.txt @@ -0,0 +1,22 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using OrderBackend.Data; +using OrderBackend.Domain; + +namespace OrderBackend.Refused; + +// The transition's own implementation, called past every token: `internal` is open inside +// the project. A Draft becomes Shipped and EF saves it. +public static class DirectMutator +{ + public static async Task Ship(int id, AppDbContext db, CancellationToken ct) + { + var order = await db.Orders.SingleAsync(x => x.Id == id, ct); + order.MarkShipped(DateTime.UtcNow); + await db.SaveChangesAsync(ct); + return Results.Ok(); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/refused/ForgedToken.cs.txt b/frontend/roslyn/protocol-samples/efcore/refused/ForgedToken.cs.txt new file mode 100644 index 00000000..8c8ca8ac --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/refused/ForgedToken.cs.txt @@ -0,0 +1,24 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using OrderBackend.Data; +using OrderBackend.Domain; + +namespace OrderBackend.Refused; + +// The domain sits in the SAME project as the handlers, so the token's `internal` constructor +// is reachable: this ships an order whose state nobody checked, in a handler with no region. +// The compiler accepts it; the scan must not. +public static class ForgedToken +{ + public static async Task Ship(int id, AppDbContext db, CancellationToken ct) + { + var order = await db.Orders.SingleAsync(x => x.Id == id, ct); + var now = DateTime.UtcNow; + new ApprovedOrder(order).Ship(now); + await db.SaveChangesAsync(ct); + return Results.Ok(); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/refused/MutatorAsDelegate.cs.txt b/frontend/roslyn/protocol-samples/efcore/refused/MutatorAsDelegate.cs.txt new file mode 100644 index 00000000..401fe9ba --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/refused/MutatorAsDelegate.cs.txt @@ -0,0 +1,22 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using OrderBackend.Data; +using OrderBackend.Domain; + +namespace OrderBackend.Refused; + +// The same bypass with no call written at the entity: the mutator leaves as a delegate. +public static class MutatorAsDelegate +{ + public static async Task Ship(int id, AppDbContext db, CancellationToken ct) + { + var order = await db.Orders.SingleAsync(x => x.Id == id, ct); + Action ship = order.MarkShipped; + ship(DateTime.UtcNow); + await db.SaveChangesAsync(ct); + return Results.Ok(); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/refused/SaveInsideRegion.cs.txt b/frontend/roslyn/protocol-samples/efcore/refused/SaveInsideRegion.cs.txt new file mode 100644 index 00000000..e0ae047f --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/refused/SaveInsideRegion.cs.txt @@ -0,0 +1,27 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using OrderBackend.Data; +using OrderBackend.Domain; + +namespace OrderBackend.Refused; + +// Saving from INSIDE the region: `SaveChanges` runs the whole EF pipeline (interceptors, +// change detection over the entity the region holds exclusively). Nothing states what that +// does to the entity, so the region is refused; the same call after the region is ordinary. +public static class SaveInsideRegion +{ + public static async Task Ship(int id, AppDbContext db, CancellationToken ct) + { + var order = await db.Orders.SingleAsync(x => x.Id == id, ct); + var now = DateTime.UtcNow; + OrderProtocol.WithApproved(order, approved => + { + approved.Ship(now); + db.SaveChanges(); + }); + return Results.Ok(); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/refused/ShipWithLogInsideRegion.cs.txt b/frontend/roslyn/protocol-samples/efcore/refused/ShipWithLogInsideRegion.cs.txt new file mode 100644 index 00000000..2d10fe16 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/refused/ShipWithLogInsideRegion.cs.txt @@ -0,0 +1,33 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.EntityFrameworkCore; +using OrderBackend.Data; +using OrderBackend.Domain; + +namespace OrderBackend.Refused; + +// The same logging call that is fine before and after the region (see OrderHandlers.Ship) +// is REFUSED inside it: nothing states what `LogInformation` does, and an exclusive region +// does not analyse unprovable code as safe. +public static class ShipWithLogInsideRegion +{ + public static async Task Ship( + int id, + AppDbContext db, + ILogger logger, + CancellationToken ct) + { + var order = await db.Orders.SingleAsync(x => x.Id == id, ct); + var now = DateTime.UtcNow; + OrderProtocol.WithApproved(order, approved => + { + logger.LogInformation("shipping inside the region"); + approved.Ship(now); + }); + await db.SaveChangesAsync(ct); + return Results.Ok(); + } +} diff --git a/frontend/roslyn/protocol-samples/efcore/refused/expected.json b/frontend/roslyn/protocol-samples/efcore/refused/expected.json new file mode 100644 index 00000000..8d1af494 --- /dev/null +++ b/frontend/roslyn/protocol-samples/efcore/refused/expected.json @@ -0,0 +1,7 @@ +{ + "DirectMutator": "'MarkShipped' of 'Order' is not public and belongs to a state protocol", + "ForgedToken": "a protocol token 'ApprovedOrder' is created outside the protocol's own types", + "MutatorAsDelegate": "'MarkShipped' of 'Order' is not public and belongs to a state protocol", + "SaveInsideRegion": "a call to 'Microsoft.EntityFrameworkCore.DbContext.SaveChanges' inside a protocol region runs code with no stated contract", + "ShipWithLogInsideRegion": "a call to 'Microsoft.Extensions.Logging.LoggerExtensions.LogInformation' inside a protocol region runs code with no stated contract" +} diff --git a/frontend/roslyn/protocol-samples/refused/R10_property_getter_inside_region.cs.txt b/frontend/roslyn/protocol-samples/refused/R10_property_getter_inside_region.cs.txt new file mode 100644 index 00000000..a4beb2dc --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R10_property_getter_inside_region.cs.txt @@ -0,0 +1,20 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A property getter is a call too: `DateTime.UtcNow` runs code the lowering cannot read. +// Compute it BEFORE the region and capture the value. +public static class R10PropertyGetterInsideRegion +{ + public static void Run(Order order) + { + Protocol.WithApproved(order, approved => + { + var now = DateTime.UtcNow; + approved.Ship(); + }); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R11_constructor_inside_region.cs.txt b/frontend/roslyn/protocol-samples/refused/R11_constructor_inside_region.cs.txt new file mode 100644 index 00000000..84ffef28 --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R11_constructor_inside_region.cs.txt @@ -0,0 +1,19 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A constructor is a call as well. +public static class R11ConstructorInsideRegion +{ + public static void Run(Order order) + { + Protocol.WithApproved(order, approved => + { + var buffer = new MemoryStream(); + approved.Ship(); + }); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R12_default_token_temporary.cs.txt b/frontend/roslyn/protocol-samples/refused/R12_default_token_temporary.cs.txt new file mode 100644 index 00000000..ea8e2c9d --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R12_default_token_temporary.cs.txt @@ -0,0 +1,13 @@ +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// No region, no token local: the forged token is a temporary. `default` compiles from any +// assembly, so only the lowering can refuse it — in a method it otherwise has no reason to read. +public static class R12DefaultTokenTemporary +{ + public static void Run(Order order) + { + default(ApprovedOrder).Ship(); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R13_public_mutator_reaches_protocol_state.cs.txt b/frontend/roslyn/protocol-samples/refused/R13_public_mutator_reaches_protocol_state.cs.txt new file mode 100644 index 00000000..cb3ed4fc --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R13_public_mutator_reaches_protocol_state.cs.txt @@ -0,0 +1,44 @@ +using System; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// ADMISSION. The token's transition and a PUBLIC method of the entity reach the same write. +// The public one needs no token, so every guarantee of the region is optional: the protocol +// is refused as declared, wherever it is (or is not) used. +public sealed class Doc +{ + public bool Published { get; private set; } + + internal void PublishCore() => Published = true; + + public void Publish() => PublishCore(); // the open door +} + +[ProtocolToken] +public readonly ref struct DraftDoc +{ + private readonly Doc _doc; + internal DraftDoc(Doc doc) => _doc = doc; + + public void Publish() => _doc.PublishCore(); +} + +public delegate void DraftDocRegion(DraftDoc draft); + +public static class DocProtocol +{ + [ProtocolRegion] + public static void WithDraft(Doc doc, DraftDocRegion body) => body(new DraftDoc(doc)); +} + +public static class R13PublicMutatorReachesProtocolState +{ + public static void Run(Doc doc) + { + DocProtocol.WithDraft(doc, draft => + { + draft.Publish(); + }); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R14_public_setter_of_protocol_state.cs.txt b/frontend/roslyn/protocol-samples/refused/R14_public_setter_of_protocol_state.cs.txt new file mode 100644 index 00000000..aad4c58c --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R14_public_setter_of_protocol_state.cs.txt @@ -0,0 +1,28 @@ +using System; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// ADMISSION, the plain form: the state a transition writes has a public setter. Nothing in +// this file even opens a region; the declaration alone is what is refused. +public sealed class Ticket +{ + public int State { get; set; } // the open door +} + +[ProtocolToken] +public readonly ref struct OpenTicket +{ + private readonly Ticket _ticket; + internal OpenTicket(Ticket ticket) => _ticket = ticket; + + public void Close() => _ticket.State = 2; +} + +public delegate void OpenTicketRegion(OpenTicket open); + +public static class TicketProtocol +{ + [ProtocolRegion] + public static void WithOpen(Ticket ticket, OpenTicketRegion body) => body(new OpenTicket(ticket)); +} diff --git a/frontend/roslyn/protocol-samples/refused/R15_region_opened_inside_protocol_type.cs.txt b/frontend/roslyn/protocol-samples/refused/R15_region_opened_inside_protocol_type.cs.txt new file mode 100644 index 00000000..1fd6885c --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R15_region_opened_inside_protocol_type.cs.txt @@ -0,0 +1,41 @@ +using System; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The types that DECLARE a protocol are trusted: their bodies are the protocol, and the +// lowering does not read them as user code. A handler written in the same class as the +// region entry it calls would therefore never be analysed — and this one spends a token +// twice. It is refused, not skipped: an unanalysed region must not read as a clean one. +public sealed class Parcel +{ + public bool Sent { get; private set; } + + internal void MarkSent() => Sent = true; +} + +[ProtocolToken] +public readonly ref struct PackedParcel +{ + private readonly Parcel _parcel; + internal PackedParcel(Parcel parcel) => _parcel = parcel; + + public void Send() => _parcel.MarkSent(); +} + +public delegate void PackedParcelRegion(PackedParcel packed); + +public static class ParcelHandlers +{ + [ProtocolRegion] + public static void WithPacked(Parcel parcel, PackedParcelRegion body) => body(new PackedParcel(parcel)); + + public static void Dispatch(Parcel parcel) + { + WithPacked(parcel, packed => + { + packed.Send(); + packed.Send(); // a stale token: OWN002 anywhere else + }); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R1_default_token.cs.txt b/frontend/roslyn/protocol-samples/refused/R1_default_token.cs.txt new file mode 100644 index 00000000..adbe9bf9 --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R1_default_token.cs.txt @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// `default` compiles for any struct, so the language cannot stop this forgery. +// The lowering must: a token may only come from a region entry, a transition, or a copy. +public static class R1DefaultToken +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, approved => + { + ApprovedOrder forged = default; + forged.Ship(); + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R2_token_outside_region.cs.txt b/frontend/roslyn/protocol-samples/refused/R2_token_outside_region.cs.txt new file mode 100644 index 00000000..4dd96130 --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R2_token_outside_region.cs.txt @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A token-typed local outside any region has no region to belong to. +public static class R2TokenOutsideRegion +{ + public static void Run(Order order) + { + ApprovedOrder forged = default; + forged.Ship(); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R3_return_inside_region.cs.txt b/frontend/roslyn/protocol-samples/refused/R3_return_inside_region.cs.txt new file mode 100644 index 00000000..425092b9 --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R3_return_inside_region.cs.txt @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// `return` inside the callback leaves the region, not the method; not modelled -> refused. +public static class R3ReturnInsideRegion +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, approved => + { + if (approved.Id == 0) + { + return; + } + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R4_loop_inside_region.cs.txt b/frontend/roslyn/protocol-samples/refused/R4_loop_inside_region.cs.txt new file mode 100644 index 00000000..4349dfe8 --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R4_loop_inside_region.cs.txt @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A loop inside a region is not modelled -> refused, never silently skipped. +public static class R4LoopInsideRegion +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Protocol.WithApproved(order, approved => + { + for (var i = 0; i < 2; i++) + { + Audit.Record(new Order()); + } + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R5_token_passed_to_helper.cs.txt b/frontend/roslyn/protocol-samples/refused/R5_token_passed_to_helper.cs.txt new file mode 100644 index 00000000..0c075e68 --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R5_token_passed_to_helper.cs.txt @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A token handed to another method: tokens do not cross method boundaries in this profile. +public static class R5TokenPassedToHelper +{ + private static void Finish(ApprovedOrder approved) => approved.Ship(); + + public static void Run(Order order) + { + Protocol.WithApproved(order, approved => + { + Finish(approved); + }); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R6_region_body_not_a_lambda.cs.txt b/frontend/roslyn/protocol-samples/refused/R6_region_body_not_a_lambda.cs.txt new file mode 100644 index 00000000..2a127c1d --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R6_region_body_not_a_lambda.cs.txt @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The region body must be written in place, or there is no block to lower. +public static class R6RegionBodyNotALambda +{ + private static void Body(ApprovedOrder approved) => approved.Ship(); + + public static void Run(Order order) + { + Protocol.WithApproved(order, Body); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R7_entity_not_a_local.cs.txt b/frontend/roslyn/protocol-samples/refused/R7_entity_not_a_local.cs.txt new file mode 100644 index 00000000..35a45863 --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R7_entity_not_a_local.cs.txt @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The entity must be a local or a parameter: that symbol IS the resource identity. +public static class R7EntityNotALocal +{ + public static void Run(Db db) + { + Protocol.WithApproved(db.SingleAsync(1).Result, approved => + { + approved.Ship(); + }); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R8_token_not_a_ref_struct.cs.txt b/frontend/roslyn/protocol-samples/refused/R8_token_not_a_ref_struct.cs.txt new file mode 100644 index 00000000..4d6ac175 --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R8_token_not_a_ref_struct.cs.txt @@ -0,0 +1,32 @@ +using System; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A token type that is NOT a ref struct could be captured, stored or awaited across, and so +// reach another region. The language only forbids that for ref structs; the lowering refuses +// anything weaker. +[ProtocolToken] +public readonly struct LooseToken +{ + public void Spend() { } +} + +public delegate void LooseRegion(LooseToken token); + +public static class LooseProtocol +{ + [ProtocolRegion] + public static void With(Order order, LooseRegion body) => body(default); +} + +public static class R8TokenNotARefStruct +{ + public static void Run(Order order) + { + LooseProtocol.With(order, token => + { + token.Spend(); + }); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/R9_opaque_call_inside_region.cs.txt b/frontend/roslyn/protocol-samples/refused/R9_opaque_call_inside_region.cs.txt new file mode 100644 index 00000000..ce673b80 --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/R9_opaque_call_inside_region.cs.txt @@ -0,0 +1,25 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// A call inside the region that never mentions the entity, and mutates it anyway. +// Nothing at the call site can be lowered, so nothing proves the call harmless - and an +// exclusive region does not analyse unprovable code as safe. REFUSED, never clean. +// (When effect summaries can prove a callee harmless, this is the rule they relax.) +public static class R9OpaqueCallInsideRegion +{ + public static async Task Run(Db db, int id) + { + var order = await db.SingleAsync(id); + Backdoor.Remember(order); + Protocol.WithApproved(order, approved => + { + Backdoor.AnnotateLast(); // mutates `order`; nothing here says so + approved.Ship(); + }); + await db.SaveChangesAsync(); + } +} diff --git a/frontend/roslyn/protocol-samples/refused/expected.json b/frontend/roslyn/protocol-samples/refused/expected.json new file mode 100644 index 00000000..06d8a698 --- /dev/null +++ b/frontend/roslyn/protocol-samples/refused/expected.json @@ -0,0 +1,17 @@ +{ + "R10_property_getter_inside_region": "property 'UtcNow' inside a protocol region runs code with no stated contract", + "R11_constructor_inside_region": "a constructor call inside a protocol region runs code with no stated contract", + "R12_default_token_temporary": "a protocol token 'ApprovedOrder' is created outside the protocol's own types", + "R13_public_mutator_reaches_protocol_state": "'Doc.Publish' is public and writes 'Published', state the protocol's transitions own", + "R14_public_setter_of_protocol_state": "'Ticket.State' is public and writes 'State', state the protocol's transitions own", + "R15_region_opened_inside_protocol_type": "a protocol region is opened inside 'ParcelHandlers', one of the protocol's own types", + "R1_default_token": "has no lowerable origin", + "R2_token_outside_region": "is declared outside a protocol region", + "R3_return_inside_region": "`return` inside a protocol region", + "R4_loop_inside_region": "ForStatement inside a protocol region is not modelled", + "R5_token_passed_to_helper": "a token does not cross a method boundary", + "R6_region_body_not_a_lambda": "must be a lambda written in place", + "R7_entity_not_a_local": "must be a local or a parameter", + "R8_token_not_a_ref_struct": "must be a ref struct", + "R9_opaque_call_inside_region": "a call to 'Own.Protocols.Sample.Backdoor.AnnotateLast' inside a protocol region runs code with no stated contract" +} diff --git a/frontend/roslyn/protocol-samples/same-assembly/S1_forged_token.cs.txt b/frontend/roslyn/protocol-samples/same-assembly/S1_forged_token.cs.txt new file mode 100644 index 00000000..5f0e7362 --- /dev/null +++ b/frontend/roslyn/protocol-samples/same-assembly/S1_forged_token.cs.txt @@ -0,0 +1,13 @@ +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// In the protocol's OWN assembly the `internal` constructor is reachable: a token for a state +// nobody checked, spent in a method with no region at all. +public static class S1ForgedToken +{ + public static void Run(Order order) + { + new ApprovedOrder(order).Ship(); + } +} diff --git a/frontend/roslyn/protocol-samples/same-assembly/S2_internal_setter.cs.txt b/frontend/roslyn/protocol-samples/same-assembly/S2_internal_setter.cs.txt new file mode 100644 index 00000000..f0f27831 --- /dev/null +++ b/frontend/roslyn/protocol-samples/same-assembly/S2_internal_setter.cs.txt @@ -0,0 +1,15 @@ +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The state itself, written past every token: `internal set` is open inside the assembly. +// Reading the same property stays ordinary. +public static class S2InternalSetter +{ + public static bool Run(Order order) + { + var wasDraft = order.Status == OrderStatus.Draft; + order.Status = OrderStatus.Shipped; + return wasDraft; + } +} diff --git a/frontend/roslyn/protocol-samples/same-assembly/S3_object_initializer.cs.txt b/frontend/roslyn/protocol-samples/same-assembly/S3_object_initializer.cs.txt new file mode 100644 index 00000000..22976f6e --- /dev/null +++ b/frontend/roslyn/protocol-samples/same-assembly/S3_object_initializer.cs.txt @@ -0,0 +1,12 @@ +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// An entity born in a state no transition produced. +public static class S3ObjectInitializer +{ + public static Order Run() + { + return new Order { Status = OrderStatus.Shipped }; + } +} diff --git a/frontend/roslyn/protocol-samples/same-assembly/S4_read_only_use.cs.txt b/frontend/roslyn/protocol-samples/same-assembly/S4_read_only_use.cs.txt new file mode 100644 index 00000000..f9f408bc --- /dev/null +++ b/frontend/roslyn/protocol-samples/same-assembly/S4_read_only_use.cs.txt @@ -0,0 +1,15 @@ +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The control: the same assembly, the same entity, only its PUBLIC surface — reads of the +// state, the public factory, the public `Annotate`. Nothing to refuse. +public static class S4ReadOnlyUse +{ + public static bool Run(int id) + { + var order = Order.Load(id); + order.Annotate("seen"); + return order.Status == OrderStatus.Draft && order.Id == id && order.Note == "seen"; + } +} diff --git a/frontend/roslyn/protocol-samples/same-assembly/S5_mentions_are_not_operations.cs.txt b/frontend/roslyn/protocol-samples/same-assembly/S5_mentions_are_not_operations.cs.txt new file mode 100644 index 00000000..05ee5442 --- /dev/null +++ b/frontend/roslyn/protocol-samples/same-assembly/S5_mentions_are_not_operations.cs.txt @@ -0,0 +1,14 @@ +using Own.Protocols.Sample; + +namespace Own.Protocols.Cases; + +// The control for the other direction: the same assembly, and the protocol's non-public +// surface only MENTIONED — a name, a type, a read. Nothing changes state, nothing is refused. +public static class S5MentionsAreNotOperations +{ + public static string Run(Order order) + { + var state = order.Status; + return nameof(Order.Status) + nameof(ApprovedOrder) + typeof(DraftOrder).Name + state; + } +} diff --git a/frontend/roslyn/protocol-samples/same-assembly/expected.json b/frontend/roslyn/protocol-samples/same-assembly/expected.json new file mode 100644 index 00000000..f3ce9414 --- /dev/null +++ b/frontend/roslyn/protocol-samples/same-assembly/expected.json @@ -0,0 +1,7 @@ +{ + "S1_forged_token": "a protocol token 'ApprovedOrder' is created outside the protocol's own types", + "S2_internal_setter": "'Status' of 'Order' is not public and belongs to a state protocol", + "S3_object_initializer": "'Status' of 'Order' is not public and belongs to a state protocol", + "S4_read_only_use": null, + "S5_mentions_are_not_operations": null +} diff --git a/ownlang/analysis.py b/ownlang/analysis.py index 17c6f78e..ae1634f0 100644 --- a/ownlang/analysis.py +++ b/ownlang/analysis.py @@ -534,7 +534,8 @@ def step(self, ins: Instr, st: State) -> None: if mut: self.err("OWN013", f"cannot use '{ins.sym.name}' directly while it " - f"is mutably borrowed", ins.line) + f"is mutably borrowed", ins.line, + subject=ins.sym.origin) elif ins.sym.kind == Kind.BORROW: if not self.binding_live(st, ins.sym): self.err("OWN004", @@ -641,7 +642,8 @@ def _consume_like(self, st: State, sym: Symbol, verb: str, line: int, shared, mut = self.loans_on(st, sym) if shared or mut: self.err(code_borrowed, - f"cannot {verb} '{sym.name}' while it is borrowed", line) + f"cannot {verb} '{sym.name}' while it is borrowed", line, + subject=sym.origin) def _check_mut_borrowable(self, st: State, owner: Symbol, line: int) -> None: if self._state_problem(st, owner, "mutably borrow", line): @@ -650,11 +652,11 @@ def _check_mut_borrowable(self, st: State, owner: Symbol, line: int) -> None: if shared: self.err("OWN006", f"cannot mutably borrow '{owner.name}': a shared borrow is " - f"live", line) + f"live", line, subject=owner.origin) elif mut: self.err("OWN011", f"cannot mutably borrow '{owner.name}': it is already " - f"mutably borrowed", line) + f"mutably borrowed", line, subject=owner.origin) def _check_shared_borrowable(self, st: State, owner: Symbol, line: int) -> None: if self._state_problem(st, owner, "borrow", line): @@ -663,7 +665,7 @@ def _check_shared_borrowable(self, st: State, owner: Symbol, line: int) -> None: if mut: self.err("OWN012", f"cannot share-borrow '{owner.name}': it is mutably " - f"borrowed", line) + f"borrowed", line, subject=owner.origin) def _apply_effect(self, st: State, sym: Symbol, eff: Effect, callee: str, line: int) -> None: diff --git a/ownlang/lowered.py b/ownlang/lowered.py index c3f31c84..dfb7e2e9 100644 --- a/ownlang/lowered.py +++ b/ownlang/lowered.py @@ -67,6 +67,8 @@ from .ast_nodes import ( Acquire, AliasJoin, + BorrowBlock, + BorrowKind, Call, ExternDecl, FnDecl, @@ -74,6 +76,7 @@ Let, LifetimeDecl, Module, + Move, Overspan, Param, Release, @@ -90,7 +93,7 @@ # The Layer 2 surface version. Bump on ANY normalization change above — the # committed goldens and the Rust replay are both keyed to it. -LOWERED_VERSION = 1 +LOWERED_VERSION = 2 # The handle-map key allowlist, in serialization order (see the docstring). _HANDLE_KEYS = ( @@ -114,6 +117,16 @@ def _arg(a: Any) -> str: def _stmt(s: Stmt) -> dict[str, Any]: + if isinstance(s, Let) and isinstance(s.rhs, Move): + return {"stmt": "move", "handle": s.name, "src": s.rhs.var, + "line": s.line} + if isinstance(s, BorrowBlock): + if s.kind is not BorrowKind.MUT: + raise ValueError( + "unprojectable shared BorrowBlock — the bridge lowers only " + "`borrow_mut`; a new shape must extend the Layer 2 contract") + return {"stmt": "borrow_mut", "owner": s.owner, "binding": s.binding, + "body": [_stmt(x) for x in s.body], "line": s.line} if isinstance(s, Let): if not isinstance(s.rhs, Acquire): raise ValueError( diff --git a/ownlang/ownir.py b/ownlang/ownir.py index e3728d55..e3ad3789 100644 --- a/ownlang/ownir.py +++ b/ownlang/ownir.py @@ -9,7 +9,7 @@ OwnIR schema (JSON):: { - "ownir_version": 0, + "ownir_version": 1, "module": "WpfApp", "components": [ { @@ -110,6 +110,8 @@ from .ast_nodes import ( Acquire, AliasJoin, + BorrowBlock, + BorrowKind, Call, Effect, EffectParam, @@ -120,6 +122,7 @@ Let, LifetimeDecl, Module, + Move, Overspan, Param, Release, @@ -178,7 +181,7 @@ # vocabulary changes incompatibly; the extractor stamps the same number so a # mismatched extractor/core pair fails loudly (see load()) instead of silently # mis-reading facts. -OWNIR_VERSION = 0 +OWNIR_VERSION = 1 class OwnIRError(ValueError): @@ -337,6 +340,7 @@ def _route_resource(rkind: str) -> tuple[str, str]: _FLOW_OPS = frozenset({ "acquire", "release", "use", "overspan", "return", "alias_join", "call", "if", "while", + "move", "borrow_mut", }) # The parameter ownership-effect vocabulary (P-006/2b): a method contract's @@ -773,7 +777,7 @@ def load(path: str) -> dict[str, Any]: # version gate first: a vocabulary mismatch makes every later shape-check # meaningless, so reject it up front with an actionable message. An absent # field is treated as the current version (the only producers that omit it - # predate versioning, i.e. are v0 by definition). + # predate the field, and every version since has only ADDED vocabulary). ver = result.get("ownir_version", OWNIR_VERSION) # V2, and scoped exactly as #262 ratified it: the TOP-LEVEL SCALAR value # the type check below reads, and nothing else. `type(...) is` rather than @@ -1362,7 +1366,7 @@ def to_module(facts: dict[str, Any], # silent (honest-skip; TZ D5): record the reason for the caller to surface # as an advisory OWN052. try: - mos: dict[str, Any] = solve(_build_skeletons(raw_fns)) + mos: dict[str, Any] = solve(_build_skeletons(_inference_view(raw_fns))) except Exception as exc: mos = {} if notes is not None: @@ -1382,13 +1386,22 @@ def to_module(facts: dict[str, Any], # to an overloaded method still matches (CodeRabbit). overloaded = frozenset( n for n, c in Counter(_canonical_callee_name(x) for x in fp_names).items() if c > 1) + region_effects = (_region_param_effects(raw_fns, mos) + if any(isinstance(fn, dict) and _has_region(fn.get("body")) + for fn in raw_fns) else None) for fn in raw_fns: if not isinstance(fn, dict): continue fname = str(fn.get("name", f"Fn{loc[0]}")) ffile = str(fn.get("file", "?")) - nodes = fn.get("body", []) - nodes = nodes if isinstance(nodes, list) else [] + flow_nodes = fn.get("body", []) + flow_nodes = flow_nodes if isinstance(flow_nodes, list) else [] + # `nodes` is the INFERENCE view (regions spliced, see `_inline_regions`); + # `flow_nodes` keeps the structure and is read by `_lower_flow` alone. + # With no region the two are the same object. + has_region = _has_region(flow_nodes) + nodes = _inline_regions(flow_nodes) if has_region else flow_nodes + fn_view = {**fn, "body": nodes} if has_region else fn # which locals have ANY release in the body (any branch) — lets the OWN001 # wording distinguish "never disposed" (no release at all) from "not # disposed on every path" (released on some branch, leaked on another). @@ -1396,7 +1409,7 @@ def to_module(facts: dict[str, Any], # ownership contract params first (they seed `localmap` so the body's # uses/releases and call arguments resolve to them), then the flow body. localmap: dict[str, str] = {} - fparams = _lower_fn_params(fn, ffile, fname, handles, loc, localmap, + fparams = _lower_fn_params(fn_view, ffile, fname, handles, loc, localmap, released, mos) # The optimistic default (d5 §5), made real: an argument at a call # position whose contract resolved `may`/`unknown` means "we cannot @@ -1416,6 +1429,19 @@ def to_module(facts: dict[str, Any], unverified = _unverified_transfer_calls(nodes, mos) kill_sites = _kill_sites_for_unverified(nodes, mos) untracked = frozenset(a for a, _c, _t, _l in unverified) - kill_sites.keys() + if has_region and unverified: + # A function that opens an exclusive region must be verified end + # to end. The optimistic default ("ownership probably left the + # caller", advisory OWN051) would turn an unverifiable handoff + # into silence, and silence inside a protocol region reads as a + # PASS. Refuse instead — on both engines, identically. + arg, callee, transfer, cline = unverified[0] + raise OwnIRError( + f"OwnIR function {fname!r} opens a borrow_mut region but hands " + f"{arg!r} to {callee!r} at an unverified position (inferred " + f"contract: {transfer}) ({ffile}:{cline}) — refused: a function " + f"with an exclusive region must not rely on the optimistic " + f"ownership default") if advisories is not None and unverified: # OWN051, gated on args that actually carry an obligation here (an # acquired local or a fresh factory result) — a plain value passed @@ -1455,9 +1481,9 @@ def to_module(facts: dict[str, Any], "ever_released": hname in released, "pool": hpool} hoisted_lets.append(Let(hh, Acquire("Disposable", [], hline), hline)) fbody = [*hoisted_lets, - *_lower_flow(nodes, ffile, fname, handles, loc, localmap, + *_lower_flow(flow_nodes, ffile, fname, handles, loc, localmap, released, mos, set(hoist), first_party, overloaded, - untracked, kill_sites)] + untracked, kill_sites, False, region_effects)] # A body that returns a value gets an owned return type, so the core # models `return s` as a valid ESCAPE (the value is discharged to the # caller) instead of a void-return mismatch that would leave `s` looking @@ -1475,6 +1501,75 @@ def to_module(facts: dict[str, Any], handles) +def _has_region(nodes: Any) -> bool: + """Whether a flow body contains a `borrow_mut` region at any depth.""" + if not isinstance(nodes, list): + return False + for n in nodes: + if not isinstance(n, dict): + continue + op = n.get("op") + if op == "borrow_mut": + return True + if op == "if" and (_has_region(n.get("then")) or _has_region(n.get("else"))): + return True + if op == "while" and _has_region(n.get("body")): + return True + return False + + +def _inline_regions(nodes: Any) -> Any: + """The INFERENCE view of a flow body: every `borrow_mut` region spliced in + place of its block. + + A region is a straight-line sub-body that runs exactly once, so for every + question the contract-inference layer asks (is this param released on all + paths, which locals are acquired, does the body return a value, which + calls are unverified) the region is transparent. Only the flow lowering + (`_lower_flow`) needs the structure, because only it emits the loan. + + Identity is load-bearing twice over: a body with no region is returned AS + IS (so every pre-existing document takes the pre-existing path, byte for + byte), and the leaf op dicts are shared, never copied.""" + if not isinstance(nodes, list) or not _has_region(nodes): + return nodes + out: list[Any] = [] + for n in nodes: + if not isinstance(n, dict): + out.append(n) + continue + op = n.get("op") + if op == "borrow_mut": + sub = _inline_regions(n.get("body")) + if isinstance(sub, list): + out.extend(sub) + elif op == "if" and (_has_region(n.get("then")) or _has_region(n.get("else"))): + m = dict(n) + m["then"] = _inline_regions(n.get("then")) + m["else"] = _inline_regions(n.get("else")) + out.append(m) + elif op == "while" and _has_region(n.get("body")): + m = dict(n) + m["body"] = _inline_regions(n.get("body")) + out.append(m) + else: + out.append(n) + return out + + +def _inference_view(raw_fns: list[Any]) -> list[Any]: + """`functions[]` as the inference layer reads it (see `_inline_regions`). + A function with no region is the SAME object, so the common case is free + and unchanged.""" + out: list[Any] = [] + for fn in raw_fns: + if isinstance(fn, dict) and _has_region(fn.get("body")): + out.append({**fn, "body": _inline_regions(fn.get("body"))}) + else: + out.append(fn) + return out + + def _released_vars(nodes: list[Any]) -> set[str]: """The set of local names with at least one `release` op anywhere in a flow body (recursing into `if` branches and `while` bodies). Used to word an OWN001 as @@ -2389,6 +2484,45 @@ def _infer_param_effect(pname: str, nodes: Any, return None +def _region_param_effects(raw_fns: list[Any], + mos: dict[str, Any] | None) -> dict[str, list[str | None]]: + """For each function NAME, the effect each parameter resolves to — the + explicit `effect` when the fact carries one, the inferred one otherwise, + `None` when it resolves to a plain value. Exactly the resolution + `_lower_fn_params` applies, over the same inference view. + + Read by one rule only: inside a `borrow_mut` region a tracked local must + not land on a parameter that resolved PLAIN. The core does report that + shape (OWN041), but OWN041 is filtered as a synthesis artifact, so without + this the path is "core raised, bridge filtered, clean" — a mutation the + facts cannot see (the callee touches a plain entity, so its flow body is + empty and nothing is inferred) passing as verified.""" + out: dict[str, list[str | None]] = {} + for fn in _inference_view(raw_fns): + if not isinstance(fn, dict): + continue + fname = str(fn.get("name", "")) + raw = fn.get("params", []) + effs: list[str | None] = [] + if isinstance(raw, list): + summ = _mos_lookup(mos, fname, _call_sig(fn)) + for i, p in enumerate(raw): + if not isinstance(p, dict): + continue + eff = p.get("effect") + if not isinstance(eff, str): + ftrans = None + if summ is not None: + ps = next((q for q in summ.params if q.index == i), None) + if ps is not None: + ftrans = ps.transfer + eff = _infer_param_effect(str(p.get("name", "?")), + fn.get("body", []), ftrans) + effs.append(eff if isinstance(eff, str) and eff != "plain" else None) + out[fname] = effs + return out + + def _lower_fn_params(fn: dict[str, Any], ffile: str, fname: str, handles: dict[str, dict[str, Any]], loc: list[int], localmap: dict[str, str], @@ -2592,7 +2726,10 @@ def _lower_flow(nodes: list[Any], ffile: str, fname: str, first_party: frozenset[str] = frozenset(), overloaded: frozenset[str] = frozenset(), untracked: frozenset[str] = frozenset(), - kill_sites: dict[str, int] | None = None) -> list[Stmt]: + kill_sites: dict[str, int] | None = None, + in_region: bool = False, + param_effects: dict[str, list[str | None]] | None = None, + ) -> list[Stmt]: """Lower one OwnIR flow body (B0b/B2) into core statements. acquire/use/release/ return reference a C# local by name (`var`); `if` carries `then`/`else` sub-bodies; `while` carries a `body` (a back-edge — the core's worklist fixpoint @@ -2705,17 +2842,80 @@ def _lower_flow(nodes: list[Any], ffile: str, fname: str, en = n.get("else", []) then_b = _lower_flow(tn if isinstance(tn, list) else [], ffile, fname, handles, loc, localmap, released_vars, mos, hoisted, - first_party, overloaded, untracked, kill_sites) + first_party, overloaded, untracked, kill_sites, + in_region, param_effects) else_b = _lower_flow(en if isinstance(en, list) else [], ffile, fname, handles, loc, localmap, released_vars, mos, hoisted, - first_party, overloaded, untracked, kill_sites) + first_party, overloaded, untracked, kill_sites, + in_region, param_effects) body.append(If("?", then_b, else_b, line)) elif op == "while": bn = n.get("body", []) body_b = _lower_flow(bn if isinstance(bn, list) else [], ffile, fname, handles, loc, localmap, released_vars, mos, hoisted, - first_party, overloaded, untracked, kill_sites) + first_party, overloaded, untracked, kill_sites, + in_region, param_effects) body.append(While("?", body_b, line)) + elif op == "move": + # `var` takes OWNERSHIP of `src`'s obligation; `src` is dead after it + # (the core's `Let(Move)` — OWN005 on a later use of `src`). Unlike + # `alias_join` the source does not stay owning. Shaped exactly like + # the alias branch above: the destination's OLD binding dies first, + # and an untracked `src` makes no claim. + name = str(n.get("var", "?")) + src_h = localmap.get(str(n.get("src", ""))) + if name not in hoisted: + localmap.pop(name, None) + if src_h is not None and name not in hoisted and name not in untracked: + handle = f"loc_{loc[0]}" + loc[0] += 1 + localmap[name] = handle + handles[handle] = {"file": ffile, "line": line, + "column": _as_col(n.get("column")), "event": name, + "component": fname, "resource": "flow-local", + "ever_released": name in released_vars, + "pool": False} + body.append(Let(handle, Move(src_h, line), line)) + elif op == "borrow_mut": + # A BLOCK-scoped exclusive loan: `owner` is unavailable (and cannot + # be re-borrowed, consumed or released) until the block closes. The + # op is compound on purpose — the core's loans are block-scoped and + # the merge asserts that every predecessor carries the same loan + # set, so the fact vocabulary must not be able to say "open a loan" + # without also saying where it closes. + oname = n.get("owner") + bname = n.get("binding") + bn = n.get("body") + if not (isinstance(oname, str) and oname + and isinstance(bname, str) and bname + and isinstance(bn, list)): + raise OwnIRError( + f"OwnIR flow op 'borrow_mut' needs a non-empty string 'owner', " + f"a non-empty string 'binding' and an array 'body' " + f"({ffile}:{line})") + owner_h = localmap.get(oname) + if owner_h is None: + # no owner the core can see => no loan the core can enforce. + # Lowering the body anyway would analyse an UNPROTECTED region + # and report it clean. + raise OwnIRError( + f"OwnIR 'borrow_mut' owner {oname!r} is not a tracked local " + f"({ffile}:{line}) — refused: an exclusive region needs an " + f"owner the core tracks") + bsym = f"brw_{loc[0]}" + loc[0] += 1 + shadowed = localmap.get(bname) + localmap[bname] = bsym + body_b = _lower_flow(bn, ffile, fname, + handles, loc, localmap, released_vars, mos, hoisted, + first_party, overloaded, untracked, kill_sites, + True, param_effects) + # the binding dies with its block + if shadowed is None: + localmap.pop(bname, None) + else: + localmap[bname] = shadowed + body.append(BorrowBlock(owner_h, bsym, BorrowKind.MUT, body_b, line)) elif op == "call": # A call to a CONTRACTED callee (a function/extern whose signature the # bridge also lowered). `lower_call` resolves each argument's effect @@ -2771,9 +2971,37 @@ def _lower_flow(nodes: list[Any], ffile: str, fname: str, # OWN040. Drop them (no effect, no claim) — precision-safe, never a crash. elif (summ is not None or callee in _SINK_EXTERN_NAMES) \ and callee and isinstance(raw_args, list): + if in_region and summ is not None: + # see `_region_param_effects`: a tracked local on a PLAIN + # position is the core's OWN041, which is filtered below. + effs = (param_effects or {}).get(callee, []) + for j, a in enumerate(raw_args): + if str(a) in localmap and (j >= len(effs) or effs[j] is None): + raise OwnIRError( + f"OwnIR call to {callee!r} inside a borrow_mut " + f"region passes tracked local {str(a)!r} at " + f"position {j}, which carries no ownership effect " + f"({ffile}:{line}) — refused: inside an exclusive " + f"region every position that receives the entity " + f"or a token must state what it does with it") arg_refs: list[Expr] = [VarRef(localmap.get(str(a), str(a)), line) for a in raw_args] body.append(Call(callee, arg_refs, line)) + elif in_region and isinstance(raw_args, list): + # An UNRESOLVABLE callee is dropped everywhere else ("no effect, + # no claim"), and the core's OWN040 for it is filtered as a + # synthetic artifact. Inside an exclusive region that default is + # a false PASS: the region's entity, its binding or one of its + # tokens just left for code nobody analysed. Refuse — the + # alternative is "core raised OWN040, bridge filtered it, clean". + for a in raw_args: + if str(a) in localmap: + raise OwnIRError( + f"OwnIR call to {callee!r} inside a borrow_mut region " + f"passes tracked local {str(a)!r}, but the callee has " + f"no ownership contract ({ffile}:{line}) — refused: an " + f"exclusive region must not hand its entity or tokens " + f"to unanalysed code") # The kill site of a tracked local (Codex P1): THIS top-level call hands # it to a may/unknown position, so discharge the obligation here — the # optimistic "ownership left the caller" as a real `$consume` on the @@ -2851,6 +3079,22 @@ def _handle_of(diag: object) -> str | None: # the violation-site label per flow-local code, for the 2-step "origin -> manifestation" # reachability slice (P-015): the Rent/acquire site is where the resource came from, the # diagnostic line is where the obligation is violated. +# The move / loan codes a flow-local handle can raise once the flow vocabulary +# carries `move` and `borrow_mut`. Each needs a wording of its OWN: the fallback +# below interpolates the core diagnostic's message, and message text is not at +# parity between the two engines, so a code left to the fallback would agree on +# the verdict and disagree on the bytes. `{noun}` is "pooled buffer" or +# "IDisposable local", as for the codes above. +_FLOW_LOCAL_LOAN_WORDING = { + "OWN005": "{noun} '{name}' is used after its ownership was moved", + "OWN007": "{noun} '{name}' is consumed or returned while it is borrowed", + "OWN008": "{noun} '{name}' is released while it is borrowed", + "OWN011": "{noun} '{name}' is exclusively borrowed while an exclusive borrow of it is live", + "OWN012": "{noun} '{name}' is borrowed while an exclusive borrow of it is live", + "OWN013": "{noun} '{name}' is used directly while an exclusive borrow of it is live", +} + + _FLOW_LOCAL_VIOLATION = { "OWN002": "used here after it was released/returned", "OWN003": "released/returned here a second time", @@ -2907,7 +3151,8 @@ def dump_summaries(facts: dict[str, Any]) -> dict[str, Any]: summaries: dict[str, Any] = {} unresolved: list[str] = [] try: - summaries, unresolved = solve_with_log(_build_skeletons(raw_fns)) + summaries, unresolved = solve_with_log( + _build_skeletons(_inference_view(raw_fns))) except Exception as exc: degraded = f"{type(exc).__name__}: {exc}" return { @@ -3035,14 +3280,16 @@ def check_facts(facts: dict[str, Any]) -> list[Finding]: if sub.get("ever_released") else f"IDisposable local '{name}' is never disposed (leak)") elif pool: - msg = { + loan = _FLOW_LOCAL_LOAN_WORDING.get(d.code) + msg = loan.format(noun="pooled buffer", name=name) if loan else { "OWN002": f"pooled buffer '{name}' is used after it is returned to the pool", "OWN003": f"pooled buffer '{name}' is returned to the pool more than once", "OWN009": (f"pooled buffer '{name}' may be used after " f"being returned on some path"), }.get(d.code, f"pooled buffer '{name}': {d.message}") else: - msg = { + loan = _FLOW_LOCAL_LOAN_WORDING.get(d.code) + msg = loan.format(noun="IDisposable local", name=name) if loan else { "OWN002": f"IDisposable local '{name}' is used after it is disposed", "OWN003": f"IDisposable local '{name}' is disposed more than once", "OWN009": f"IDisposable local '{name}' may be used after disposal on some path", diff --git a/pyproject.toml b/pyproject.toml index d3e84c89..ae06d25c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ select = ["E", "W", "F", "I", "B", "UP", "C4", "RUF"] [tool.ruff.lint.per-file-ignores] # scripts/perf_baseline.py is an INSTRUMENT SOURCE: its bytes are hashed into # the measurement harness digest that the frozen #263 preregistration names -# (104c384d01bf), and steps 4, 5 and 6 are bound to that same value. Rewrapping +# (1a26aa63fd5f), and steps 4, 5 and 6 are bound to that same value. Rewrapping # a line there is not a cosmetic edit — it moves the digest and makes the frozen # contract point at an identity the tree no longer contains, which is exactly # what scripts/step7/mergegate.py exists to refuse. So the one over-long line diff --git a/rust/crates/own-analysis/src/ownership.rs b/rust/crates/own-analysis/src/ownership.rs index 9a15de49..7c45bc6a 100644 --- a/rust/crates/own-analysis/src/ownership.rs +++ b/rust/crates/own-analysis/src/ownership.rs @@ -213,8 +213,10 @@ enum Emit<'a> { impl Emit<'_> { /// Emit `code` at `line` with **no** subject — the Python `err(...)` calls - /// that pass no `subject=` (the loan/permission codes OWN004/006/007-on- - /// consume/011/012/013/034/041). + /// that pass no `subject=` (OWN004/034/041). The loan/permission codes on + /// an OWNER (OWN006/007/011/012/013) carry one since the `OwnIR` flow + /// vocabulary gained `move`/`borrow_mut`: without it the bridge cannot map + /// the verdict back to a fact handle (IR5). fn push(&mut self, code: &'static str, line: u32) { self.push_at(code, line, None); } @@ -302,7 +304,7 @@ fn consume_like( } let (shared, mutable) = loans_on(st, sym); if shared > 0 || mutable { - emit.push(code_borrowed, line); + emit.push_at(code_borrowed, line, Some(sym)); } } @@ -312,9 +314,9 @@ fn check_mut_borrowable(st: &State, owner: SymId, emit: &mut Emit<'_>, line: u32 } let (shared, mutable) = loans_on(st, owner); if shared > 0 { - emit.push("OWN006", line); + emit.push_at("OWN006", line, Some(owner)); } else if mutable { - emit.push("OWN011", line); + emit.push_at("OWN011", line, Some(owner)); } } @@ -324,7 +326,7 @@ fn check_shared_borrowable(st: &State, owner: SymId, emit: &mut Emit<'_>, line: } let (_shared, mutable) = loans_on(st, owner); if mutable { - emit.push("OWN012", line); + emit.push_at("OWN012", line, Some(owner)); } } @@ -481,7 +483,7 @@ impl<'a> Ownership<'a> { if !state_problem(st, *sym, emit, *line) { let (_shared, mutable) = loans_on(st, *sym); if mutable { - emit.push("OWN013", *line); + emit.push_at("OWN013", *line, Some(*sym)); } } } diff --git a/rust/crates/own-analysis/tests/subject.rs b/rust/crates/own-analysis/tests/subject.rs index 16502447..8517e9ca 100644 --- a/rust/crates/own-analysis/tests/subject.rs +++ b/rust/crates/own-analysis/tests/subject.rs @@ -86,13 +86,16 @@ fn origin_is_inherited_across_a_move() { } #[test] -fn loan_permission_codes_stay_subject_less_like_python() { +fn loan_permission_codes_on_an_owner_carry_its_origin_like_python() { // `borrow b as r { borrow_mut b as m { } }`: a mutable borrow while a shared - // one is live is OWN006 — Python's `err(...)` passes no subject there. + // one is live is OWN006. It USED to be subject-less on both sides; since the + // `OwnIR` flow vocabulary carries `move`/`borrow_mut` the bridge must map a + // loan verdict back to a fact handle (IR5), so Python's `err(...)` passes + // `subject=owner.origin` there and this core stamps the same. let got = subjects( "fn f() {\n let b = acquire Conn(1);\n borrow b as r {\n borrow_mut b as m {\n }\n }\n release b;\n}\n", ); - assert_eq!(got, vec![(8, "OWN006".to_owned(), None)]); + assert_eq!(got, vec![(8, "OWN006".to_owned(), s("b#6"))]); } #[test] diff --git a/rust/crates/own-bridge/src/ast.rs b/rust/crates/own-bridge/src/ast.rs index f57a168a..a21ae663 100644 --- a/rust/crates/own-bridge/src/ast.rs +++ b/rust/crates/own-bridge/src/ast.rs @@ -34,9 +34,9 @@ use crate::BridgeError; use own_lowered::{Function, LoweredDocument, Param, Stmt, TypeShape}; use own_syntax::ast::{ - Acquire, AliasJoin, Call, Effect, EffectParam, Expr, ExternDecl, FnDecl, If, Let, LifetimeDecl, - MemberRole, Module, Overspan, Release, ResourceDecl, ResourceMember, Return, Stmt as AstStmt, - Subscribe, TypeRef, Use, VarRef, While, + Acquire, AliasJoin, BorrowBlock, BorrowKind, Call, Effect, EffectParam, Expr, ExternDecl, + FnDecl, If, Let, LifetimeDecl, MemberRole, Module, Move, Overspan, Release, ResourceDecl, + ResourceMember, Return, Stmt as AstStmt, Subscribe, TypeRef, Use, VarRef, While, }; /// A fact coordinate as a core line: in the §4.2 domain, or degraded to `0`. @@ -153,6 +153,31 @@ fn stmt(s: &Stmt) -> Result { src: src.clone(), line: core_line(*line), }), + Stmt::Move { handle, src, line } => { + // Python: `Let(handle, Move(src_h, line), line)` — the move + // expression and the `let` carry the same line. + let line = core_line(*line); + AstStmt::Let(Let { + name: handle.clone(), + rhs: Expr::Move(Move { + var: src.clone(), + line, + }), + line, + }) + } + Stmt::BorrowMut { + owner, + binding, + body, + line, + } => AstStmt::BorrowBlock(BorrowBlock { + owner: owner.clone(), + binding: binding.clone(), + kind: BorrowKind::Mut, + body: stmts(body)?, + line: core_line(*line), + }), Stmt::Call { callee, args, line } => { // Python: `VarRef(localmap.get(a, a), line)` — every argument is a // name reference carrying the CALL's line. diff --git a/rust/crates/own-bridge/src/dump.rs b/rust/crates/own-bridge/src/dump.rs index 3461426a..299c3c70 100644 --- a/rust/crates/own-bridge/src/dump.rs +++ b/rust/crates/own-bridge/src/dump.rs @@ -23,7 +23,7 @@ // visibility here (same stance as `mos.rs`). #![allow(clippy::redundant_pub_crate)] -use crate::lower::{as_list, build_skeletons, py_str}; +use crate::lower::{as_list, build_skeletons, inference_view, py_str}; use crate::mos; use crate::BridgeError; use own_ir::{OwnIr, OWNIR_VERSION}; @@ -62,7 +62,9 @@ pub(crate) fn dump_summaries(facts: &OwnIr) -> Result { let mut summaries: Vec = Vec::new(); let mut unresolved: Vec = Vec::new(); let mut degraded = Value::Null; - match mos::solve_with_log(build_skeletons(raw_fns)) { + let view_store = inference_view(raw_fns); + let view_fns: &[Value] = view_store.as_deref().unwrap_or(raw_fns); + match mos::solve_with_log(build_skeletons(view_fns)) { Ok((mos, log)) => { unresolved = log; // `sorted(summaries)` — the map key IS `MethodSummary.key` in the diff --git a/rust/crates/own-bridge/src/lower.rs b/rust/crates/own-bridge/src/lower.rs index 93c07207..b3de0fc6 100644 --- a/rust/crates/own-bridge/src/lower.rs +++ b/rust/crates/own-bridge/src/lower.rs @@ -365,6 +365,133 @@ fn callee_returns_fresh( // --- flow-body walks (the `_*` helpers of ownir.py) -------------------------- /// `_released_vars`. +/// Python `{s!r}` for a plain name — the only strings the region refusals +/// interpolate. +fn repr_str(s: &str) -> String { + format!("'{s}'") +} + +// --- the inference view (`_has_region` / `_inline_regions`) ------------------- + +/// `_has_region`: whether a flow body contains a `borrow_mut` region at any +/// depth. +pub(crate) fn has_region(nodes: &[Value]) -> bool { + nodes + .iter() + .filter_map(Value::as_object) + .any(|n| match get_str(n, "op") { + Some("borrow_mut") => true, + Some("if") => has_region(as_list(n.get("then"))) || has_region(as_list(n.get("else"))), + Some("while") => has_region(as_list(n.get("body"))), + _ => false, + }) +} + +/// `_inline_regions`: the INFERENCE view of a flow body — every `borrow_mut` +/// region spliced in place of its block. +/// +/// A region is a straight-line sub-body that runs exactly once, so it is +/// transparent to every question the contract-inference layer asks. Only +/// [`lower_flow`] needs the structure, because only it emits the loan. Callers +/// take this path ONLY for a body [`has_region`] accepts, so a document +/// without regions never sees a copy. +fn inline_regions(nodes: &[Value]) -> Vec { + let mut out: Vec = Vec::new(); + for n_v in nodes { + let Some(n) = n_v.as_object() else { + out.push(n_v.clone()); + continue; + }; + let splice = |key: &str, m: &mut Obj| { + if let Some(Value::Array(sub)) = n.get(key) { + m.insert(key.to_owned(), Value::Array(inline_regions(sub))); + } + }; + match get_str(n, "op") { + Some("borrow_mut") => { + if let Some(Value::Array(sub)) = n.get("body") { + out.extend(inline_regions(sub)); + } + } + Some("if") + if has_region(as_list(n.get("then"))) || has_region(as_list(n.get("else"))) => + { + let mut m = n.clone(); + splice("then", &mut m); + splice("else", &mut m); + out.push(Value::Object(m)); + } + Some("while") if has_region(as_list(n.get("body"))) => { + let mut m = n.clone(); + splice("body", &mut m); + out.push(Value::Object(m)); + } + _ => out.push(n_v.clone()), + } + } + out +} + +/// `_inference_view`: `functions[]` as the inference layer reads it, or `None` +/// when no function opens a region (the common case: nothing is copied and +/// the caller keeps reading the original slice). +pub(crate) fn inference_view(raw_fns: &[Value]) -> Option> { + let regional = |f: &Obj| has_region(as_list(f.get("body"))); + if !raw_fns.iter().filter_map(Value::as_object).any(regional) { + return None; + } + Some( + raw_fns + .iter() + .map(|fv| match fv.as_object() { + Some(f) if regional(f) => { + let mut m = f.clone(); + m.insert( + "body".to_owned(), + Value::Array(inline_regions(as_list(f.get("body")))), + ); + Value::Object(m) + } + _ => fv.clone(), + }) + .collect(), + ) +} + +/// `_region_param_effects`: for each function NAME, whether each parameter +/// resolves to an ownership effect (`true`) or to a plain value (`false`) — +/// the resolution [`lower_fn_params`] applies, over the same inference view. +/// +/// Read by one rule: inside a `borrow_mut` region a tracked local must not +/// land on a PLAIN position. The core reports that shape as OWN041, which the +/// verdict layer filters as a synthesis artifact — so without the rule the +/// path is "core raised, bridge filtered, clean". +fn region_param_effects(view_fns: &[Value], mos: &Mos) -> HashMap> { + let mut out: HashMap> = HashMap::new(); + for f in view_fns.iter().filter_map(Value::as_object) { + let fname = str_or(f, "name", ""); + let mut effs: Vec = Vec::new(); + if let Some(raw) = f.get("params").and_then(Value::as_array) { + let summ = mos_lookup(mos, &fname, call_sig(f)); + for (i, p) in raw.iter().enumerate() { + let Some(p) = p.as_object() else { continue }; + let eff: Option<&str> = p.get("effect").and_then(Value::as_str).or_else(|| { + let ftrans = summ.and_then(|s| { + s.params + .iter() + .find(|q| q.index == i64::try_from(i).unwrap_or(i64::MAX)) + .map(|q| q.transfer) + }); + infer_param_effect(&str_or(p, "name", "?"), as_list(f.get("body")), ftrans) + }); + effs.push(eff.is_some_and(|e| e != "plain")); + } + } + out.insert(fname, effs); + } + out +} + fn released_vars(nodes: &[Value]) -> HashSet { let mut out = HashSet::new(); fn walk(nodes: &[Value], out: &mut HashSet) { @@ -1477,6 +1604,11 @@ struct FnCtx<'v, 'a> { overloaded: &'a HashSet, untracked: &'a HashSet, kill_sites: &'a HashMap, + /// Inside a `borrow_mut` region: an unverifiable handoff refuses instead + /// of dropping to "no effect, no claim". + in_region: bool, + /// `_region_param_effects`, present iff some function opens a region. + param_effects: Option<&'a HashMap>>, } fn lower_flow<'v>(ctx: &mut FnCtx<'v, '_>, nodes: &'v [Value]) -> Result, BridgeError> { @@ -1599,6 +1731,87 @@ fn lower_flow<'v>(ctx: &mut FnCtx<'v, '_>, nodes: &'v [Value]) -> Result { + // `var` takes OWNERSHIP of `src`'s obligation; `src` is dead + // after it. Shaped like `alias_join`: the destination's old + // binding dies first, and an untracked `src` makes no claim. + let name = str_or(n, "var", "?"); + let src_h = ctx.localmap.get(&str_or(n, "src", "")).cloned(); + if !ctx.hoisted.contains(&name) { + ctx.localmap.remove(&name); + } + if let Some(src_h) = src_h { + if !ctx.hoisted.contains(&name) && !ctx.untracked.contains(&name) { + let handle = format!("loc_{}", ctx.loc); + *ctx.loc = ctx.loc.saturating_add(1); + ctx.localmap.insert(name.clone(), handle.clone()); + ctx.handles.push( + &handle, + flow_local_record( + ctx.ffile, + line, + n.get("column"), + &name, + ctx.fname, + ctx.released.contains(&name), + Some(false), + ), + )?; + body.push(Stmt::Move { + handle, + src: src_h, + line, + }); + } + } + } + Some("borrow_mut") => { + // A BLOCK-scoped exclusive loan. Compound on purpose: the + // core's loans are block-scoped and its merge requires every + // predecessor to carry the same loan set. + let oname = get_str(n, "owner").filter(|s| !s.is_empty()); + let bname = get_str(n, "binding").filter(|s| !s.is_empty()); + let bn = n.get("body").and_then(Value::as_array); + let (Some(oname), Some(bname), Some(bn)) = (oname, bname, bn) else { + return Err(BridgeError(format!( + "OwnIR flow op 'borrow_mut' needs a non-empty string 'owner', \ + a non-empty string 'binding' and an array 'body' ({}:{line})", + ctx.ffile, + ))); + }; + // no owner the core can see => no loan the core can enforce. + let Some(owner_h) = ctx.localmap.get(oname).cloned() else { + return Err(BridgeError(format!( + "OwnIR 'borrow_mut' owner {} is not a tracked local \ + ({}:{line}) — refused: an exclusive region needs an \ + owner the core tracks", + repr_str(oname), + ctx.ffile, + ))); + }; + let bsym = format!("brw_{}", ctx.loc); + *ctx.loc = ctx.loc.saturating_add(1); + let shadowed = ctx.localmap.insert(bname.to_owned(), bsym.clone()); + let outer = ctx.in_region; + ctx.in_region = true; + let body_b = lower_flow(ctx, bn)?; + ctx.in_region = outer; + // the binding dies with its block + match shadowed { + Some(prev) => { + ctx.localmap.insert(bname.to_owned(), prev); + } + None => { + ctx.localmap.remove(bname); + } + } + body.push(Stmt::BorrowMut { + owner: owner_h, + binding: bsym, + body: body_b, + line, + }); + } Some("call") => { let callee = str_or(n, "callee", ""); let identity = canonical(&callee); @@ -1648,6 +1861,29 @@ fn lower_flow<'v>(ctx: &mut FnCtx<'v, '_>, nodes: &'v [Value]) -> Result(ctx: &mut FnCtx<'v, '_>, nodes: &'v [Value]) -> Result Result { // notes.append(f"{type(exc).__name__}: {exc}")`; the only failure a facts // document can reach is the duplicate-key guard, a `ValueError` there. let mut mos_notes: Vec = Vec::new(); - let mos_map: Mos = match mos::solve(build_skeletons(raw_fns)) { + // the INFERENCE view (regions spliced); `None` when no function opens one. + let view_store = inference_view(raw_fns); + let view_fns: &[Value] = view_store.as_deref().unwrap_or(raw_fns); + let mos_map: Mos = match mos::solve(build_skeletons(view_fns)) { Ok(m) => m, Err(e) => { mos_notes.push(format!("ValueError: {e}")); @@ -1944,15 +2204,28 @@ pub(crate) fn lower_full(facts: &OwnIr) -> Result { .map(|(n, _)| n.to_owned()) .collect() }; + let region_effects: Option>> = view_store + .is_some() + .then(|| region_param_effects(view_fns, &mos_map)); for fn_v in raw_fns { let Some(f) = fn_v.as_object() else { continue }; let fname = f.get("name").map_or_else(|| format!("Fn{loc}"), py_str); let ffile = str_or(f, "file", "?"); - let nodes: &[Value] = as_list(f.get("body")); + // `flow_nodes` keeps the structure and is read by `lower_flow` alone; + // `nodes` is the inference view. With no region they are one slice. + let flow_nodes: &[Value] = as_list(f.get("body")); + let f_view_store: Option = has_region(flow_nodes).then(|| { + let mut m = f.clone(); + m.insert("body".to_owned(), Value::Array(inline_regions(flow_nodes))); + m + }); + let regional = f_view_store.is_some(); + let f_view: &Obj = f_view_store.as_ref().unwrap_or(f); + let nodes: &[Value] = as_list(f_view.get("body")); let released = released_vars(nodes); let mut localmap: HashMap = HashMap::new(); let fparams = lower_fn_params( - f, + f_view, &ffile, &fname, &mut handles, @@ -1970,6 +2243,23 @@ pub(crate) fn lower_full(facts: &OwnIr) -> Result { .map(|(a, _, _, _)| a.clone()) .filter(|a| !kill_sites.contains_key(a)) .collect(); + if regional { + // A function that opens an exclusive region must be verified end + // to end: the optimistic default (advisory OWN051) would turn an + // unverifiable handoff into silence, and silence inside a + // protocol region reads as a PASS. + if let Some((arg, callee, transfer, cline)) = unverified.first() { + return Err(BridgeError(format!( + "OwnIR function {} opens a borrow_mut region but hands {} to {} \ + at an unverified position (inferred contract: {transfer}) \ + ({ffile}:{cline}) — refused: a function with an exclusive \ + region must not rely on the optimistic ownership default", + repr_str(&fname), + repr_str(arg), + repr_str(callee), + ))); + } + } // OWN051, gated on args that actually carry an obligation here (an // acquired local or a fresh factory result) — a plain value passed to // a may-position is not a gap worth a note (BR-L8). @@ -2040,8 +2330,10 @@ pub(crate) fn lower_full(facts: &OwnIr) -> Result { overloaded: &overloaded, untracked: &untracked, kill_sites: &kill_sites, + in_region: false, + param_effects: region_effects.as_ref(), }; - fbody.extend(lower_flow(&mut ctx, nodes)?); + fbody.extend(lower_flow(&mut ctx, flow_nodes)?); // a value-returning body gets an owned return type so `return s` // models a valid escape (discharge), not a void-return mismatch. let fret = returns_value(nodes).then(|| TypeShape { diff --git a/rust/crates/own-bridge/src/render.rs b/rust/crates/own-bridge/src/render.rs index e3fcfd8a..d91733d1 100644 --- a/rust/crates/own-bridge/src/render.rs +++ b/rust/crates/own-bridge/src/render.rs @@ -38,7 +38,7 @@ const SARIF_VERSION: &str = "2.1.0"; const TOOL_NAME: &str = "Owen"; /// `OWNIR_VERSION` — the schema stamp the driver carries so a consumer can tell /// which fact vocabulary produced the log. -const OWNIR_VERSION: u32 = 0; +const OWNIR_VERSION: u32 = 1; /// `_esc_data`: a GitHub workflow-command MESSAGE escapes only `%`, CR and LF. fn esc_data(s: &str) -> String { diff --git a/rust/crates/own-bridge/src/verdict.rs b/rust/crates/own-bridge/src/verdict.rs index c2a03d7c..7746a6ac 100644 --- a/rust/crates/own-bridge/src/verdict.rs +++ b/rust/crates/own-bridge/src/verdict.rs @@ -166,6 +166,27 @@ fn flow_local_message( (false, false) => format!("IDisposable local '{name}' is never disposed (leak)"), }; } + // `_FLOW_LOCAL_LOAN_WORDING`: the move / loan codes reachable since the + // flow vocabulary gained `move` and `borrow_mut`. They need wordings of + // their own — the fallback interpolates the core message, which is not at + // parity between the engines. + let noun = if pool { + "pooled buffer" + } else { + "IDisposable local" + }; + let loan = match code { + "OWN005" => Some("is used after its ownership was moved"), + "OWN007" => Some("is consumed or returned while it is borrowed"), + "OWN008" => Some("is released while it is borrowed"), + "OWN011" => Some("is exclusively borrowed while an exclusive borrow of it is live"), + "OWN012" => Some("is borrowed while an exclusive borrow of it is live"), + "OWN013" => Some("is used directly while an exclusive borrow of it is live"), + _ => None, + }; + if let Some(tail) = loan { + return format!("{noun} '{name}' {tail}"); + } if pool { return match code { "OWN002" => format!("pooled buffer '{name}' is used after it is returned to the pool"), @@ -1386,9 +1407,10 @@ mod tests { /// BR-V4's flow-local FALLBACK: a code with no wording of its own keeps the /// core diagnostic's message verbatim after a colon, on both sides of the /// pool split. Driven through `map_core` — the production branch — because - /// no facts document can reach it: the `OwnIR` flow vocabulary is nine ops, + /// no facts document can reach it: the `OwnIR` flow vocabulary is eleven ops, /// and the only codes they raise on a flow-local handle are OWN001/002/003/ - /// 009/025, every one of which HAS a wording. Same shape as the BR-V1 + /// 009/025 plus the move/loan codes OWN005/007/008/011/012/013, every one + /// of which HAS a wording. Same shape as the BR-V1 /// severity control above: a rule the corpus cannot exercise is proven at /// the unit level rather than left unproven or quietly dropped. /// @@ -1415,7 +1437,7 @@ mod tests { let diags: Vec = ["loc_0", "loc_1"] .iter() .map(|h| { - Diagnostic::new("OWN005", "moved 's' at A.cs:9", 9) + Diagnostic::new("OWN015", "moved 's' at A.cs:9", 9) .unwrap() .with_subject(format!("{h}#4")) }) diff --git a/rust/crates/own-bridge/tests/mechanisms.rs b/rust/crates/own-bridge/tests/mechanisms.rs index cca00d72..714a23f7 100644 --- a/rust/crates/own-bridge/tests/mechanisms.rs +++ b/rust/crates/own-bridge/tests/mechanisms.rs @@ -34,12 +34,12 @@ fn record_order_changes_global_mint_order_predictably() { ) }; let doc_ab = lower(&format!( - r#"{{"ownir_version": 0, "module": "M", "components": [{}, {}]}}"#, + r#"{{"ownir_version": 1, "module": "M", "components": [{}, {}]}}"#, comp("A"), comp("B") )); let doc_ba = lower(&format!( - r#"{{"ownir_version": 0, "module": "M", "components": [{}, {}]}}"#, + r#"{{"ownir_version": 1, "module": "M", "components": [{}, {}]}}"#, comp("B"), comp("A") )); @@ -62,7 +62,7 @@ fn record_order_changes_global_mint_order_predictably() { #[test] fn kill_on_rebind_removes_the_old_mapping() { let doc = lower( - r#"{"ownir_version": 0, "module": "M", "functions": [ + r#"{"ownir_version": 1, "module": "M", "functions": [ {"name": "F", "file": "F.cs", "body": [ {"op": "acquire", "var": "x", "line": 2}, {"op": "call", "callee": "Unknown.Make", "args": [], "result": "x", "line": 3}, @@ -82,7 +82,7 @@ fn kill_on_rebind_removes_the_old_mapping() { #[test] fn precise_overload_channel_does_not_unmap() { let doc = lower( - r#"{"ownir_version": 0, "module": "M", "functions": [ + r#"{"ownir_version": 1, "module": "M", "functions": [ {"name": "Take", "file": "F.cs", "sig": "System.IO.Stream", "params": [{"name": "p", "line": 1, "effect": "consume"}], "body": []}, {"name": "Take", "file": "F.cs", "sig": "System.String", @@ -115,7 +115,7 @@ fn precise_overload_channel_does_not_unmap() { #[test] fn merged_may_consume_applies_the_kill_site_unmap() { let doc = lower( - r#"{"ownir_version": 0, "module": "M", "functions": [ + r#"{"ownir_version": 1, "module": "M", "functions": [ {"name": "Take", "file": "F.cs", "sig": "System.IO.Stream", "params": [{"name": "p", "line": 1, "effect": "consume"}], "body": []}, {"name": "Take", "file": "F.cs", "sig": "System.String", @@ -148,7 +148,7 @@ mod hoist_gates { #[test] fn positive_control_hoists() { let doc = lower( - r#"{"ownir_version": 0, "module": "M", "functions": [ + r#"{"ownir_version": 1, "module": "M", "functions": [ {"name": "F", "file": "F.cs", "body": [ {"op": "if", "line": 2, "then": [{"op": "acquire", "var": "r", "line": 3}], @@ -175,7 +175,7 @@ mod hoist_gates { #[test] fn nested_depth_reference_blocks_the_hoist() { let doc = lower( - r#"{"ownir_version": 0, "module": "M", "functions": [ + r#"{"ownir_version": 1, "module": "M", "functions": [ {"name": "F", "file": "F.cs", "body": [ {"op": "if", "line": 2, "then": [ {"op": "if", "line": 3, @@ -195,7 +195,7 @@ mod hoist_gates { #[test] fn while_body_acquire_blocks_the_hoist() { let doc = lower( - r#"{"ownir_version": 0, "module": "M", "functions": [ + r#"{"ownir_version": 1, "module": "M", "functions": [ {"name": "F", "file": "F.cs", "body": [ {"op": "while", "line": 2, "body": [{"op": "acquire", "var": "r", "line": 3}]}, @@ -214,7 +214,7 @@ mod hoist_gates { #[test] fn early_return_blocks_the_hoist() { let doc = lower( - r#"{"ownir_version": 0, "module": "M", "functions": [ + r#"{"ownir_version": 1, "module": "M", "functions": [ {"name": "F", "file": "F.cs", "body": [ {"op": "if", "line": 2, "then": [{"op": "acquire", "var": "r", "line": 3}], @@ -236,7 +236,7 @@ mod hoist_gates { #[test] fn unknown_flow_op_fails_loud_with_python_text() { let facts = own_ir::OwnIr::from_json( - r#"{"ownir_version": 0, "module": "M", "functions": [ + r#"{"ownir_version": 1, "module": "M", "functions": [ {"name": "F", "file": "X.cs", "body": [{"op": "goto", "line": 7}]}]}"#, ) .expect("facts parse"); diff --git a/rust/crates/own-bridge/tests/verdicts.rs b/rust/crates/own-bridge/tests/verdicts.rs index 6a34e734..ee5503bc 100644 --- a/rust/crates/own-bridge/tests/verdicts.rs +++ b/rust/crates/own-bridge/tests/verdicts.rs @@ -366,6 +366,7 @@ fn lowered_lines(doc: &own_lowered::LoweredDocument) -> Vec { | Stmt::Overspan { line, .. } | Stmt::Return { line, .. } | Stmt::AliasJoin { line, .. } + | Stmt::Move { line, .. } | Stmt::Call { line, .. } | Stmt::Subscribe { line, .. } => out.push(*line), Stmt::If { @@ -375,7 +376,7 @@ fn lowered_lines(doc: &own_lowered::LoweredDocument) -> Vec { walk(then, out); walk(r#else, out); } - Stmt::While { body, line, .. } => { + Stmt::While { body, line, .. } | Stmt::BorrowMut { body, line, .. } => { out.push(*line); walk(body, out); } diff --git a/rust/crates/own-ir/src/lib.rs b/rust/crates/own-ir/src/lib.rs index 91dbee96..b250f647 100644 --- a/rust/crates/own-ir/src/lib.rs +++ b/rust/crates/own-ir/src/lib.rs @@ -59,7 +59,7 @@ use serde_json::{Map, Value}; /// The schema version this crate understands. Bump only on an incompatible /// vocabulary change — additive optional fields are NOT a version bump. -pub const OWNIR_VERSION: i64 = 0; +pub const OWNIR_VERSION: i64 = 1; /// Why a document was rejected. /// diff --git a/rust/crates/own-ir/tests/roundtrip.rs b/rust/crates/own-ir/tests/roundtrip.rs index abcb2ccb..26281dbc 100644 --- a/rust/crates/own-ir/tests/roundtrip.rs +++ b/rust/crates/own-ir/tests/roundtrip.rs @@ -45,9 +45,9 @@ fn round_trips_every_python_fixture() { #[test] fn version_gate_rejects_future_schema() { - let err = OwnIr::from_json(r#"{"ownir_version": 1}"#).expect_err("v1 must be rejected"); + let err = OwnIr::from_json(r#"{"ownir_version": 2}"#).expect_err("v2 must be rejected"); assert!( - err.message.contains("schema v1") && err.message.contains(&format!("v{OWNIR_VERSION}")), + err.message.contains("schema v2") && err.message.contains(&format!("v{OWNIR_VERSION}")), "gate message must name both versions: {err}" ); } diff --git a/rust/crates/own-ir/tests/validation_replay.rs b/rust/crates/own-ir/tests/validation_replay.rs index 2b603185..0bfaeb9d 100644 --- a/rust/crates/own-ir/tests/validation_replay.rs +++ b/rust/crates/own-ir/tests/validation_replay.rs @@ -370,7 +370,7 @@ fn the_depth_guard_never_fires_on_a_document_from_json_accepts() { node = serde_json::json!({"nested": [node]}); } serde_json::to_string(&serde_json::json!({ - "ownir_version": 0, + "ownir_version": 1, "future_section": node })) .expect("serializes") diff --git a/rust/crates/own-ir/tests/version_repr_census.rs b/rust/crates/own-ir/tests/version_repr_census.rs index 2109f087..cbf3a4df 100644 --- a/rust/crates/own-ir/tests/version_repr_census.rs +++ b/rust/crates/own-ir/tests/version_repr_census.rs @@ -61,10 +61,10 @@ const CENSUS: &[(&str, &str, &str)] = &[ ("null", "{\"ownir_version\": null}", "OwnIR 'ownir_version' must be an integer, got None"), ("array of one", "{\"ownir_version\": [\"a\"]}", "OwnIR 'ownir_version' must be an integer, got ['a']"), ("array empty", "{\"ownir_version\": []}", "OwnIR 'ownir_version' must be an integer, got []"), - ("int oversized +", "{\"ownir_version\": 10000000000000000000000000000000}", "OwnIR facts are schema v10000000000000000000000000000000, but this core understands v0. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it."), - ("int oversized -", "{\"ownir_version\": -10000000000000000000000000000000}", "OwnIR facts are schema v-10000000000000000000000000000000, but this core understands v0. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it."), - ("int i64 max + 1", "{\"ownir_version\": 9223372036854775808}", "OwnIR facts are schema v9223372036854775808, but this core understands v0. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it."), - ("int mismatch 7", "{\"ownir_version\": 7}", "OwnIR facts are schema v7, but this core understands v0. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it."), + ("int oversized +", "{\"ownir_version\": 10000000000000000000000000000000}", "OwnIR facts are schema v10000000000000000000000000000000, but this core understands v1. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it."), + ("int oversized -", "{\"ownir_version\": -10000000000000000000000000000000}", "OwnIR facts are schema v-10000000000000000000000000000000, but this core understands v1. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it."), + ("int i64 max + 1", "{\"ownir_version\": 9223372036854775808}", "OwnIR facts are schema v9223372036854775808, but this core understands v1. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it."), + ("int mismatch 7", "{\"ownir_version\": 7}", "OwnIR facts are schema v7, but this core understands v1. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it."), ]; /// Every value class the reference rejects, spelled byte for byte as the diff --git a/rust/crates/own-lowered/src/model.rs b/rust/crates/own-lowered/src/model.rs index e88a2e68..0b149a51 100644 --- a/rust/crates/own-lowered/src/model.rs +++ b/rust/crates/own-lowered/src/model.rs @@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize}; /// The Layer 2 surface version — must equal `ownlang/lowered.py`'s /// `LOWERED_VERSION` and `manifest.json`'s `lowered_version`. -pub const LOWERED_VERSION: u32 = 1; +pub const LOWERED_VERSION: u32 = 2; /// Three-state presence for the schema-nullable handle keys. /// @@ -208,6 +208,13 @@ pub enum Stmt { src: String, line: i64, }, + /// `handle` takes ownership of `src`'s obligation; `src` is dead after it + /// (unlike `alias_join`, where the source stays owning). + Move { + handle: String, + src: String, + line: i64, + }, Call { callee: String, args: Vec, @@ -229,6 +236,15 @@ pub enum Stmt { body: Vec, line: i64, }, + /// A block-scoped exclusive loan of `owner`, visible inside as `binding`. + /// Compound on purpose: the core's loans are block-scoped, so the surface + /// cannot open a loan without also saying where it closes. + BorrowMut { + owner: String, + binding: String, + body: Vec, + line: i64, + }, } /// One normalized handle-map entry: `handle` first, then the allowlist keys in diff --git a/rust/crates/own-lowered/tests/strictness.rs b/rust/crates/own-lowered/tests/strictness.rs index 61290902..9b114e79 100644 --- a/rust/crates/own-lowered/tests/strictness.rs +++ b/rust/crates/own-lowered/tests/strictness.rs @@ -56,7 +56,7 @@ fn rejects_wrong_version_on_a_rejection_document() { #[test] fn accepts_the_current_version_on_a_rejection_document() { - let text = "{\n \"lowered_version\": 1,\n \"error\": \"boom\"\n}\n"; + let text = "{\n \"lowered_version\": 2,\n \"error\": \"boom\"\n}\n"; let surface = parse_document(text).expect("a current-version rejection parses"); let emitted = to_canonical_json(&surface).expect("canonical emit"); assert_eq!( @@ -71,7 +71,7 @@ fn rejects_a_null_parameter_type() { // never write `"type": null` on a parameter, so the typed model must not // accept it either. let text = r#"{ - "lowered_version": 1, + "lowered_version": 2, "module": "m", "resources": [], "externs": [], @@ -102,7 +102,7 @@ fn rejects_a_null_parameter_type() { fn rejects_explicit_null_on_a_non_nullable_handle_key() { // `released` is optional-but-boolean on the record; an explicit null must // fail the parse, not decay to "missing" and vanish on re-emit. - let text = doc(1, r#"[{"handle": "sub_0", "released": null}]"#); + let text = doc(2, r#"[{"handle": "sub_0", "released": null}]"#); parse_document(&text).expect_err("\"released\": null must be rejected, not deleted"); } @@ -112,7 +112,7 @@ fn preserves_explicit_null_metadata_through_a_round_trip() { // membership) explicit `null` for `type`, `source`, and `source_type` — // `{}` and `{"source_type": null}` are DIFFERENT Layer 2 documents. let text = doc( - 1, + 2, r#"[ { "handle": "sub_0", diff --git a/rust/crates/own-shadow/tests/repro.rs b/rust/crates/own-shadow/tests/repro.rs index b72644e9..f4cb2074 100644 --- a/rust/crates/own-shadow/tests/repro.rs +++ b/rust/crates/own-shadow/tests/repro.rs @@ -832,7 +832,7 @@ fn verify_refuses_each_structural_violation() { "raw bytes that parse to another document", "does not reproduce input.canonical", with_raw(&|_raw| { - let other = br#"{"ownir_version": 0, "module": "SomethingElse"}"#; + let other = br#"{"ownir_version": 1, "module": "SomethingElse"}"#; let identity = own_shadow::hash_bytes(other); Json::Object(vec![ ("algorithm".to_owned(), Json::Str("sha256".to_owned())), diff --git a/scripts/perf_baseline.py b/scripts/perf_baseline.py index 0d112d81..944c6bc1 100644 --- a/scripts/perf_baseline.py +++ b/scripts/perf_baseline.py @@ -1272,7 +1272,7 @@ def materialize_calibration(w: Workload, tmp: Path) -> Path: if gen == "facts": scale = _as_int(w.spec.get("scale", 1), 1) doc = { - "ownir_version": 0, + "ownir_version": 1, "module": w.id, "components": [{"name": f"C{i}", "kind": "class", "file": f"gen/{i}.cs", "line": i + 1} for i in range(scale)], diff --git a/scripts/protocol_gate.py b/scripts/protocol_gate.py new file mode 100644 index 00000000..213c8f87 --- /dev/null +++ b/scripts/protocol_gate.py @@ -0,0 +1,519 @@ +#!/usr/bin/env python3 +"""State protocols (P-010, pillar 9): real C# -> OwnIR v1 -> core, tied back to source. + +The Layer 2/3 ledgers freeze the facts the Roslyn lowering emits for the state-protocol +surface, and both engines replay them with zero `dotnet`. This script is the other half: it +runs the REAL extractor over the C# those facts came from, so a frozen fact can never drift +away from the program it claims to describe. Five questions (needs `dotnet` on PATH; zero +Python dependencies). Every path below is under `frontend/roslyn/protocol-samples/`: + +1. **cases** — every `cases/.cs` is run through the extractor (with the sample API + beside it). The facts must equal the committed fixture + `tests/fixtures/lowered/typestate_cs_.facts.json` (JSON-equal: the extractor writes + platform newlines), and the reference engine's verdict on them must equal + `cases/expected.json`. + +2. **refused** — every `refused/.cs.txt` compiles, and the extractor must REFUSE it + (exit 2) with the text in `expected.json`: a shape the core cannot check, code with no + contract inside a region, a protocol that is not admitted. + +3. **does-not-compile** — every `does-not-compile/.cs.txt` must be rejected by the C# + compiler itself, built against the API as a SEPARATE assembly (so `internal` means what + it means to a real consumer). + +4. **same-assembly** — every `same-assembly/.cs.txt` compiles when it shares an + assembly with the API (where `internal` protects nothing), and the extractor must refuse + it all the same: a token made by hand, the protocol's state written past every token. A + control with a null expectation must be ACCEPTED: a mention is not an operation. + +5. **efcore** — `efcore/` is an ordinary ASP.NET Core + EF Core backend. It must run (its + acceptance runner drives real HTTP against real SQLite); the extractor must lower its + handlers to the committed `tests/fixtures/lowered/typestate_ef_orderbackend.facts.json` + with a clean verdict, from the project file alone; a copy whose handlers rely on IMPLICIT + usings must be refused rather than silently lose its regions; and the handlers under + `efcore/refused/`, `efcore/accepted/` and `efcore/known-gaps/` — all of which the C# + compiler accepts inside that same project — must be refused, accepted, and (still) + accepted. + +The refused / does-not-compile sources carry a `.cs.txt` suffix on purpose: a directory +scan must not pick up programs whose whole point is to be refused. The samples live under +`frontend/roslyn/` rather than `examples/` for a related reason: `examples/` is swept as one +document by the #260 shadow sweep, and a backend whose references that walk does not have +is, correctly, a refusal of the whole scan. + +Run: python scripts/protocol_gate.py (verify) + python scripts/protocol_gate.py --write (regenerate the fixtures from C#) + python scripts/protocol_gate.py --rust (also compare the two public CLIs) +""" + +from __future__ import annotations + +import json +import os +import re +import shutil +import subprocess +import sys +import tempfile + +ROOT = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) +sys.path.insert(0, ROOT) + +from ownlang.ownir import OwnIRError, check_facts # noqa: E402 + +PROTO = os.path.join(ROOT, "frontend", "roslyn", "protocol-samples") +EXTRACTOR = os.path.join(ROOT, "frontend", "roslyn", "OwnSharp.Extractor") +FIXDIR = os.path.join(ROOT, "tests", "fixtures", "lowered") +SAMPLES_REL = "frontend/roslyn/protocol-samples" +API_REL = f"{SAMPLES_REL}/Api" + + +def _run(cmd: list[str], cwd: str = ROOT) -> subprocess.CompletedProcess[str]: + return subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, encoding="utf-8", + errors="replace", check=False) + + +def _extractor_dll() -> str: + built = _run(["dotnet", "build", EXTRACTOR, "-c", "Release", "-nologo", "-v", "q"]) + if built.returncode != 0: + print(built.stdout[-2000:]) + raise SystemExit("FAIL: the extractor does not build") + return os.path.join(EXTRACTOR, "bin", "Release", "net8.0", "ownsharp-extract.dll") + + +def _fixture(case: str) -> str: + return os.path.join(FIXDIR, f"typestate_cs_{case.lower()}.facts.json") + + +def _verdict(facts: dict[str, object]) -> list[str] | str: + try: + return sorted({f.code for f in check_facts(facts)}) + except OwnIRError as e: + return f"refused: {e}" + + +def cases(dll: str, write: bool, fails: list[str]) -> int: + with open(os.path.join(PROTO, "cases", "expected.json"), encoding="utf-8") as f: + expected = json.load(f) + on_disk = sorted(n[:-3] for n in os.listdir(os.path.join(PROTO, "cases")) + if n.endswith(".cs")) + if on_disk != sorted(expected): + fails.append(f"cases: expected.json {sorted(expected)} != sources {on_disk}") + return 0 + with tempfile.TemporaryDirectory() as tmp: + for case in on_disk: + out = os.path.join(tmp, f"{case}.json") + # relative, forward-slash inputs: the `file` fields are part of the fixture + done = _run(["dotnet", dll, API_REL, f"{SAMPLES_REL}/cases/{case}.cs", + "--flow-locals", "-o", out]) + if done.returncode != 0: + fails.append(f"cases/{case}: the extractor exited {done.returncode}: " + f"{done.stderr.strip()[-300:]}") + continue + with open(out, encoding="utf-8") as f: + facts = json.load(f) + fixture = _fixture(case) + if write: + with open(fixture, "w", encoding="utf-8", newline="\n") as f: + json.dump(facts, f, indent=2, ensure_ascii=False) + f.write("\n") + elif not os.path.exists(fixture): + fails.append(f"cases/{case}: fixture missing ({os.path.basename(fixture)}); " + f"run with --write") + else: + with open(fixture, encoding="utf-8") as f: + if json.load(f) != facts: + fails.append(f"cases/{case}: the extractor no longer emits the " + f"committed facts ({os.path.basename(fixture)})") + got = _verdict(facts) + if got != expected[case]: + fails.append(f"cases/{case}: verdict {got!r}, expected {expected[case]!r}") + return len(on_disk) + + +def _staged(sub: str, case: str, tmp: str) -> str: + """Copy `.cs.txt` to `/.cs` and return it relative to ROOT-less tmp.""" + dst = os.path.join(tmp, f"{case}.cs") + shutil.copyfile(os.path.join(PROTO, sub, f"{case}.cs.txt"), dst) + return dst + + +def refused(dll: str, fails: list[str]) -> int: + with open(os.path.join(PROTO, "refused", "expected.json"), encoding="utf-8") as f: + expected = json.load(f) + on_disk = sorted(n[:-7] for n in os.listdir(os.path.join(PROTO, "refused")) + if n.endswith(".cs.txt")) + if on_disk != sorted(expected): + fails.append(f"refused: expected.json {sorted(expected)} != sources {on_disk}") + return 0 + with tempfile.TemporaryDirectory() as tmp: + for case in on_disk: + src = _staged("refused", case, tmp) + out = os.path.join(tmp, f"{case}.json") + done = _run(["dotnet", dll, API_REL, src, "--flow-locals", "-o", out]) + if done.returncode != 2: + fails.append(f"refused/{case}: the extractor exited {done.returncode}, " + f"expected a refusal (2)") + elif os.path.exists(out): + fails.append(f"refused/{case}: a facts file was written despite the refusal") + elif expected[case] not in done.stderr: + fails.append(f"refused/{case}: refusal text lacks {expected[case]!r}: " + f"{done.stderr.strip()[-300:]}") + return len(on_disk) + + +_PROJECT = """ + + net8.0 + 12 + enable + false + CS1998;CS0169;CS0649;CS0168;CS0219;CS0414 + + {items} + +""" + + +def does_not_compile(fails: list[str]) -> int: + with open(os.path.join(PROTO, "does-not-compile", "expected.json"), encoding="utf-8") as f: + expected = json.load(f) + on_disk = sorted(n[:-7] for n in os.listdir(os.path.join(PROTO, "does-not-compile")) + if n.endswith(".cs.txt")) + if on_disk != sorted(expected): + fails.append(f"does-not-compile: expected.json {sorted(expected)} != sources {on_disk}") + return 0 + with tempfile.TemporaryDirectory() as tmp: + api = os.path.join(tmp, "Api") + os.makedirs(api) + shutil.copyfile(os.path.join(PROTO, "Api", "ProtocolApi.cs"), + os.path.join(api, "ProtocolApi.cs")) + with open(os.path.join(api, "Api.csproj"), "w", encoding="utf-8") as f: + f.write(_PROJECT.format(items='')) + # the positive control: the compilable cases DO build against the same API + ok = os.path.join(tmp, "Ok") + os.makedirs(ok) + for n in os.listdir(os.path.join(PROTO, "cases")): + if n.endswith(".cs"): + shutil.copyfile(os.path.join(PROTO, "cases", n), os.path.join(ok, n)) + for n in os.listdir(os.path.join(PROTO, "refused")): + if n.endswith(".cs.txt"): + shutil.copyfile(os.path.join(PROTO, "refused", n), os.path.join(ok, n[:-4])) + with open(os.path.join(ok, "Ok.csproj"), "w", encoding="utf-8") as f: + f.write(_PROJECT.format(items='' + '')) + built = _run(["dotnet", "build", ok, "-nologo", "-v", "q"], cwd=tmp) + if built.returncode != 0: + codes = sorted(set(re.findall(r"error (CS\d+)", built.stdout))) + fails.append(f"does-not-compile: the positive control (cases + refused) does not " + f"build: {codes}") + for case in on_disk: + proj = os.path.join(tmp, case) + os.makedirs(proj) + shutil.copyfile(os.path.join(PROTO, "does-not-compile", f"{case}.cs.txt"), + os.path.join(proj, f"{case}.cs")) + with open(os.path.join(proj, f"{case}.csproj"), "w", encoding="utf-8") as f: + f.write(_PROJECT.format(items='' + '')) + built = _run(["dotnet", "build", proj, "-nologo", "-v", "q"], cwd=tmp) + codes = sorted(set(re.findall(r"error (CS\d+)", built.stdout))) + if built.returncode == 0: + fails.append(f"does-not-compile/{case}: it COMPILES") + elif not set(codes) & set(expected[case]): + fails.append(f"does-not-compile/{case}: errors {codes}, expected one of " + f"{expected[case]}") + return len(on_disk) + + +def same_assembly(dll: str, fails: list[str]) -> int: + """The protocol and its users in ONE assembly. There `internal` holds nothing, so every + program under `same-assembly/` COMPILES; the scan has to hold the boundary instead + (exit 2, the text in `expected.json`), and must still accept the control whose expected + text is null — the same assembly, the entity's public surface only.""" + with open(os.path.join(PROTO, "same-assembly", "expected.json"), encoding="utf-8") as f: + expected = json.load(f) + on_disk = sorted(n[:-7] for n in os.listdir(os.path.join(PROTO, "same-assembly")) + if n.endswith(".cs.txt")) + if on_disk != sorted(expected): + fails.append(f"same-assembly: expected.json {sorted(expected)} != sources {on_disk}") + return 0 + with tempfile.TemporaryDirectory() as tmp: + one = os.path.join(tmp, "One") + os.makedirs(one) + shutil.copyfile(os.path.join(PROTO, "Api", "ProtocolApi.cs"), + os.path.join(one, "ProtocolApi.cs")) + for case in on_disk: + shutil.copyfile(os.path.join(PROTO, "same-assembly", f"{case}.cs.txt"), + os.path.join(one, f"{case}.cs")) + with open(os.path.join(one, "One.csproj"), "w", encoding="utf-8") as f: + f.write(_PROJECT.format(items='')) + built = _run(["dotnet", "build", one, "-nologo", "-v", "q"], cwd=tmp) + if built.returncode != 0: + codes = sorted(set(re.findall(r"error (CS\d+)", built.stdout))) + fails.append(f"same-assembly: the programs do not build in one assembly: {codes}") + src = os.path.join(tmp, "src") + os.makedirs(src) + for case in on_disk: + staged = _staged("same-assembly", case, src) + out = os.path.join(tmp, f"{case}.json") + done = _run(["dotnet", dll, API_REL, staged, "--flow-locals", "-o", out]) + if expected[case] is None: + if done.returncode != 0: + fails.append(f"same-assembly/{case}: the control was not accepted (exit " + f"{done.returncode}): {done.stderr.strip()[-300:]}") + elif done.returncode != 2: + fails.append(f"same-assembly/{case}: the extractor exited {done.returncode}, " + f"expected a refusal (2)") + elif os.path.exists(out): + fails.append(f"same-assembly/{case}: a facts file was written despite the " + f"refusal") + elif expected[case] not in done.stderr: + fails.append(f"same-assembly/{case}: refusal text lacks {expected[case]!r}: " + f"{done.stderr.strip()[-300:]}") + return len(on_disk) + + +EF = os.path.join(PROTO, "efcore") +EF_REL = f"{SAMPLES_REL}/efcore/OrderBackend" +EF_PROJECT = f"{EF_REL}/OrderBackend.csproj" +EF_FIXTURE = os.path.join(FIXDIR, "typestate_ef_orderbackend.facts.json") +EF_REGIONS = ("OrderBackend.OrderHandlers.Ship$protocol", + "OrderBackend.OrderHandlers.SubmitAndApprove$protocol") +EF_CHECKS = 13 +# Textual, and labelled as such: the handler file carries no attribute, and the backend's own +# sources reach for neither reflection nor a custom query provider. +_EF_FORBIDDEN = ("System.Reflection", ".GetType()", "Activator.", "dynamic ", "IQueryProvider", + "ExpressionVisitor", "Expression<") +# The usings a Web SDK project gets implicitly. The scan does not read `obj/`, so a handler +# that leans on them does not bind; the staged copy below removes exactly these lines. +_EF_IMPLICIT = re.compile(r"^using (System|System\.Threading|System\.Threading\.Tasks|" + r"System\.Linq|Microsoft\.AspNetCore\.Http|" + r"Microsoft\.Extensions\.Logging);\n", flags=re.M) +# What a staged handler's directory promises: the extractor's answer to it. +_EF_STAGED = {"refused": "refuse", "accepted": "accept", "known-gaps": "accept"} + + +def _ef_sources() -> list[str]: + out = [] + for base, dirs, names in os.walk(os.path.join(EF, "OrderBackend")): + dirs[:] = [d for d in dirs if d not in ("bin", "obj")] + out += [os.path.join(base, n) for n in names if n.endswith(".cs")] + return sorted(out) + + +def _has_region(flow: list[dict[str, object]]) -> bool: + return any(op.get("op") == "borrow_mut" for op in flow) + + +def _stage_backend(tmp: str, name: str) -> str: + """A buildable copy of the backend project (sources only) under `//`.""" + stage = os.path.join(tmp, name) + shutil.copytree(os.path.join(EF, "OrderBackend"), os.path.join(stage, "OrderBackend"), + ignore=shutil.ignore_patterns("bin", "obj")) + shutil.copyfile(os.path.join(EF, "nuget.config"), os.path.join(stage, "nuget.config")) + return stage + + +def efcore(dll: str, write: bool, fails: list[str]) -> int: + """The same lowering over a REAL ASP.NET Core + EF Core backend. + + * the backend runs: a real HTTP listener, a real SQLite file, the transitions are seen by + the ChangeTracker on the instance EF tracks and are saved (`Acceptance`, its own exit code); + * the handler file is plain: no attribute; the sources use no reflection, no custom LINQ; + * the scan of the project file alone emits the committed facts, both regions are present + in them, and the verdict is clean — with the opaque calls (logger, EF, `Results.*`, + `await using`, `try`/`catch`, `return`) sitting AROUND the regions; + * the same handlers leaning on implicit usings still compile, and are REFUSED (exit 2) + instead of losing their regions; + * staged handlers the compiler accepts are refused / accepted as their directory says.""" + n = 0 + built = _run(["dotnet", "build", os.path.join(EF, "Acceptance"), "-nologo", "-v", "q"]) + if built.returncode != 0: + fails.append(f"efcore: the backend does not build: {built.stdout.strip()[-400:]}") + return n + ran = _run(["dotnet", os.path.join(EF, "Acceptance", "bin", "Debug", "net8.0", + "Acceptance.dll")]) + oks = len(re.findall(r"^ok\[", ran.stdout, flags=re.M)) + if (ran.returncode != 0 or "all checks hold" not in ran.stdout or oks != EF_CHECKS + or "FAIL[" in ran.stdout): + fails.append(f"efcore/acceptance: exit {ran.returncode}, {oks}/{EF_CHECKS} checks: " + f"{ran.stdout.strip()[-400:]}") + n += oks + + with open(os.path.join(EF, "OrderBackend", "OrderHandlers.cs"), encoding="utf-8") as f: + handlers = f.read() + if re.search(r"^\s*\[", handlers, flags=re.M): + fails.append("efcore/plain: OrderHandlers.cs carries an attribute") + for path in _ef_sources(): + with open(path, encoding="utf-8") as f: + text = f.read() + for word in _EF_FORBIDDEN: + if word in text: + fails.append(f"efcore/plain: {os.path.basename(path)} uses {word!r}") + n += 1 + + with tempfile.TemporaryDirectory() as tmp: + # (a) the scan of the project file alone: the committed facts, both regions, clean + out = os.path.join(tmp, "bound.json") + done = _run(["dotnet", dll, EF_PROJECT, "--flow-locals", "-o", out]) + if done.returncode != 0: + fails.append(f"efcore/bound: the extractor exited {done.returncode}: " + f"{done.stderr.strip()[-300:]}") + else: + with open(out, encoding="utf-8") as f: + facts = json.load(f) + by_name = {fn["name"]: fn for fn in facts.get("functions", [])} + for region in EF_REGIONS: + if region not in by_name or not _has_region(by_name[region]["body"]): + fails.append(f"efcore/bound: no protocol region lowered for {region}") + if write: + with open(EF_FIXTURE, "w", encoding="utf-8", newline="\n") as f: + json.dump(facts, f, indent=2, ensure_ascii=False) + f.write("\n") + elif not os.path.exists(EF_FIXTURE): + fails.append("efcore/bound: fixture missing; run with --write") + else: + with open(EF_FIXTURE, encoding="utf-8") as f: + if json.load(f) != facts: + fails.append("efcore/bound: the extractor no longer emits the committed " + f"facts ({os.path.basename(EF_FIXTURE)})") + got = _verdict(facts) + if got != []: + fails.append(f"efcore/bound: verdict {got!r}, expected clean") + n += 1 + + # (b) the same project with its handlers leaning on IMPLICIT usings. It compiles — + # the SDK generates them into obj/ — and the scan, which does not read obj/, must + # say that it cannot bind the region rather than drop it. + stage = _stage_backend(tmp, "implicit") + handler = os.path.join(stage, "OrderBackend", "OrderHandlers.cs") + with open(handler, encoding="utf-8") as f: + stripped, removed = _EF_IMPLICIT.subn("", f.read()) + with open(handler, "w", encoding="utf-8", newline="\n") as f: + f.write(stripped) + project = os.path.join(stage, "OrderBackend", "OrderBackend.csproj") + built = _run(["dotnet", "build", project, "-nologo", "-v", "q"], cwd=stage) + out = os.path.join(tmp, "implicit.json") + done = _run(["dotnet", dll, project, "--flow-locals", "-o", out]) + if removed == 0: + fails.append("efcore/implicit: the handler file has no explicit usings to remove") + elif built.returncode != 0: + codes = sorted(set(re.findall(r"error (CS\d+)", built.stdout))) + fails.append(f"efcore/implicit: the staged backend does not build: {codes}") + elif done.returncode != 2 or os.path.exists(out) or "does not resolve" not in done.stderr: + fails.append(f"efcore/implicit: exit {done.returncode}, expected a refusal naming " + f"the unresolved type: {done.stderr.strip()[-300:]}") + n += 1 + + # (c) handlers staged INTO a copy of the project, which must still compile: + # `refused/` - the scan must refuse each (exit 2, the expected text); + # `accepted/` - the scan must accept each: a mention is not an operation; + # `known-gaps/` - the scan ACCEPTS each although the row changes state past every + # token: outside what the profile claims, pinned so that it is a + # stated limit and never a forgotten one. + staged: list[tuple[str, str, str]] = [] + for kind in _EF_STAGED: + with open(os.path.join(EF, kind, "expected.json"), encoding="utf-8") as f: + expected = json.load(f) + on_disk = sorted(x[:-7] for x in os.listdir(os.path.join(EF, kind)) + if x.endswith(".cs.txt")) + if on_disk != sorted(expected): + fails.append(f"efcore/{kind}: expected.json {sorted(expected)} != sources " + f"{on_disk}") + return n + staged += [(kind, case, expected[case]) for case in on_disk] + stage = _stage_backend(tmp, "staged") + for kind, case, _ in staged: + shutil.copyfile(os.path.join(EF, kind, f"{case}.cs.txt"), + os.path.join(stage, "OrderBackend", f"{case}.cs")) + project = os.path.join(stage, "OrderBackend", "OrderBackend.csproj") + built = _run(["dotnet", "build", project, "-nologo", "-v", "q"], cwd=stage) + if built.returncode != 0: + codes = sorted(set(re.findall(r"error (CS\d+)", built.stdout))) + fails.append(f"efcore/staged: the staged backend does not build: {codes}") + return n + for kind, case, want in staged: + # one staged handler per scan: the project's own sources plus this file + keep = os.path.join(stage, "OrderBackend", f"{case}.cs") + hidden = [os.path.join(stage, "OrderBackend", f"{other}.cs") + for _, other, _ in staged if other != case] + for path in hidden: + os.replace(path, path + ".off") + out = os.path.join(tmp, f"{case}.json") + done = _run(["dotnet", dll, project, "--flow-locals", "-o", out]) + for path in hidden: + os.replace(path + ".off", path) + where = f"efcore/{kind}/{case}" + if _EF_STAGED[kind] == "accept": + if done.returncode != 0: + fails.append(f"{where}: the scan does not accept it (exit " + f"{done.returncode}): {done.stderr.strip()[-300:]}") + else: + with open(out, encoding="utf-8") as f: + got = _verdict(json.load(f)) + if got != []: + fails.append(f"{where}: verdict {got!r}, expected clean") + elif done.returncode != 2: + fails.append(f"{where}: the extractor exited {done.returncode}, expected a " + f"refusal (2)") + elif os.path.exists(out): + fails.append(f"{where}: a facts file was written despite the refusal") + elif want not in done.stderr or os.path.basename(keep) not in done.stderr: + fails.append(f"{where}: refusal text lacks {want!r}: " + f"{done.stderr.strip()[-300:]}") + n += 1 + return n + + +def rust_cli(binary: str, fails: list[str]) -> int: + """The two PUBLIC engines over the frozen C#-derived facts: exit code, stdout and + stderr must be byte-identical.""" + n = 0 + for name in sorted(os.listdir(FIXDIR)): + if not (name.startswith(("typestate_cs_", "typestate_ef_")) + and name.endswith(".facts.json")): + continue + rel = f"tests/fixtures/lowered/{name}" + args = ["ownir", rel, "--format", "human", "--severity", "error"] + py = subprocess.run([sys.executable, "-m", "ownlang", *args], cwd=ROOT, + capture_output=True, check=False) + rs = subprocess.run([binary, *args], cwd=ROOT, capture_output=True, check=False) + if (py.returncode, py.stdout, py.stderr) != (rs.returncode, rs.stdout, rs.stderr): + fails.append(f"rust/{name}: the two engines differ (python rc={py.returncode}, " + f"rust rc={rs.returncode})") + n += 1 + return n + + +def main() -> int: + write = "--write" in sys.argv[1:] + rust = None + if "--rust" in sys.argv[1:]: + rust = sys.argv[sys.argv.index("--rust") + 1] + fails: list[str] = [] + if rust is not None and "--rust-only" in sys.argv[1:]: + n = rust_cli(rust, fails) + for f in fails: + print(f"FAIL: {f}") + print(f"protocol gate (rust CLI parity): {n} C#-derived documents, {len(fails)} failure(s)") + return 1 if fails else 0 + dll = _extractor_dll() + n_cases = cases(dll, write, fails) + n_refused = refused(dll, fails) + n_nocompile = does_not_compile(fails) + n_same = same_assembly(dll, fails) + n_ef = efcore(dll, write, fails) + n_rust = rust_cli(rust, fails) if rust is not None else 0 + for f in fails: + print(f"FAIL: {f}") + print(f"protocol gate: {n_cases} cases lowered from C# and judged, {n_refused} refused by " + f"the lowering, {n_nocompile} rejected by the C# compiler, {n_same} same-assembly " + f"programs held to the boundary, {n_ef} checks on the real " + f"ASP.NET Core + EF Core backend" + + (f", {n_rust} documents byte-identical on both CLIs" if rust else "") + + f"; {len(fails)} failure(s)" + (" [fixtures written]" if write else "")) + return 1 if fails else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/spec/Bridge.md b/spec/Bridge.md index a5138302..5a6c3431 100644 --- a/spec/Bridge.md +++ b/spec/Bridge.md @@ -217,6 +217,32 @@ through `_as_line` — a non-integer, or one outside the [§4.2](OwnIR.md) coordinate domain, reads as `0`. The bridge never invents lines and never clamps one; the anchor policy for *findings* is BR-V5's. +**BR-L12 (`move`).** `move src -> var` lowers to `Let(var', Move(src_h))`: +`var` takes the obligation, `src` is dead after it (the core's OWN005 on a later +use). Shaped like the alias branch: the destination's old binding dies first +(BR-L6), a hoisted or untracked destination mints nothing, and an untracked +`src` makes no claim. + +**BR-L13 (`borrow_mut` — the exclusive region, and its admission rules).** +`borrow_mut owner as binding { body }` lowers to one `BorrowBlock(owner_h, +brw_, MUT, body')` — the op is compound because the core's loans are +block-scoped; `binding` is in scope for `body` only and restores what it +shadowed. Inference reads the region as transparent (its body spliced in +place), so a region never changes a summary. Four shapes are **refused** +(`OwnIRError`, file:line) rather than lowered, because each would otherwise +reach the verdict as "the core raised, the bridge filtered it, clean": +(a) an `owner` that is not a tracked local — there would be no loan to enforce; +(b) inside a region, a call to an unresolvable callee that passes a tracked +local — the default "drop it: no effect, no claim" (BR-L9b) would hand the +entity or a token to unanalysed code, and the core's OWN040 for it is filtered; +(c) inside a region, a tracked local on a position that resolved **plain** — +the core's OWN041, filtered as a synthesis artifact; +(d) any `may`/`unknown` position (BR-L8) in a function that contains a region — +the optimistic untrack would silently drop the region's owner or a token. +A frontend must therefore not emit a region it cannot prove closed over +contracted calls; what it may put inside one is the frontend's rule, not the +bridge's (the Roslyn lowering is default-deny: transitions and what it reads). + ## 3. Interprocedural MOS Normatively specified in [Inference.md](Inference.md) (INF-L/S/R/M/F/A/P + diff --git a/spec/OwnIR.md b/spec/OwnIR.md index 035d288f..405c59f3 100644 --- a/spec/OwnIR.md +++ b/spec/OwnIR.md @@ -19,7 +19,7 @@ A facts document is a single JSON object: ```json { - "ownir_version": 0, + "ownir_version": 1, "module": "WpfApp", "components": [ /* §4 owned-resource records, grouped by type */ ], "functions": [ /* §5 flow bodies (intra-procedural CFG facts) */ ], @@ -45,7 +45,21 @@ producer**: the Python core, the Roslyn extractor (`OwnSharp.Extractor`), and th OwnTS frontend. A document whose `ownir_version` differs from the core's raises `OwnIRError` at load — a mismatched extractor/core pair fails loudly rather than silently mis-reading facts. A document that omits the field is read as the -current version (legacy v0 producers). +current version (the producers that omit it predate the field). + +The version is currently **1**: + +| Version | What it added | +|---|---| +| 0 | the initial vocabulary | +| 1 | two flow ops: `move` ([§5](#5-flow-bodies-functions)) and the compound `borrow_mut` ([§5.3](#53-exclusive-regions-borrow_mut)) | + +A document stamped with an older version is refused, not migrated: no core +reads two versions, and a producer and a core are built from the same commit. + +An ADDITIVE section does not appear in this table, because it does not move the +version: `orphaned_awaitables` ([§9](#9-orphaned-awaitables-orphaned_awaitables)) +arrived while the version was 0 and is part of version 1 unchanged. What bumps the version — the rule that keeps the three producers honest: @@ -299,6 +313,8 @@ op vocabulary: | `call` | `callee`, `args`, optional `result`, optional `sig` | a `Call` checked against the callee's contract; a `fresh`-returning callee mints an acquire for `result` (D5.2) | | `if` | `then`, `else` (sub-bodies) | an `If` with both branches lowered | | `while` | `body` (sub-body) | a `While` — a back-edge the core's worklist fixpoint converges over (A1) | +| `move` | `var`, `src` | a `Let`+`Move`: `var` takes ownership of `src`'s obligation and `src` is dead after it (a later use is **OWN005**) | +| `borrow_mut` | `owner`, `binding`, `body` (sub-body) | a `BorrowBlock`: an exclusive loan of the local `owner` for the block, visible inside as `binding` (§5.3) | Anything else is a hard error (§2, fail-loud). Overwriting a tracked local (a re-bound `call` result or `alias_join` target) kills its previous ownership @@ -395,6 +411,39 @@ that registers the sidecar binds them to the shared coordinate domain. The producer validates every record against this vocabulary and refuses to write a facts file at all if one is malformed (exit 2): fail-loud at the source. +### 5.3 Exclusive regions (`borrow_mut`) + +`borrow_mut` is a **compound** op: it carries the loan's whole extent as its +`body`. There is no `borrow_start`/`borrow_end` pair, and there will not be one — +the core's loans are block-scoped and its merge requires every predecessor to +carry the same loan set, so the fact vocabulary must not be able to open a loan +without also stating where it closes. + +While the block is open the owner cannot be re-borrowed (**OWN011**/**OWN012**), +used directly (**OWN013**), released (**OWN008**), or consumed/returned +(**OWN007**); these are the core's verdicts, mapped to the owner's fact handle. +The contract-inference layer reads a region as transparent (its body spliced in +place): a region runs exactly once, so it changes no inferred contract. + +A region is **fail-closed**. Each of the following is refused with an +`OwnIRError`, never lowered: + +- `owner` does not name a tracked local (a missing `owner`/`binding`/`body` is + refused as malformed); +- a `call` inside the block hands a tracked local to a callee that has no + ownership contract (elsewhere such a call is dropped: "no effect, no claim"); +- a `call` inside the block puts a tracked local on a position that carries no + ownership effect (the core's OWN041, which the bridge filters as an artifact); +- the function hands **any** argument to a `may`/`unknown` position: the + optimistic default (§5, advisory OWN051) is not available to a function that + opens a region. + +What a region does **not** check is stated as plainly: the core has no relation +between a token and the region it was minted in. A token acquired outside any +region, two tokens in one region, and a token spent against a different owner +are all accepted by the core; a frontend that uses regions for a state protocol +must make those shapes unrepresentable in what it emits. + ## 6. DI registration graph (`services[]`) An optional array feeding the **DI001** captive-dependency check (P-006), a diff --git a/spec/ownir.schema.json b/spec/ownir.schema.json index 65df9d57..f6d6d3ff 100644 --- a/spec/ownir.schema.json +++ b/spec/ownir.schema.json @@ -8,7 +8,7 @@ "properties": { "ownir_version": { "description": "OwnIR fact-vocabulary version. Every producer stamps the same integer (OWNIR_VERSION in ownlang/ownir.py); a document whose version differs from the core's is rejected at load (spec/OwnIR.md IR1/IR2). An absent field is read as the current version by the core, but this schema requires it.", - "const": 0 + "const": 1 }, "module": { "description": "The extracted module/assembly name.", @@ -298,6 +298,31 @@ "body": { "type": "array", "items": { "$ref": "#/$defs/flowOp" } } }, "required": ["op"] + }, + { + "title": "move", + "description": "`var` takes ownership of `src`'s obligation (Let+Move); `src` is dead after it. Unlike alias_join the source does not stay owning.", + "properties": { + "op": { "const": "move" }, + "line": { "$ref": "#/$defs/sourceLine" }, + "column": { "$ref": "#/$defs/sourceColumn" }, + "var": { "type": "string" }, + "src": { "type": "string" } + }, + "required": ["op", "var", "src"] + }, + { + "title": "borrow_mut", + "description": "A block-scoped exclusive loan of the local `owner`, visible inside `body` as `binding` (a BorrowBlock). Compound on purpose: the vocabulary cannot open a loan without saying where it closes. Inside the block an unverifiable handoff of a tracked local is refused, not dropped.", + "properties": { + "op": { "const": "borrow_mut" }, + "line": { "$ref": "#/$defs/sourceLine" }, + "column": { "$ref": "#/$defs/sourceColumn" }, + "owner": { "type": "string", "minLength": 1 }, + "binding": { "type": "string", "minLength": 1 }, + "body": { "type": "array", "items": { "$ref": "#/$defs/flowOp" } } + }, + "required": ["op", "owner", "binding", "body"] } ] }, diff --git a/tests/check_fix_candidates_facts.py b/tests/check_fix_candidates_facts.py index 82a81d58..9e5fac72 100644 --- a/tests/check_fix_candidates_facts.py +++ b/tests/check_fix_candidates_facts.py @@ -15,8 +15,13 @@ import copy import json +import os import sys +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) + +from ownlang.ownir import OWNIR_VERSION + _ADDITIVE_COMPONENT_KEYS = ( "qualified_name", "is_partial", @@ -65,9 +70,15 @@ def check(cond: bool, msg: str) -> None: if not cond: fails.append(msg) - # Top-level: additive version present, ownir_version untouched. + # Top-level: additive version present, ownir_version untouched. "Untouched" is a + # claim about the FLAG, not about a number: `--fix-candidates` is additive metadata, + # so it must stamp the vocabulary version the core currently understands — the same + # one a flag-off run stamps (compared below, where the flag-off facts are in hand). + # This used to read `== 0`, which held only until the vocabulary first moved. check(on.get("fix_candidates_version") == 1, "top-level fix_candidates_version must be 1") - check(on.get("ownir_version") == 0, "ownir_version must stay 0") + check(on.get("ownir_version") == OWNIR_VERSION, + f"--fix-candidates must not move ownir_version: the facts are stamped " + f"{on.get('ownir_version')!r}, the core understands {OWNIR_VERSION}") def only_fix(name: str) -> dict | None: fx = _fixes(on, name) @@ -226,6 +237,9 @@ def only_fix(name: str) -> dict | None: if off_path is not None: off = _load(off_path) check("fix_candidates_version" not in off, "flag-off: no fix_candidates_version") + check(on.get("ownir_version") == off.get("ownir_version"), + f"the flag moved ownir_version: {off.get('ownir_version')!r} without it, " + f"{on.get('ownir_version')!r} with it") for c in off.get("components", []): # type: ignore[union-attr] check("qualified_name" not in c, f"flag-off: {c.get('name')} has qualified_name") for s in c.get("subscriptions") or []: diff --git a/tests/fake_shadow_engine.py b/tests/fake_shadow_engine.py index e56ec912..0f5184bf 100755 --- a/tests/fake_shadow_engine.py +++ b/tests/fake_shadow_engine.py @@ -87,7 +87,7 @@ def main() -> int: target = os.environ.get("OWN_FAKE_ENGINE_REWRITE") if target: with open(target, "wb") as f: - f.write(b'{"ownir_version": 0, "module": "RewrittenUnderneath"}\n') + f.write(b'{"ownir_version": 1, "module": "RewrittenUnderneath"}\n') entry = _recorded_entry() entry["consumed"] = hash_bytes(raw) diff --git a/tests/fixtures/cli_ownir/bands-sarif-error-normal.case.json b/tests/fixtures/cli_ownir/bands-sarif-error-normal.case.json index 30b980ba..e464ca44 100644 --- a/tests/fixtures/cli_ownir/bands-sarif-error-normal.case.json +++ b/tests/fixtures/cli_ownir/bands-sarif-error-normal.case.json @@ -14,7 +14,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n },\n {\n \"id\": \"OWN050\",\n \"shortDescription\": {\n \"text\": \"declaring type unresolved -- leakage analysis skipped\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN050\",\n \"level\": \"note\",\n \"message\": {\n \"text\": \"cannot verify 'ext.Unknown' \\u2014 its declaring type is an unresolved reference (build the project or pass references); leakage analysis skipped [resource: unresolved reference]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 13\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"unresolved reference\",\n \"component\": \"Vm\",\n \"event\": \"ext.Unknown\",\n \"handler\": \"OnU\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n },\n {\n \"id\": \"OWN050\",\n \"shortDescription\": {\n \"text\": \"declaring type unresolved -- leakage analysis skipped\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN050\",\n \"level\": \"note\",\n \"message\": {\n \"text\": \"cannot verify 'ext.Unknown' \\u2014 its declaring type is an unresolved reference (build the project or pass references); leakage analysis skipped [resource: unresolved reference]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 13\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"unresolved reference\",\n \"component\": \"Vm\",\n \"event\": \"ext.Unknown\",\n \"handler\": \"OnU\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", "stderr": "\n2 findings, 1 advisory (OWN050), 1 suppressed ([OwnIgnore]).\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/bands-sarif-error-quiet.case.json b/tests/fixtures/cli_ownir/bands-sarif-error-quiet.case.json index 36a2efa1..60e9278f 100644 --- a/tests/fixtures/cli_ownir/bands-sarif-error-quiet.case.json +++ b/tests/fixtures/cli_ownir/bands-sarif-error-quiet.case.json @@ -14,7 +14,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", "stderr": "\n2 findings (1 advisory hidden), 1 suppressed ([OwnIgnore]).\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/bands-sarif-error-verbose.case.json b/tests/fixtures/cli_ownir/bands-sarif-error-verbose.case.json index 1c9e8fe1..da29f794 100644 --- a/tests/fixtures/cli_ownir/bands-sarif-error-verbose.case.json +++ b/tests/fixtures/cli_ownir/bands-sarif-error-verbose.case.json @@ -14,7 +14,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n },\n {\n \"id\": \"OWN050\",\n \"shortDescription\": {\n \"text\": \"declaring type unresolved -- leakage analysis skipped\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN050\",\n \"level\": \"note\",\n \"message\": {\n \"text\": \"cannot verify 'ext.Unknown' \\u2014 its declaring type is an unresolved reference (build the project or pass references); leakage analysis skipped [resource: unresolved reference]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 13\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"unresolved reference\",\n \"component\": \"Vm\",\n \"event\": \"ext.Unknown\",\n \"handler\": \"OnU\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n },\n {\n \"id\": \"OWN050\",\n \"shortDescription\": {\n \"text\": \"declaring type unresolved -- leakage analysis skipped\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN050\",\n \"level\": \"note\",\n \"message\": {\n \"text\": \"cannot verify 'ext.Unknown' \\u2014 its declaring type is an unresolved reference (build the project or pass references); leakage analysis skipped [resource: unresolved reference]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 13\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"unresolved reference\",\n \"component\": \"Vm\",\n \"event\": \"ext.Unknown\",\n \"handler\": \"OnU\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", "stderr": "\n2 findings, 1 advisory (OWN050), 1 suppressed ([OwnIgnore]).\n by code: OWN001=3, OWN050=1\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/bands-sarif-warning-normal.case.json b/tests/fixtures/cli_ownir/bands-sarif-warning-normal.case.json index 72613d4d..d6dc0575 100644 --- a/tests/fixtures/cli_ownir/bands-sarif-warning-normal.case.json +++ b/tests/fixtures/cli_ownir/bands-sarif-warning-normal.case.json @@ -14,7 +14,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n },\n {\n \"id\": \"OWN050\",\n \"shortDescription\": {\n \"text\": \"declaring type unresolved -- leakage analysis skipped\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN050\",\n \"level\": \"note\",\n \"message\": {\n \"text\": \"cannot verify 'ext.Unknown' \\u2014 its declaring type is an unresolved reference (build the project or pass references); leakage analysis skipped [resource: unresolved reference]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 13\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"unresolved reference\",\n \"component\": \"Vm\",\n \"event\": \"ext.Unknown\",\n \"handler\": \"OnU\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n },\n {\n \"id\": \"OWN050\",\n \"shortDescription\": {\n \"text\": \"declaring type unresolved -- leakage analysis skipped\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN050\",\n \"level\": \"note\",\n \"message\": {\n \"text\": \"cannot verify 'ext.Unknown' \\u2014 its declaring type is an unresolved reference (build the project or pass references); leakage analysis skipped [resource: unresolved reference]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 13\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"unresolved reference\",\n \"component\": \"Vm\",\n \"event\": \"ext.Unknown\",\n \"handler\": \"OnU\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", "stderr": "\n2 findings, 1 advisory (OWN050), 1 suppressed ([OwnIgnore]).\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/bands-sarif-warning-quiet.case.json b/tests/fixtures/cli_ownir/bands-sarif-warning-quiet.case.json index 696b01fb..19cb988e 100644 --- a/tests/fixtures/cli_ownir/bands-sarif-warning-quiet.case.json +++ b/tests/fixtures/cli_ownir/bands-sarif-warning-quiet.case.json @@ -14,7 +14,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", "stderr": "\n2 findings (1 advisory hidden), 1 suppressed ([OwnIgnore]).\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/bands-sarif-warning-verbose.case.json b/tests/fixtures/cli_ownir/bands-sarif-warning-verbose.case.json index 630f612e..e0ba5250 100644 --- a/tests/fixtures/cli_ownir/bands-sarif-warning-verbose.case.json +++ b/tests/fixtures/cli_ownir/bands-sarif-warning-verbose.case.json @@ -14,7 +14,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n },\n {\n \"id\": \"OWN050\",\n \"shortDescription\": {\n \"text\": \"declaring type unresolved -- leakage analysis skipped\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN050\",\n \"level\": \"note\",\n \"message\": {\n \"text\": \"cannot verify 'ext.Unknown' \\u2014 its declaring type is an unresolved reference (build the project or pass references); leakage analysis skipped [resource: unresolved reference]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 13\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"unresolved reference\",\n \"component\": \"Vm\",\n \"event\": \"ext.Unknown\",\n \"handler\": \"OnU\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n },\n {\n \"id\": \"OWN050\",\n \"shortDescription\": {\n \"text\": \"declaring type unresolved -- leakage analysis skipped\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Injected' is subscribed (handler 'OnI') but never unsubscribed; its source is an injected dependency whose lifetime is unknown, so it may outlive and keep 'Vm' alive (possible leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Injected\",\n \"handler\": \"OnI\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 11\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n },\n {\n \"ruleId\": \"OWN050\",\n \"level\": \"note\",\n \"message\": {\n \"text\": \"cannot verify 'ext.Unknown' \\u2014 its declaring type is an unresolved reference (build the project or pass references); leakage analysis skipped [resource: unresolved reference]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 13\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"unresolved reference\",\n \"component\": \"Vm\",\n \"event\": \"ext.Unknown\",\n \"handler\": \"OnU\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Ignored' is subscribed (handler 'OnG') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 12\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Ignored\",\n \"handler\": \"OnG\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", "stderr": "\n2 findings, 1 advisory (OWN050), 1 suppressed ([OwnIgnore]).\n by code: OWN001=3, OWN050=1\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/clean-sarif.case.json b/tests/fixtures/cli_ownir/clean-sarif.case.json index bd060f59..a78e26c9 100644 --- a/tests/fixtures/cli_ownir/clean-sarif.case.json +++ b/tests/fixtures/cli_ownir/clean-sarif.case.json @@ -10,7 +10,7 @@ "env": {}, "expected": { "exit": 0, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": []\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": []\n }\n ]\n}\n", "stderr": "../verdict_renders/render_empty.facts.json: ok — no subscription leaks found\n\n0 findings.\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/inputs/empty_ignore_reason.facts.json b/tests/fixtures/cli_ownir/inputs/empty_ignore_reason.facts.json index e09206bc..5ad23da6 100644 --- a/tests/fixtures/cli_ownir/inputs/empty_ignore_reason.facts.json +++ b/tests/fixtures/cli_ownir/inputs/empty_ignore_reason.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "EmptyReason", "_doc": [ "BR-V6: a reason-less [OwnIgnore] never suppresses. `ignore_reason` is", diff --git a/tests/fixtures/cli_ownir/inputs/nonascii_file.facts.json b/tests/fixtures/cli_ownir/inputs/nonascii_file.facts.json index cefc3c7a..6c64c8c1 100644 --- a/tests/fixtures/cli_ownir/inputs/nonascii_file.facts.json +++ b/tests/fixtures/cli_ownir/inputs/nonascii_file.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "NonAscii", "_doc": [ "A component whose FILE carries non-ASCII (and an astral character):", diff --git "a/tests/fixtures/cli_ownir/inputs/pa th \303\274n\303\257c\303\270d\303\251/facts.json" "b/tests/fixtures/cli_ownir/inputs/pa th \303\274n\303\257c\303\270d\303\251/facts.json" index 7f67d236..de27162e 100644 --- "a/tests/fixtures/cli_ownir/inputs/pa th \303\274n\303\257c\303\270d\303\251/facts.json" +++ "b/tests/fixtures/cli_ownir/inputs/pa th \303\274n\303\257c\303\270d\303\251/facts.json" @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "SpacedPath", "_doc": [ "Reached through a directory whose name carries a space and non-ASCII:", diff --git a/tests/fixtures/cli_ownir/inputs/suppressed_only.facts.json b/tests/fixtures/cli_ownir/inputs/suppressed_only.facts.json index 7ea3c91c..a0432bd4 100644 --- a/tests/fixtures/cli_ownir/inputs/suppressed_only.facts.json +++ b/tests/fixtures/cli_ownir/inputs/suppressed_only.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "SuppressedOnly", "_doc": [ "Every finding is [OwnIgnore]-suppressed: the run prints the `ok` line", diff --git a/tests/fixtures/cli_ownir/leaky-sarif-error.case.json b/tests/fixtures/cli_ownir/leaky-sarif-error.case.json index 1bc4fc99..f996a4f2 100644 --- a/tests/fixtures/cli_ownir/leaky-sarif-error.case.json +++ b/tests/fixtures/cli_ownir/leaky-sarif-error.case.json @@ -12,7 +12,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Anchored' is subscribed (handler 'OnA') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 9,\n \"startColumn\": 17\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Anchored\",\n \"handler\": \"OnA\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Bare' is subscribed (handler 'OnB') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Bare\",\n \"handler\": \"OnB\"\n }\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Anchored' is subscribed (handler 'OnA') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 9,\n \"startColumn\": 17\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Anchored\",\n \"handler\": \"OnA\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Bare' is subscribed (handler 'OnB') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Bare\",\n \"handler\": \"OnB\"\n }\n }\n ]\n }\n ]\n}\n", "stderr": "\n2 findings.\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/leaky-sarif-warning.case.json b/tests/fixtures/cli_ownir/leaky-sarif-warning.case.json index d4a141c7..1720818c 100644 --- a/tests/fixtures/cli_ownir/leaky-sarif-warning.case.json +++ b/tests/fixtures/cli_ownir/leaky-sarif-warning.case.json @@ -12,7 +12,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Anchored' is subscribed (handler 'OnA') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 9,\n \"startColumn\": 17\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Anchored\",\n \"handler\": \"OnA\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Bare' is subscribed (handler 'OnB') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Bare\",\n \"handler\": \"OnB\"\n }\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Anchored' is subscribed (handler 'OnA') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 9,\n \"startColumn\": 17\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Anchored\",\n \"handler\": \"OnA\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"warning\",\n \"message\": {\n \"text\": \"event 'bus.Bare' is subscribed (handler 'OnB') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Bare\",\n \"handler\": \"OnB\"\n }\n }\n ]\n }\n ]\n}\n", "stderr": "\n2 findings.\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/path-backslash-file-sarif.case.json b/tests/fixtures/cli_ownir/path-backslash-file-sarif.case.json index 84a6fcf3..8a0b95d7 100644 --- a/tests/fixtures/cli_ownir/path-backslash-file-sarif.case.json +++ b/tests/fixtures/cli_ownir/path-backslash-file-sarif.case.json @@ -10,7 +10,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.50% off\\r\\nnext' is subscribed (handler 'OnE') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"src/gen:a,b.cs\"\n },\n \"region\": {\n \"startLine\": 7\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.50% off\\r\\nnext\",\n \"handler\": \"OnE\"\n }\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.50% off\\r\\nnext' is subscribed (handler 'OnE') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"src/gen:a,b.cs\"\n },\n \"region\": {\n \"startLine\": 7\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.50% off\\r\\nnext\",\n \"handler\": \"OnE\"\n }\n }\n ]\n }\n ]\n}\n", "stderr": "\n1 finding.\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/path-nonascii-file-sarif.case.json b/tests/fixtures/cli_ownir/path-nonascii-file-sarif.case.json index f9b4011a..ad9bd923 100644 --- a/tests/fixtures/cli_ownir/path-nonascii-file-sarif.case.json +++ b/tests/fixtures/cli_ownir/path-nonascii-file-sarif.case.json @@ -10,7 +10,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"src/\\u00dcn\\u00efc\\u00f8d\\u00e9/\\u0412\\u044c\\u044e_\\ud83d\\ude00.cs\"\n },\n \"region\": {\n \"startLine\": 4\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"src/\\u00dcn\\u00efc\\u00f8d\\u00e9/\\u0412\\u044c\\u044e_\\ud83d\\ude00.cs\"\n },\n \"region\": {\n \"startLine\": 4\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n }\n }\n ]\n }\n ]\n}\n", "stderr": "\n1 finding.\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/refuse-version-mismatch.case.json b/tests/fixtures/cli_ownir/refuse-version-mismatch.case.json index 69bae7ac..dfce65c6 100644 --- a/tests/fixtures/cli_ownir/refuse-version-mismatch.case.json +++ b/tests/fixtures/cli_ownir/refuse-version-mismatch.case.json @@ -9,7 +9,7 @@ "expected": { "exit": 2, "stdout": "", - "stderr": "inputs/version_mismatch.facts.json: error: OwnIR facts are schema v99, but this core understands v0. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it.\n", + "stderr": "inputs/version_mismatch.facts.json: error: OwnIR facts are schema v99, but this core understands v1. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it.\n", "os_error_tail": null } } diff --git a/tests/fixtures/cli_ownir/sarif-ascii-escape-em-dash.case.json b/tests/fixtures/cli_ownir/sarif-ascii-escape-em-dash.case.json index 5ef6ffe3..20d8683a 100644 --- a/tests/fixtures/cli_ownir/sarif-ascii-escape-em-dash.case.json +++ b/tests/fixtures/cli_ownir/sarif-ascii-escape-em-dash.case.json @@ -10,7 +10,7 @@ "env": {}, "expected": { "exit": 1, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Anchored' is subscribed (handler 'OnA') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 9,\n \"startColumn\": 17\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Anchored\",\n \"handler\": \"OnA\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Bare' is subscribed (handler 'OnB') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Bare\",\n \"handler\": \"OnB\"\n }\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Anchored' is subscribed (handler 'OnA') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 9,\n \"startColumn\": 17\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Anchored\",\n \"handler\": \"OnA\"\n }\n },\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'bus.Bare' is subscribed (handler 'OnB') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 10\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"bus.Bare\",\n \"handler\": \"OnB\"\n }\n }\n ]\n }\n ]\n}\n", "stderr": "\n2 findings.\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/suppressed-only-sarif.case.json b/tests/fixtures/cli_ownir/suppressed-only-sarif.case.json index 03adfc2c..ff8723f4 100644 --- a/tests/fixtures/cli_ownir/suppressed-only-sarif.case.json +++ b/tests/fixtures/cli_ownir/suppressed-only-sarif.case.json @@ -10,7 +10,7 @@ "env": {}, "expected": { "exit": 0, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 7\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [\n {\n \"id\": \"OWN001\",\n \"shortDescription\": {\n \"text\": \"owned resource not released on all paths (possible leak)\"\n }\n }\n ],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": [\n {\n \"ruleId\": \"OWN001\",\n \"level\": \"error\",\n \"message\": {\n \"text\": \"event 'SystemEvents.Static' is subscribed (handler 'OnS') but never unsubscribed \\u2014 the source keeps 'Vm' alive (leak) [resource: subscription token]\"\n },\n \"locations\": [\n {\n \"physicalLocation\": {\n \"artifactLocation\": {\n \"uri\": \"Vm.cs\"\n },\n \"region\": {\n \"startLine\": 7\n }\n }\n }\n ],\n \"properties\": {\n \"resourceKind\": \"subscription token\",\n \"component\": \"Vm\",\n \"event\": \"SystemEvents.Static\",\n \"handler\": \"OnS\"\n },\n \"suppressions\": [\n {\n \"kind\": \"inSource\",\n \"justification\": \"owned by the host container\"\n }\n ]\n }\n ]\n }\n ]\n}\n", "stderr": "inputs/suppressed_only.facts.json: ok — no subscription leaks found\n\n0 findings, 1 suppressed ([OwnIgnore]).\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/usage-duplicate-flag-last-wins.case.json b/tests/fixtures/cli_ownir/usage-duplicate-flag-last-wins.case.json index 9b003cdb..60e0fb9b 100644 --- a/tests/fixtures/cli_ownir/usage-duplicate-flag-last-wins.case.json +++ b/tests/fixtures/cli_ownir/usage-duplicate-flag-last-wins.case.json @@ -10,7 +10,7 @@ "env": {}, "expected": { "exit": 0, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": []\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": []\n }\n ]\n}\n", "stderr": "../verdict_renders/render_empty.facts.json: ok — no subscription leaks found\n\n0 findings.\n", "os_error_tail": null } diff --git a/tests/fixtures/cli_ownir/usage-equals-spelling-accepted.case.json b/tests/fixtures/cli_ownir/usage-equals-spelling-accepted.case.json index 9afa2ec3..61942cdd 100644 --- a/tests/fixtures/cli_ownir/usage-equals-spelling-accepted.case.json +++ b/tests/fixtures/cli_ownir/usage-equals-spelling-accepted.case.json @@ -9,7 +9,7 @@ "env": {}, "expected": { "exit": 0, - "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [],\n \"properties\": {\n \"ownirSchemaVersion\": 0\n }\n }\n },\n \"results\": []\n }\n ]\n}\n", + "stdout": "{\n \"$schema\": \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\",\n \"version\": \"2.1.0\",\n \"runs\": [\n {\n \"tool\": {\n \"driver\": {\n \"name\": \"Owen\",\n \"informationUri\": \"https://github.com/PhysShell/Own.NET\",\n \"rules\": [],\n \"properties\": {\n \"ownirSchemaVersion\": 1\n }\n }\n },\n \"results\": []\n }\n ]\n}\n", "stderr": "../verdict_renders/render_empty.facts.json: ok — no subscription leaks found\n\n0 findings.\n", "os_error_tail": null } diff --git a/tests/fixtures/lowered/alias_join_cases.facts.json b/tests/fixtures/lowered/alias_join_cases.facts.json index 08a4ae2b..6f6124d8 100644 --- a/tests/fixtures/lowered/alias_join_cases.facts.json +++ b/tests/fixtures/lowered/alias_join_cases.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Alias", "functions": [ { diff --git a/tests/fixtures/lowered/alias_join_cases.golden.json b/tests/fixtures/lowered/alias_join_cases.golden.json index 80bc95bc..d7e687da 100644 --- a/tests/fixtures/lowered/alias_join_cases.golden.json +++ b/tests/fixtures/lowered/alias_join_cases.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Alias", "resources": [ { diff --git a/tests/fixtures/lowered/flow_kill_on_rebind.facts.json b/tests/fixtures/lowered/flow_kill_on_rebind.facts.json index 90f3ed80..1d65275e 100644 --- a/tests/fixtures/lowered/flow_kill_on_rebind.facts.json +++ b/tests/fixtures/lowered/flow_kill_on_rebind.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Rebind", "functions": [ { diff --git a/tests/fixtures/lowered/flow_kill_on_rebind.golden.json b/tests/fixtures/lowered/flow_kill_on_rebind.golden.json index d4791147..4d1b389e 100644 --- a/tests/fixtures/lowered/flow_kill_on_rebind.golden.json +++ b/tests/fixtures/lowered/flow_kill_on_rebind.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Rebind", "resources": [ { diff --git a/tests/fixtures/lowered/flow_unmapped_refs.facts.json b/tests/fixtures/lowered/flow_unmapped_refs.facts.json index 80bdd19b..93aa73b2 100644 --- a/tests/fixtures/lowered/flow_unmapped_refs.facts.json +++ b/tests/fixtures/lowered/flow_unmapped_refs.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Unmapped", "functions": [ { diff --git a/tests/fixtures/lowered/flow_unmapped_refs.golden.json b/tests/fixtures/lowered/flow_unmapped_refs.golden.json index 3a26751a..d79f4c55 100644 --- a/tests/fixtures/lowered/flow_unmapped_refs.golden.json +++ b/tests/fixtures/lowered/flow_unmapped_refs.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Unmapped", "resources": [ { diff --git a/tests/fixtures/lowered/fn_params_ordering.facts.json b/tests/fixtures/lowered/fn_params_ordering.facts.json index 32850b34..9bd29f2d 100644 --- a/tests/fixtures/lowered/fn_params_ordering.facts.json +++ b/tests/fixtures/lowered/fn_params_ordering.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Params", "functions": [ { diff --git a/tests/fixtures/lowered/fn_params_ordering.golden.json b/tests/fixtures/lowered/fn_params_ordering.golden.json index 65bb9e67..9cbc7363 100644 --- a/tests/fixtures/lowered/fn_params_ordering.golden.json +++ b/tests/fixtures/lowered/fn_params_ordering.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Params", "resources": [ { diff --git a/tests/fixtures/lowered/handles_global_counters.facts.json b/tests/fixtures/lowered/handles_global_counters.facts.json index d9aac604..94d7c7b6 100644 --- a/tests/fixtures/lowered/handles_global_counters.facts.json +++ b/tests/fixtures/lowered/handles_global_counters.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Counters", "components": [ { diff --git a/tests/fixtures/lowered/handles_global_counters.golden.json b/tests/fixtures/lowered/handles_global_counters.golden.json index 2eb1a399..6e503d3d 100644 --- a/tests/fixtures/lowered/handles_global_counters.golden.json +++ b/tests/fixtures/lowered/handles_global_counters.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Counters", "resources": [ { diff --git a/tests/fixtures/lowered/handles_null_metadata.facts.json b/tests/fixtures/lowered/handles_null_metadata.facts.json index e09d2e52..8f49eef2 100644 --- a/tests/fixtures/lowered/handles_null_metadata.facts.json +++ b/tests/fixtures/lowered/handles_null_metadata.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "NullMeta", "components": [ { diff --git a/tests/fixtures/lowered/handles_null_metadata.golden.json b/tests/fixtures/lowered/handles_null_metadata.golden.json index 1ecac10c..8eea0723 100644 --- a/tests/fixtures/lowered/handles_null_metadata.golden.json +++ b/tests/fixtures/lowered/handles_null_metadata.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "NullMeta", "resources": [ { diff --git a/tests/fixtures/lowered/hoist_neg_early_return.facts.json b/tests/fixtures/lowered/hoist_neg_early_return.facts.json index 7391db70..65e99f30 100644 --- a/tests/fixtures/lowered/hoist_neg_early_return.facts.json +++ b/tests/fixtures/lowered/hoist_neg_early_return.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "HoistNeg3", "functions": [ { diff --git a/tests/fixtures/lowered/hoist_neg_early_return.golden.json b/tests/fixtures/lowered/hoist_neg_early_return.golden.json index b71d10d5..fa00e419 100644 --- a/tests/fixtures/lowered/hoist_neg_early_return.golden.json +++ b/tests/fixtures/lowered/hoist_neg_early_return.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "HoistNeg3", "resources": [ { diff --git a/tests/fixtures/lowered/hoist_neg_nested_depth.facts.json b/tests/fixtures/lowered/hoist_neg_nested_depth.facts.json index dd6428b2..26eb4ec0 100644 --- a/tests/fixtures/lowered/hoist_neg_nested_depth.facts.json +++ b/tests/fixtures/lowered/hoist_neg_nested_depth.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "HoistNeg1", "functions": [ { diff --git a/tests/fixtures/lowered/hoist_neg_nested_depth.golden.json b/tests/fixtures/lowered/hoist_neg_nested_depth.golden.json index 63cbee3c..00446216 100644 --- a/tests/fixtures/lowered/hoist_neg_nested_depth.golden.json +++ b/tests/fixtures/lowered/hoist_neg_nested_depth.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "HoistNeg1", "resources": [ { diff --git a/tests/fixtures/lowered/hoist_neg_while_body.facts.json b/tests/fixtures/lowered/hoist_neg_while_body.facts.json index a55a0f16..4fd47302 100644 --- a/tests/fixtures/lowered/hoist_neg_while_body.facts.json +++ b/tests/fixtures/lowered/hoist_neg_while_body.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "HoistNeg2", "functions": [ { diff --git a/tests/fixtures/lowered/hoist_neg_while_body.golden.json b/tests/fixtures/lowered/hoist_neg_while_body.golden.json index 616bac85..86174ba4 100644 --- a/tests/fixtures/lowered/hoist_neg_while_body.golden.json +++ b/tests/fixtures/lowered/hoist_neg_while_body.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "HoistNeg2", "resources": [ { diff --git a/tests/fixtures/lowered/hoist_pool_kind.facts.json b/tests/fixtures/lowered/hoist_pool_kind.facts.json index 3bc2dad9..e4857ec9 100644 --- a/tests/fixtures/lowered/hoist_pool_kind.facts.json +++ b/tests/fixtures/lowered/hoist_pool_kind.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "HoistPool", "functions": [ { diff --git a/tests/fixtures/lowered/hoist_pool_kind.golden.json b/tests/fixtures/lowered/hoist_pool_kind.golden.json index 7a4c1418..b59f75dc 100644 --- a/tests/fixtures/lowered/hoist_pool_kind.golden.json +++ b/tests/fixtures/lowered/hoist_pool_kind.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "HoistPool", "resources": [ { diff --git a/tests/fixtures/lowered/hoist_positive_release.facts.json b/tests/fixtures/lowered/hoist_positive_release.facts.json index b047f4cb..ec736570 100644 --- a/tests/fixtures/lowered/hoist_positive_release.facts.json +++ b/tests/fixtures/lowered/hoist_positive_release.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Hoist", "functions": [ { diff --git a/tests/fixtures/lowered/hoist_positive_release.golden.json b/tests/fixtures/lowered/hoist_positive_release.golden.json index 9cbb385a..4b070e14 100644 --- a/tests/fixtures/lowered/hoist_positive_release.golden.json +++ b/tests/fixtures/lowered/hoist_positive_release.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Hoist", "resources": [ { diff --git a/tests/fixtures/lowered/hoist_positive_use_only.facts.json b/tests/fixtures/lowered/hoist_positive_use_only.facts.json index 1249f1f3..83a74b73 100644 --- a/tests/fixtures/lowered/hoist_positive_use_only.facts.json +++ b/tests/fixtures/lowered/hoist_positive_use_only.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "HoistUse", "functions": [ { diff --git a/tests/fixtures/lowered/hoist_positive_use_only.golden.json b/tests/fixtures/lowered/hoist_positive_use_only.golden.json index 8c7cefed..6e128b03 100644 --- a/tests/fixtures/lowered/hoist_positive_use_only.golden.json +++ b/tests/fixtures/lowered/hoist_positive_use_only.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "HoistUse", "resources": [ { diff --git a/tests/fixtures/lowered/lines_preserved.facts.json b/tests/fixtures/lowered/lines_preserved.facts.json index d4070dbf..740d921b 100644 --- a/tests/fixtures/lowered/lines_preserved.facts.json +++ b/tests/fixtures/lowered/lines_preserved.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Lines", "components": [ { diff --git a/tests/fixtures/lowered/lines_preserved.golden.json b/tests/fixtures/lowered/lines_preserved.golden.json index 8ec7dac5..4248d504 100644 --- a/tests/fixtures/lowered/lines_preserved.golden.json +++ b/tests/fixtures/lowered/lines_preserved.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Lines", "resources": [ { diff --git a/tests/fixtures/lowered/manifest.json b/tests/fixtures/lowered/manifest.json index 08a4ba54..6bb93d0c 100644 --- a/tests/fixtures/lowered/manifest.json +++ b/tests/fixtures/lowered/manifest.json @@ -1,6 +1,6 @@ { "comment": "The frozen Layer 2 case ledger (#259). Hand-maintained: adding or removing a case is a deliberate contract change, and the harness requires manifest == facts == goldens exactly, so a fixture pair cannot silently disappear. rust_replay: false marks a Python-only behavior snapshot pinning an open decision (see 'decision'); the Rust own-bridge replays every rust_replay: true case byte-for-byte.", - "lowered_version": 1, + "lowered_version": 2, "cases": [ { "name": "alias_join_cases", @@ -200,6 +200,271 @@ ], "rust_replay": true }, + { + "name": "typestate_cs_a1_alias_of_entity", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_a2_entity_through_indexer", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_g6_capability_not_spent", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l10_region_inside_try", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l11_region_beside_disposable", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l12_region_beside_leaked_disposable", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l13_values_captured_into_region", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l1_stale_capability", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l2_copied_capability", + "rules": [ + "BR-L12", + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l3_raw_mutation", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l4_raw_escape", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l5_normal_transition", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l6_two_transitions", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l6b_chained_transitions", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l7_read_after_region", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l8_branch_inside_region", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_l9_opaque_calls_around_region", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_cs_x1_nested_region_same_entity", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_ef_orderbackend", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_g6_capability_not_spent", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l1_stale_capability", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l2_copied_capability", + "rules": [ + "BR-L12", + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l3_raw_entity_mutation", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l3b_second_region", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l4_raw_entity_unknown_call", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l4b_raw_entity_shared_call", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l4c_raw_entity_consumed", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l4d_token_unknown_call", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l5_normal_transition", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l5b_two_transitions", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_l5c_read_after_region", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_n1_token_spent_on_other_entity", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_n2_two_tokens_one_region", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_n3_raw_mutation_inferred_effect", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_n4_token_outlives_region", + "rules": [ + "BR-L13" + ], + "rust_replay": true + }, + { + "name": "typestate_w1_loan_wordings", + "rules": [ + "BR-L12", + "BR-L13", + "BR-V4" + ], + "rust_replay": true + }, + { + "name": "typestate_w2_loan_wordings_pooled", + "rules": [ + "BR-L12", + "BR-L13", + "BR-V4" + ], + "rust_replay": true + }, { "name": "vocab_unknown_op", "rules": [ diff --git a/tests/fixtures/lowered/mos_call_channel_overload_sig.facts.json b/tests/fixtures/lowered/mos_call_channel_overload_sig.facts.json index 2eb9eec9..4bd22d8f 100644 --- a/tests/fixtures/lowered/mos_call_channel_overload_sig.facts.json +++ b/tests/fixtures/lowered/mos_call_channel_overload_sig.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Overloads", "functions": [ { diff --git a/tests/fixtures/lowered/mos_call_channel_overload_sig.golden.json b/tests/fixtures/lowered/mos_call_channel_overload_sig.golden.json index 5f89d2ec..5baf3c83 100644 --- a/tests/fixtures/lowered/mos_call_channel_overload_sig.golden.json +++ b/tests/fixtures/lowered/mos_call_channel_overload_sig.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Overloads", "resources": [ { diff --git a/tests/fixtures/lowered/mos_call_direct_consume.facts.json b/tests/fixtures/lowered/mos_call_direct_consume.facts.json index 06febc9d..3b00bf1f 100644 --- a/tests/fixtures/lowered/mos_call_direct_consume.facts.json +++ b/tests/fixtures/lowered/mos_call_direct_consume.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Direct", "functions": [ { diff --git a/tests/fixtures/lowered/mos_call_direct_consume.golden.json b/tests/fixtures/lowered/mos_call_direct_consume.golden.json index 5ec4317d..3b3fb7ab 100644 --- a/tests/fixtures/lowered/mos_call_direct_consume.golden.json +++ b/tests/fixtures/lowered/mos_call_direct_consume.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Direct", "resources": [ { diff --git a/tests/fixtures/lowered/mos_call_unknown_drop.facts.json b/tests/fixtures/lowered/mos_call_unknown_drop.facts.json index c225ca25..1ecbe439 100644 --- a/tests/fixtures/lowered/mos_call_unknown_drop.facts.json +++ b/tests/fixtures/lowered/mos_call_unknown_drop.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Drop", "functions": [ { diff --git a/tests/fixtures/lowered/mos_call_unknown_drop.golden.json b/tests/fixtures/lowered/mos_call_unknown_drop.golden.json index 5b7a3a52..b5383dea 100644 --- a/tests/fixtures/lowered/mos_call_unknown_drop.golden.json +++ b/tests/fixtures/lowered/mos_call_unknown_drop.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Drop", "resources": [ { diff --git a/tests/fixtures/lowered/mos_fresh_mint.facts.json b/tests/fixtures/lowered/mos_fresh_mint.facts.json index 8a6e910b..fcb16e30 100644 --- a/tests/fixtures/lowered/mos_fresh_mint.facts.json +++ b/tests/fixtures/lowered/mos_fresh_mint.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Fresh", "functions": [ { diff --git a/tests/fixtures/lowered/mos_fresh_mint.golden.json b/tests/fixtures/lowered/mos_fresh_mint.golden.json index eb875eed..2817d8e7 100644 --- a/tests/fixtures/lowered/mos_fresh_mint.golden.json +++ b/tests/fixtures/lowered/mos_fresh_mint.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Fresh", "resources": [ { diff --git a/tests/fixtures/lowered/mos_killsite_toplevel.facts.json b/tests/fixtures/lowered/mos_killsite_toplevel.facts.json index 4a28235c..18a69151 100644 --- a/tests/fixtures/lowered/mos_killsite_toplevel.facts.json +++ b/tests/fixtures/lowered/mos_killsite_toplevel.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "KillSite", "functions": [ { diff --git a/tests/fixtures/lowered/mos_killsite_toplevel.golden.json b/tests/fixtures/lowered/mos_killsite_toplevel.golden.json index 17b38129..897c0824 100644 --- a/tests/fixtures/lowered/mos_killsite_toplevel.golden.json +++ b/tests/fixtures/lowered/mos_killsite_toplevel.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "KillSite", "resources": [ { diff --git a/tests/fixtures/lowered/mos_untrack_inbranch.facts.json b/tests/fixtures/lowered/mos_untrack_inbranch.facts.json index 7623d084..78b93728 100644 --- a/tests/fixtures/lowered/mos_untrack_inbranch.facts.json +++ b/tests/fixtures/lowered/mos_untrack_inbranch.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Untrack", "functions": [ { diff --git a/tests/fixtures/lowered/mos_untrack_inbranch.golden.json b/tests/fixtures/lowered/mos_untrack_inbranch.golden.json index 68248fda..057496bb 100644 --- a/tests/fixtures/lowered/mos_untrack_inbranch.golden.json +++ b/tests/fixtures/lowered/mos_untrack_inbranch.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "Untrack", "resources": [ { diff --git a/tests/fixtures/lowered/routing_r1_unresolved.facts.json b/tests/fixtures/lowered/routing_r1_unresolved.facts.json index 51734477..aa5da99e 100644 --- a/tests/fixtures/lowered/routing_r1_unresolved.facts.json +++ b/tests/fixtures/lowered/routing_r1_unresolved.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "R1", "components": [ { diff --git a/tests/fixtures/lowered/routing_r1_unresolved.golden.json b/tests/fixtures/lowered/routing_r1_unresolved.golden.json index c1faff33..3164f9fb 100644 --- a/tests/fixtures/lowered/routing_r1_unresolved.golden.json +++ b/tests/fixtures/lowered/routing_r1_unresolved.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "R1", "resources": [ { diff --git a/tests/fixtures/lowered/routing_r2_subscribe_self.facts.json b/tests/fixtures/lowered/routing_r2_subscribe_self.facts.json index c88e1789..1a9a4879 100644 --- a/tests/fixtures/lowered/routing_r2_subscribe_self.facts.json +++ b/tests/fixtures/lowered/routing_r2_subscribe_self.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "R2", "components": [ { diff --git a/tests/fixtures/lowered/routing_r2_subscribe_self.golden.json b/tests/fixtures/lowered/routing_r2_subscribe_self.golden.json index 4abbe0de..b19f88e2 100644 --- a/tests/fixtures/lowered/routing_r2_subscribe_self.golden.json +++ b/tests/fixtures/lowered/routing_r2_subscribe_self.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "R2", "resources": [ { diff --git a/tests/fixtures/lowered/routing_r3_capture_static.facts.json b/tests/fixtures/lowered/routing_r3_capture_static.facts.json index 2beca0c8..74077eab 100644 --- a/tests/fixtures/lowered/routing_r3_capture_static.facts.json +++ b/tests/fixtures/lowered/routing_r3_capture_static.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "R3", "components": [ { diff --git a/tests/fixtures/lowered/routing_r3_capture_static.golden.json b/tests/fixtures/lowered/routing_r3_capture_static.golden.json index cff46efd..b2cf0552 100644 --- a/tests/fixtures/lowered/routing_r3_capture_static.golden.json +++ b/tests/fixtures/lowered/routing_r3_capture_static.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "R3", "resources": [ { diff --git a/tests/fixtures/lowered/routing_r4_returned_fresh.facts.json b/tests/fixtures/lowered/routing_r4_returned_fresh.facts.json index a4fa4707..adb55f8d 100644 --- a/tests/fixtures/lowered/routing_r4_returned_fresh.facts.json +++ b/tests/fixtures/lowered/routing_r4_returned_fresh.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "R4", "components": [ { diff --git a/tests/fixtures/lowered/routing_r4_returned_fresh.golden.json b/tests/fixtures/lowered/routing_r4_returned_fresh.golden.json index c3726089..fbaf66ec 100644 --- a/tests/fixtures/lowered/routing_r4_returned_fresh.golden.json +++ b/tests/fixtures/lowered/routing_r4_returned_fresh.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "R4", "resources": [ { diff --git a/tests/fixtures/lowered/routing_r5_di_capture.facts.json b/tests/fixtures/lowered/routing_r5_di_capture.facts.json index 24617c4d..d3e70e6b 100644 --- a/tests/fixtures/lowered/routing_r5_di_capture.facts.json +++ b/tests/fixtures/lowered/routing_r5_di_capture.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "R5", "components": [ { diff --git a/tests/fixtures/lowered/routing_r5_di_capture.golden.json b/tests/fixtures/lowered/routing_r5_di_capture.golden.json index ebfdbda2..3d572e00 100644 --- a/tests/fixtures/lowered/routing_r5_di_capture.golden.json +++ b/tests/fixtures/lowered/routing_r5_di_capture.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "R5", "resources": [ { diff --git a/tests/fixtures/lowered/routing_r6_token_kinds.facts.json b/tests/fixtures/lowered/routing_r6_token_kinds.facts.json index cc9dcc94..5e87ce03 100644 --- a/tests/fixtures/lowered/routing_r6_token_kinds.facts.json +++ b/tests/fixtures/lowered/routing_r6_token_kinds.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "R6", "components": [ { diff --git a/tests/fixtures/lowered/routing_r6_token_kinds.golden.json b/tests/fixtures/lowered/routing_r6_token_kinds.golden.json index fd157e1a..18e2c5cb 100644 --- a/tests/fixtures/lowered/routing_r6_token_kinds.golden.json +++ b/tests/fixtures/lowered/routing_r6_token_kinds.golden.json @@ -1,5 +1,5 @@ { - "lowered_version": 1, + "lowered_version": 2, "module": "R6", "resources": [ { diff --git a/tests/fixtures/lowered/tolerant_unknown_kind.facts.json b/tests/fixtures/lowered/tolerant_unknown_kind.facts.json index 1a60649e..ed817928 100644 --- a/tests/fixtures/lowered/tolerant_unknown_kind.facts.json +++ b/tests/fixtures/lowered/tolerant_unknown_kind.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "OD2", "components": [ { diff --git a/tests/fixtures/lowered/tolerant_unknown_kind.golden.json b/tests/fixtures/lowered/tolerant_unknown_kind.golden.json index 4f4692cf..273fb9c7 100644 --- a/tests/fixtures/lowered/tolerant_unknown_kind.golden.json +++ b/tests/fixtures/lowered/tolerant_unknown_kind.golden.json @@ -1,4 +1,4 @@ { - "lowered_version": 1, + "lowered_version": 2, "error": "unknown resource kind 'mutex' — a new kind is a vocabulary change that must bump OWNIR_VERSION (see spec/OwnIR.md §2)" } diff --git a/tests/fixtures/lowered/typestate_cs_a1_alias_of_entity.facts.json b/tests/fixtures/lowered/typestate_cs_a1_alias_of_entity.facts.json new file mode 100644 index 00000000..6d4eee76 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_a1_alias_of_entity.facts.json @@ -0,0 +1,79 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.A1AliasOfEntity.Run", + "file": "frontend/roslyn/protocol-samples/cases/A1_alias_of_entity.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 15 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 15, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 15 + }, + { + "op": "use", + "var": "order", + "line": 17 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 18 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 15 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_a1_alias_of_entity.golden.json b/tests/fixtures/lowered/typestate_cs_a1_alias_of_entity.golden.json new file mode 100644 index 00000000..ec3a2a4e --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_a1_alias_of_entity.golden.json @@ -0,0 +1,215 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.A1AliasOfEntity.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 15 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 15 + }, + { + "stmt": "use", + "handle": "loc_0", + "line": 17 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 18 + } + ], + "line": 15 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 15 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_3", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.A1AliasOfEntity.Run", + "file": "frontend/roslyn/protocol-samples/cases/A1_alias_of_entity.cs", + "line": 15, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.A1AliasOfEntity.Run", + "file": "frontend/roslyn/protocol-samples/cases/A1_alias_of_entity.cs", + "line": 15, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_3", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_a2_entity_through_indexer.facts.json b/tests/fixtures/lowered/typestate_cs_a2_entity_through_indexer.facts.json new file mode 100644 index 00000000..1d232591 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_a2_entity_through_indexer.facts.json @@ -0,0 +1,79 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.A2EntityThroughIndexer.Run", + "file": "frontend/roslyn/protocol-samples/cases/A2_entity_through_indexer.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 15 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 15, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 15 + }, + { + "op": "use", + "var": "order", + "line": 17 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 18 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 15 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_a2_entity_through_indexer.golden.json b/tests/fixtures/lowered/typestate_cs_a2_entity_through_indexer.golden.json new file mode 100644 index 00000000..7aacf30e --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_a2_entity_through_indexer.golden.json @@ -0,0 +1,215 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.A2EntityThroughIndexer.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 15 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 15 + }, + { + "stmt": "use", + "handle": "loc_0", + "line": 17 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 18 + } + ], + "line": 15 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 15 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_3", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.A2EntityThroughIndexer.Run", + "file": "frontend/roslyn/protocol-samples/cases/A2_entity_through_indexer.cs", + "line": 15, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.A2EntityThroughIndexer.Run", + "file": "frontend/roslyn/protocol-samples/cases/A2_entity_through_indexer.cs", + "line": 15, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_3", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_g6_capability_not_spent.facts.json b/tests/fixtures/lowered/typestate_cs_g6_capability_not_spent.facts.json new file mode 100644 index 00000000..7ad4bfcb --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_g6_capability_not_spent.facts.json @@ -0,0 +1,42 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.G6CapabilityNotSpent.Run", + "file": "frontend/roslyn/protocol-samples/cases/G6_capability_not_spent.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 13 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 13, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 13 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 13 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_g6_capability_not_spent.golden.json b/tests/fixtures/lowered/typestate_cs_g6_capability_not_spent.golden.json new file mode 100644 index 00000000..43018bdf --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_g6_capability_not_spent.golden.json @@ -0,0 +1,149 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.G6CapabilityNotSpent.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 13 + } + ], + "line": 13 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 13 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.G6CapabilityNotSpent.Run", + "file": "frontend/roslyn/protocol-samples/cases/G6_capability_not_spent.cs", + "line": 13, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.G6CapabilityNotSpent.Run", + "file": "frontend/roslyn/protocol-samples/cases/G6_capability_not_spent.cs", + "line": 13, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l10_region_inside_try.facts.json b/tests/fixtures/lowered/typestate_cs_l10_region_inside_try.facts.json new file mode 100644 index 00000000..7ee861d3 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l10_region_inside_try.facts.json @@ -0,0 +1,74 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L10RegionInsideTry.Run", + "file": "frontend/roslyn/protocol-samples/cases/L10_region_inside_try.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 21 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 21, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 21 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 23 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 21 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l10_region_inside_try.golden.json b/tests/fixtures/lowered/typestate_cs_l10_region_inside_try.golden.json new file mode 100644 index 00000000..da06b74e --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l10_region_inside_try.golden.json @@ -0,0 +1,210 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L10RegionInsideTry.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 21 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 21 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 23 + } + ], + "line": 21 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 21 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_3", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L10RegionInsideTry.Run", + "file": "frontend/roslyn/protocol-samples/cases/L10_region_inside_try.cs", + "line": 21, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L10RegionInsideTry.Run", + "file": "frontend/roslyn/protocol-samples/cases/L10_region_inside_try.cs", + "line": 21, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_3", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l11_region_beside_disposable.facts.json b/tests/fixtures/lowered/typestate_cs_l11_region_beside_disposable.facts.json new file mode 100644 index 00000000..6b5588d8 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l11_region_beside_disposable.facts.json @@ -0,0 +1,98 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L11RegionBesideDisposable.Run", + "file": "frontend/roslyn/protocol-samples/cases/L11_region_beside_disposable.cs", + "sig": "Own.Protocols.Sample.Order", + "body": [ + { + "op": "acquire", + "var": "log", + "line": 15, + "column": 13, + "kind": "disposable" + }, + { + "op": "use", + "var": "log", + "line": 16 + }, + { + "op": "release", + "var": "log", + "line": 21 + } + ] + }, + { + "name": "Own.Protocols.Cases.L11RegionBesideDisposable.Run$protocol", + "file": "frontend/roslyn/protocol-samples/cases/L11_region_beside_disposable.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 17 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 17, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 17 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 19 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 17 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 1, + "methods_flow_analysed": 1, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l11_region_beside_disposable.golden.json b/tests/fixtures/lowered/typestate_cs_l11_region_beside_disposable.golden.json new file mode 100644 index 00000000..8ccba53e --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l11_region_beside_disposable.golden.json @@ -0,0 +1,244 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L11RegionBesideDisposable.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 15 + }, + { + "stmt": "use", + "handle": "loc_0", + "line": 16 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 21 + } + ] + }, + { + "name": "Own.Protocols.Cases.L11RegionBesideDisposable.Run$protocol", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_1", + "resource": "Disposable", + "line": 17 + }, + { + "stmt": "borrow_mut", + "owner": "loc_1", + "binding": "brw_2", + "body": [ + { + "stmt": "acquire", + "handle": "loc_3", + "resource": "Disposable", + "line": 17 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_3", + "brw_2" + ], + "line": 19 + } + ], + "line": 17 + }, + { + "stmt": "release", + "handle": "loc_1", + "line": 17 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L11RegionBesideDisposable.Run", + "file": "frontend/roslyn/protocol-samples/cases/L11_region_beside_disposable.cs", + "line": 15, + "event": "log", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_1", + "component": "Own.Protocols.Cases.L11RegionBesideDisposable.Run$protocol", + "file": "frontend/roslyn/protocol-samples/cases/L11_region_beside_disposable.cs", + "line": 17, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_3", + "component": "Own.Protocols.Cases.L11RegionBesideDisposable.Run$protocol", + "file": "frontend/roslyn/protocol-samples/cases/L11_region_beside_disposable.cs", + "line": 17, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l12_region_beside_leaked_disposable.facts.json b/tests/fixtures/lowered/typestate_cs_l12_region_beside_leaked_disposable.facts.json new file mode 100644 index 00000000..8908084c --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l12_region_beside_leaked_disposable.facts.json @@ -0,0 +1,93 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L12RegionBesideLeakedDisposable.Run", + "file": "frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs", + "sig": "Own.Protocols.Sample.Order", + "body": [ + { + "op": "acquire", + "var": "log", + "line": 14, + "column": 13, + "kind": "disposable" + }, + { + "op": "use", + "var": "log", + "line": 15 + } + ] + }, + { + "name": "Own.Protocols.Cases.L12RegionBesideLeakedDisposable.Run$protocol", + "file": "frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 16 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 16, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 16 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 18 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 16 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 1, + "methods_flow_analysed": 1, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l12_region_beside_leaked_disposable.golden.json b/tests/fixtures/lowered/typestate_cs_l12_region_beside_leaked_disposable.golden.json new file mode 100644 index 00000000..d9c2e77d --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l12_region_beside_leaked_disposable.golden.json @@ -0,0 +1,239 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L12RegionBesideLeakedDisposable.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 14 + }, + { + "stmt": "use", + "handle": "loc_0", + "line": 15 + } + ] + }, + { + "name": "Own.Protocols.Cases.L12RegionBesideLeakedDisposable.Run$protocol", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_1", + "resource": "Disposable", + "line": 16 + }, + { + "stmt": "borrow_mut", + "owner": "loc_1", + "binding": "brw_2", + "body": [ + { + "stmt": "acquire", + "handle": "loc_3", + "resource": "Disposable", + "line": 16 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_3", + "brw_2" + ], + "line": 18 + } + ], + "line": 16 + }, + { + "stmt": "release", + "handle": "loc_1", + "line": 16 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L12RegionBesideLeakedDisposable.Run", + "file": "frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs", + "line": 14, + "event": "log", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_1", + "component": "Own.Protocols.Cases.L12RegionBesideLeakedDisposable.Run$protocol", + "file": "frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs", + "line": 16, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_3", + "component": "Own.Protocols.Cases.L12RegionBesideLeakedDisposable.Run$protocol", + "file": "frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs", + "line": 16, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l13_values_captured_into_region.facts.json b/tests/fixtures/lowered/typestate_cs_l13_values_captured_into_region.facts.json new file mode 100644 index 00000000..813bda94 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l13_values_captured_into_region.facts.json @@ -0,0 +1,96 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L13ValuesCapturedIntoRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L13_values_captured_into_region.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 15 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 15, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 15 + }, + { + "op": "use", + "var": "approved", + "line": 17 + }, + { + "op": "if", + "line": 18, + "then": [ + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 20 + } + ], + "else": [ + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 24 + } + ] + } + ] + }, + { + "op": "release", + "var": "order", + "line": 15 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l13_values_captured_into_region.golden.json b/tests/fixtures/lowered/typestate_cs_l13_values_captured_into_region.golden.json new file mode 100644 index 00000000..522f3865 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l13_values_captured_into_region.golden.json @@ -0,0 +1,233 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L13ValuesCapturedIntoRegion.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 15 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 15 + }, + { + "stmt": "use", + "handle": "loc_2", + "line": 17 + }, + { + "stmt": "if", + "cond": "?", + "then": [ + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 20 + } + ], + "else": [ + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 24 + } + ], + "line": 18 + } + ], + "line": 15 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 15 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_3", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L13ValuesCapturedIntoRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L13_values_captured_into_region.cs", + "line": 15, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L13ValuesCapturedIntoRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L13_values_captured_into_region.cs", + "line": 15, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_3", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l1_stale_capability.facts.json b/tests/fixtures/lowered/typestate_cs_l1_stale_capability.facts.json new file mode 100644 index 00000000..733b1354 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l1_stale_capability.facts.json @@ -0,0 +1,143 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L1StaleCapability.Run", + "file": "frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 13 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 13, + "body": [ + { + "op": "acquire", + "var": "draft", + "line": 13 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Submit", + "args": [ + "draft", + "order.region1" + ], + "line": 15 + }, + { + "op": "acquire", + "var": "submitted", + "line": 15 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Cancel", + "args": [ + "draft", + "order.region1" + ], + "line": 16 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.SubmittedOrder.Approve", + "args": [ + "submitted", + "order.region1" + ], + "line": 17 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 13 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Cancel", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 57 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 57 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 57 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 51 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 51 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 51 + } + ] + }, + { + "name": "Own.Protocols.Sample.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 69 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 69 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 69 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l1_stale_capability.golden.json b/tests/fixtures/lowered/typestate_cs_l1_stale_capability.golden.json new file mode 100644 index 00000000..fc17d984 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l1_stale_capability.golden.json @@ -0,0 +1,348 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L1StaleCapability.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Submit", + "args": [ + "loc_2", + "brw_1" + ], + "line": 15 + }, + { + "stmt": "acquire", + "handle": "loc_3", + "resource": "Disposable", + "line": 15 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Cancel", + "args": [ + "loc_2", + "brw_1" + ], + "line": 16 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.SubmittedOrder.Approve", + "args": [ + "loc_3", + "brw_1" + ], + "line": 17 + } + ], + "line": 13 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 13 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Cancel", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 57, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 57, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 57 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 51, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 51, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 51 + } + ] + }, + { + "name": "Own.Protocols.Sample.SubmittedOrder.Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 69, + "lifetime": null + }, + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 69, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_8", + "line": 69 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L1StaleCapability.Run", + "file": "frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs", + "line": 13, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L1StaleCapability.Run", + "file": "frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs", + "line": 13, + "event": "draft", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_3", + "component": "Own.Protocols.Cases.L1StaleCapability.Run", + "file": "frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs", + "line": 15, + "event": "submitted", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.DraftOrder.Cancel", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 57, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Own.Protocols.Sample.DraftOrder.Cancel", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 57, + "event": "entity", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "Own.Protocols.Sample.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 51, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "Own.Protocols.Sample.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 51, + "event": "entity", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "Own.Protocols.Sample.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 69, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_9", + "component": "Own.Protocols.Sample.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 69, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l2_copied_capability.facts.json b/tests/fixtures/lowered/typestate_cs_l2_copied_capability.facts.json new file mode 100644 index 00000000..eb4bac95 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l2_copied_capability.facts.json @@ -0,0 +1,89 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L2CopiedCapability.Run", + "file": "frontend/roslyn/protocol-samples/cases/L2_copied_capability.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 13 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 13, + "body": [ + { + "op": "acquire", + "var": "draft", + "line": 13 + }, + { + "op": "move", + "var": "copy", + "src": "draft", + "line": 15 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Cancel", + "args": [ + "draft", + "order.region1" + ], + "line": 16 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Cancel", + "args": [ + "copy", + "order.region1" + ], + "line": 17 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 13 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Cancel", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 57 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 57 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 57 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l2_copied_capability.golden.json b/tests/fixtures/lowered/typestate_cs_l2_copied_capability.golden.json new file mode 100644 index 00000000..bd595c5a --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l2_copied_capability.golden.json @@ -0,0 +1,235 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L2CopiedCapability.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "move", + "handle": "loc_3", + "src": "loc_2", + "line": 15 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Cancel", + "args": [ + "loc_2", + "brw_1" + ], + "line": 16 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Cancel", + "args": [ + "loc_3", + "brw_1" + ], + "line": 17 + } + ], + "line": 13 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 13 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Cancel", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 57, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 57, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 57 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L2CopiedCapability.Run", + "file": "frontend/roslyn/protocol-samples/cases/L2_copied_capability.cs", + "line": 13, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L2CopiedCapability.Run", + "file": "frontend/roslyn/protocol-samples/cases/L2_copied_capability.cs", + "line": 13, + "event": "draft", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_3", + "component": "Own.Protocols.Cases.L2CopiedCapability.Run", + "file": "frontend/roslyn/protocol-samples/cases/L2_copied_capability.cs", + "line": 15, + "event": "copy", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.DraftOrder.Cancel", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 57, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Own.Protocols.Sample.DraftOrder.Cancel", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 57, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l3_raw_mutation.facts.json b/tests/fixtures/lowered/typestate_cs_l3_raw_mutation.facts.json new file mode 100644 index 00000000..f625405d --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l3_raw_mutation.facts.json @@ -0,0 +1,79 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L3RawMutation.Run", + "file": "frontend/roslyn/protocol-samples/cases/L3_raw_mutation.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 13 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 13, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 13 + }, + { + "op": "use", + "var": "order", + "line": 15 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 16 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 13 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l3_raw_mutation.golden.json b/tests/fixtures/lowered/typestate_cs_l3_raw_mutation.golden.json new file mode 100644 index 00000000..48e7ec4b --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l3_raw_mutation.golden.json @@ -0,0 +1,215 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L3RawMutation.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "use", + "handle": "loc_0", + "line": 15 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 16 + } + ], + "line": 13 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 13 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_3", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L3RawMutation.Run", + "file": "frontend/roslyn/protocol-samples/cases/L3_raw_mutation.cs", + "line": 13, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L3RawMutation.Run", + "file": "frontend/roslyn/protocol-samples/cases/L3_raw_mutation.cs", + "line": 13, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_3", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l4_raw_escape.facts.json b/tests/fixtures/lowered/typestate_cs_l4_raw_escape.facts.json new file mode 100644 index 00000000..0b31942f --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l4_raw_escape.facts.json @@ -0,0 +1,79 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L4RawEscape.Run", + "file": "frontend/roslyn/protocol-samples/cases/L4_raw_escape.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 13 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 13, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 13 + }, + { + "op": "use", + "var": "order", + "line": 15 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 16 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 13 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l4_raw_escape.golden.json b/tests/fixtures/lowered/typestate_cs_l4_raw_escape.golden.json new file mode 100644 index 00000000..3d26b354 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l4_raw_escape.golden.json @@ -0,0 +1,215 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L4RawEscape.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "use", + "handle": "loc_0", + "line": 15 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 16 + } + ], + "line": 13 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 13 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_3", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L4RawEscape.Run", + "file": "frontend/roslyn/protocol-samples/cases/L4_raw_escape.cs", + "line": 13, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L4RawEscape.Run", + "file": "frontend/roslyn/protocol-samples/cases/L4_raw_escape.cs", + "line": 13, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_3", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l5_normal_transition.facts.json b/tests/fixtures/lowered/typestate_cs_l5_normal_transition.facts.json new file mode 100644 index 00000000..532f9b78 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l5_normal_transition.facts.json @@ -0,0 +1,74 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L5NormalTransition.Run", + "file": "frontend/roslyn/protocol-samples/cases/L5_normal_transition.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 12 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 12, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 12 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 14 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 12 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l5_normal_transition.golden.json b/tests/fixtures/lowered/typestate_cs_l5_normal_transition.golden.json new file mode 100644 index 00000000..dc84db51 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l5_normal_transition.golden.json @@ -0,0 +1,210 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L5NormalTransition.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 14 + } + ], + "line": 12 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 12 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_3", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L5NormalTransition.Run", + "file": "frontend/roslyn/protocol-samples/cases/L5_normal_transition.cs", + "line": 12, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L5NormalTransition.Run", + "file": "frontend/roslyn/protocol-samples/cases/L5_normal_transition.cs", + "line": 12, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_3", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l6_two_transitions.facts.json b/tests/fixtures/lowered/typestate_cs_l6_two_transitions.facts.json new file mode 100644 index 00000000..a67ac375 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l6_two_transitions.facts.json @@ -0,0 +1,111 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L6TwoTransitions.Run", + "file": "frontend/roslyn/protocol-samples/cases/L6_two_transitions.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 12 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 12, + "body": [ + { + "op": "acquire", + "var": "draft", + "line": 12 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Submit", + "args": [ + "draft", + "order.region1" + ], + "line": 14 + }, + { + "op": "acquire", + "var": "submitted", + "line": 14 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.SubmittedOrder.Approve", + "args": [ + "submitted", + "order.region1" + ], + "line": 15 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 12 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 51 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 51 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 51 + } + ] + }, + { + "name": "Own.Protocols.Sample.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 69 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 69 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 69 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l6_two_transitions.golden.json b/tests/fixtures/lowered/typestate_cs_l6_two_transitions.golden.json new file mode 100644 index 00000000..68d77eea --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l6_two_transitions.golden.json @@ -0,0 +1,287 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L6TwoTransitions.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Submit", + "args": [ + "loc_2", + "brw_1" + ], + "line": 14 + }, + { + "stmt": "acquire", + "handle": "loc_3", + "resource": "Disposable", + "line": 14 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.SubmittedOrder.Approve", + "args": [ + "loc_3", + "brw_1" + ], + "line": 15 + } + ], + "line": 12 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 12 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 51, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 51, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 51 + } + ] + }, + { + "name": "Own.Protocols.Sample.SubmittedOrder.Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 69, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 69, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 69 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L6TwoTransitions.Run", + "file": "frontend/roslyn/protocol-samples/cases/L6_two_transitions.cs", + "line": 12, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L6TwoTransitions.Run", + "file": "frontend/roslyn/protocol-samples/cases/L6_two_transitions.cs", + "line": 12, + "event": "draft", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_3", + "component": "Own.Protocols.Cases.L6TwoTransitions.Run", + "file": "frontend/roslyn/protocol-samples/cases/L6_two_transitions.cs", + "line": 14, + "event": "submitted", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 51, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Own.Protocols.Sample.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 51, + "event": "entity", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "Own.Protocols.Sample.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 69, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "Own.Protocols.Sample.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 69, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l6b_chained_transitions.facts.json b/tests/fixtures/lowered/typestate_cs_l6b_chained_transitions.facts.json new file mode 100644 index 00000000..f4a08ce2 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l6b_chained_transitions.facts.json @@ -0,0 +1,111 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L6bChainedTransitions.Run", + "file": "frontend/roslyn/protocol-samples/cases/L6b_chained_transitions.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 12 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 12, + "body": [ + { + "op": "acquire", + "var": "draft", + "line": 12 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Submit", + "args": [ + "draft", + "order.region1" + ], + "line": 12 + }, + { + "op": "acquire", + "var": "$t2", + "line": 12 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.SubmittedOrder.Approve", + "args": [ + "$t2", + "order.region1" + ], + "line": 12 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 12 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 51 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 51 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 51 + } + ] + }, + { + "name": "Own.Protocols.Sample.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 69 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 69 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 69 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l6b_chained_transitions.golden.json b/tests/fixtures/lowered/typestate_cs_l6b_chained_transitions.golden.json new file mode 100644 index 00000000..bd3eb0b6 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l6b_chained_transitions.golden.json @@ -0,0 +1,287 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L6bChainedTransitions.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Submit", + "args": [ + "loc_2", + "brw_1" + ], + "line": 12 + }, + { + "stmt": "acquire", + "handle": "loc_3", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.SubmittedOrder.Approve", + "args": [ + "loc_3", + "brw_1" + ], + "line": 12 + } + ], + "line": 12 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 12 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 51, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 51, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 51 + } + ] + }, + { + "name": "Own.Protocols.Sample.SubmittedOrder.Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 69, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 69, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 69 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L6bChainedTransitions.Run", + "file": "frontend/roslyn/protocol-samples/cases/L6b_chained_transitions.cs", + "line": 12, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L6bChainedTransitions.Run", + "file": "frontend/roslyn/protocol-samples/cases/L6b_chained_transitions.cs", + "line": 12, + "event": "draft", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_3", + "component": "Own.Protocols.Cases.L6bChainedTransitions.Run", + "file": "frontend/roslyn/protocol-samples/cases/L6b_chained_transitions.cs", + "line": 12, + "event": "$t2", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 51, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Own.Protocols.Sample.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 51, + "event": "entity", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "Own.Protocols.Sample.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 69, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "Own.Protocols.Sample.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 69, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l7_read_after_region.facts.json b/tests/fixtures/lowered/typestate_cs_l7_read_after_region.facts.json new file mode 100644 index 00000000..29500f8c --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l7_read_after_region.facts.json @@ -0,0 +1,74 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L7ReadAfterRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L7_read_after_region.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 12 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 12, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 12 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 14 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 12 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l7_read_after_region.golden.json b/tests/fixtures/lowered/typestate_cs_l7_read_after_region.golden.json new file mode 100644 index 00000000..9c8e9e91 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l7_read_after_region.golden.json @@ -0,0 +1,210 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L7ReadAfterRegion.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 14 + } + ], + "line": 12 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 12 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_3", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L7ReadAfterRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L7_read_after_region.cs", + "line": 12, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L7ReadAfterRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L7_read_after_region.cs", + "line": 12, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_3", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l8_branch_inside_region.facts.json b/tests/fixtures/lowered/typestate_cs_l8_branch_inside_region.facts.json new file mode 100644 index 00000000..3aadeee4 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l8_branch_inside_region.facts.json @@ -0,0 +1,95 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L8BranchInsideRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L8_branch_inside_region.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 12 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 12, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 12 + }, + { + "op": "use", + "var": "approved", + "line": 14 + }, + { + "op": "if", + "line": 14, + "then": [ + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 16 + } + ], + "else": [] + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 18 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 12 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l8_branch_inside_region.golden.json b/tests/fixtures/lowered/typestate_cs_l8_branch_inside_region.golden.json new file mode 100644 index 00000000..733d75de --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l8_branch_inside_region.golden.json @@ -0,0 +1,232 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L8BranchInsideRegion.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "use", + "handle": "loc_2", + "line": 14 + }, + { + "stmt": "if", + "cond": "?", + "then": [ + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 16 + } + ], + "else": [], + "line": 14 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 18 + } + ], + "line": 12 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 12 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_3", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L8BranchInsideRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L8_branch_inside_region.cs", + "line": 12, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L8BranchInsideRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L8_branch_inside_region.cs", + "line": 12, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_3", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_l9_opaque_calls_around_region.facts.json b/tests/fixtures/lowered/typestate_cs_l9_opaque_calls_around_region.facts.json new file mode 100644 index 00000000..ffe52534 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l9_opaque_calls_around_region.facts.json @@ -0,0 +1,74 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L9OpaqueCallsAroundRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L9_opaque_calls_around_region.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 18 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 18, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 18 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 20 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 18 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_l9_opaque_calls_around_region.golden.json b/tests/fixtures/lowered/typestate_cs_l9_opaque_calls_around_region.golden.json new file mode 100644 index 00000000..fdb4ca07 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_l9_opaque_calls_around_region.golden.json @@ -0,0 +1,210 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.L9OpaqueCallsAroundRegion.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 18 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 18 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 20 + } + ], + "line": 18 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 18 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_3", + "line": 80 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.L9OpaqueCallsAroundRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L9_opaque_calls_around_region.cs", + "line": 18, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.L9OpaqueCallsAroundRegion.Run", + "file": "frontend/roslyn/protocol-samples/cases/L9_opaque_calls_around_region.cs", + "line": 18, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_3", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_4", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_cs_x1_nested_region_same_entity.facts.json b/tests/fixtures/lowered/typestate_cs_x1_nested_region_same_entity.facts.json new file mode 100644 index 00000000..678406a7 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_x1_nested_region_same_entity.facts.json @@ -0,0 +1,119 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "Own.Protocols.Cases.X1NestedRegionSameEntity.Run", + "file": "frontend/roslyn/protocol-samples/cases/X1_nested_region_same_entity.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 13 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 13, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 13 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region2", + "line": 15, + "body": [ + { + "op": "acquire", + "var": "draft", + "line": 15 + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Cancel", + "args": [ + "draft", + "order.region2" + ], + "line": 15 + } + ] + }, + { + "op": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 16 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 13 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 80 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 80 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 80 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Cancel", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 57 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 57 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 57 + } + ] + } + ], + "stats": { + "methods_with_local": 0, + "methods_flow_analysed": 0, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_cs_x1_nested_region_same_entity.golden.json b/tests/fixtures/lowered/typestate_cs_x1_nested_region_same_entity.golden.json new file mode 100644 index 00000000..115028c2 --- /dev/null +++ b/tests/fixtures/lowered/typestate_cs_x1_nested_region_same_entity.golden.json @@ -0,0 +1,295 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Own.Protocols.Cases.X1NestedRegionSameEntity.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_0", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_1", + "body": [ + { + "stmt": "acquire", + "handle": "loc_2", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "borrow_mut", + "owner": "loc_0", + "binding": "brw_3", + "body": [ + { + "stmt": "acquire", + "handle": "loc_4", + "resource": "Disposable", + "line": 15 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.DraftOrder.Cancel", + "args": [ + "loc_4", + "brw_3" + ], + "line": 15 + } + ], + "line": 15 + }, + { + "stmt": "call", + "callee": "Own.Protocols.Sample.ApprovedOrder.Ship", + "args": [ + "loc_2", + "brw_1" + ], + "line": 16 + } + ], + "line": 13 + }, + { + "stmt": "release", + "handle": "loc_0", + "line": 13 + } + ] + }, + { + "name": "Own.Protocols.Sample.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 80, + "lifetime": null + }, + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 80, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_5", + "line": 80 + } + ] + }, + { + "name": "Own.Protocols.Sample.DraftOrder.Cancel", + "lifetime": null, + "params": [ + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 57, + "lifetime": null + }, + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 57, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_7", + "line": 57 + } + ] + } + ], + "handles": [ + { + "handle": "loc_0", + "component": "Own.Protocols.Cases.X1NestedRegionSameEntity.Run", + "file": "frontend/roslyn/protocol-samples/cases/X1_nested_region_same_entity.cs", + "line": 13, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_2", + "component": "Own.Protocols.Cases.X1NestedRegionSameEntity.Run", + "file": "frontend/roslyn/protocol-samples/cases/X1_nested_region_same_entity.cs", + "line": 13, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_4", + "component": "Own.Protocols.Cases.X1NestedRegionSameEntity.Run", + "file": "frontend/roslyn/protocol-samples/cases/X1_nested_region_same_entity.cs", + "line": 15, + "event": "draft", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_5", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_6", + "component": "Own.Protocols.Sample.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 80, + "event": "entity", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_7", + "component": "Own.Protocols.Sample.DraftOrder.Cancel", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 57, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_8", + "component": "Own.Protocols.Sample.DraftOrder.Cancel", + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 57, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_ef_orderbackend.facts.json b/tests/fixtures/lowered/typestate_ef_orderbackend.facts.json new file mode 100644 index 00000000..4b0f69b4 --- /dev/null +++ b/tests/fixtures/lowered/typestate_ef_orderbackend.facts.json @@ -0,0 +1,312 @@ +{ + "ownir_version": 1, + "module": "Extracted", + "components": [], + "services": [], + "functions": [ + { + "name": "OrderBackend.OrderHandlers.Create", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "sig": "System.String,OrderBackend.Data.AppDbContext,System.Threading.CancellationToken", + "params": [ + { + "name": "db", + "line": 16 + } + ], + "body": [ + { + "op": "use", + "var": "db", + "line": 19 + }, + { + "op": "use", + "var": "db", + "line": 20 + }, + { + "op": "return", + "var": null, + "line": 21 + } + ] + }, + { + "name": "OrderBackend.OrderHandlers.Ship", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "sig": "System.Int32,OrderBackend.Data.AppDbContext,Microsoft.Extensions.Logging.ILogger`1,System.Threading.CancellationToken", + "params": [ + { + "name": "db", + "line": 26 + } + ], + "body": [ + { + "op": "if", + "line": 33, + "then": [ + { + "op": "return", + "var": null, + "line": 34 + } + ], + "else": [] + }, + { + "op": "if", + "line": 42, + "then": [ + { + "op": "return", + "var": null, + "line": 40 + } + ], + "else": [] + }, + { + "op": "use", + "var": "db", + "line": 52 + }, + { + "op": "return", + "var": null, + "line": 56 + } + ] + }, + { + "name": "OrderBackend.OrderHandlers.SubmitAndApprove", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "sig": "System.Int32,OrderBackend.Data.AppDbContext,System.Threading.CancellationToken", + "params": [ + { + "name": "db", + "line": 59 + } + ], + "body": [ + { + "op": "if", + "line": 62, + "then": [ + { + "op": "return", + "var": null, + "line": 63 + } + ], + "else": [] + }, + { + "op": "if", + "line": 69, + "then": [ + { + "op": "return", + "var": null, + "line": 66 + } + ], + "else": [] + }, + { + "op": "use", + "var": "db", + "line": 80 + }, + { + "op": "return", + "var": null, + "line": 81 + } + ] + }, + { + "name": "OrderBackend.OrderHandlers.Get", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "sig": "System.Int32,OrderBackend.Data.AppDbContext,System.Threading.CancellationToken", + "params": [ + { + "name": "db", + "line": 84 + } + ], + "body": [ + { + "op": "return", + "var": null, + "line": 87 + } + ] + }, + { + "name": "OrderBackend.OrderHandlers.Ship$protocol", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 42 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 42, + "body": [ + { + "op": "acquire", + "var": "approved", + "line": 42 + }, + { + "op": "call", + "callee": "OrderBackend.Domain.ApprovedOrder.Ship", + "args": [ + "approved", + "order.region1" + ], + "line": 44 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 42 + } + ] + }, + { + "name": "OrderBackend.OrderHandlers.SubmitAndApprove$protocol", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 69 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "order.region1", + "line": 69, + "body": [ + { + "op": "acquire", + "var": "draft", + "line": 69 + }, + { + "op": "call", + "callee": "OrderBackend.Domain.DraftOrder.Submit", + "args": [ + "draft", + "order.region1" + ], + "line": 71 + }, + { + "op": "acquire", + "var": "submitted", + "line": 71 + }, + { + "op": "call", + "callee": "OrderBackend.Domain.SubmittedOrder.Approve", + "args": [ + "submitted", + "order.region1" + ], + "line": 72 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 69 + } + ] + }, + { + "name": "OrderBackend.Domain.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 65 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 65 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 65 + } + ] + }, + { + "name": "OrderBackend.Domain.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 37 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 37 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 37 + } + ] + }, + { + "name": "OrderBackend.Domain.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "params": [ + { + "name": "token", + "effect": "consume", + "line": 53 + }, + { + "name": "entity", + "effect": "borrow_mut", + "line": 53 + } + ], + "body": [ + { + "op": "release", + "var": "token", + "line": 53 + } + ] + } + ], + "stats": { + "methods_with_local": 4, + "methods_flow_analysed": 4, + "methods_skipped_unmodelled": 0 + } +} diff --git a/tests/fixtures/lowered/typestate_ef_orderbackend.golden.json b/tests/fixtures/lowered/typestate_ef_orderbackend.golden.json new file mode 100644 index 00000000..7fbbc2e5 --- /dev/null +++ b/tests/fixtures/lowered/typestate_ef_orderbackend.golden.json @@ -0,0 +1,605 @@ +{ + "lowered_version": 2, + "module": "Extracted", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "OrderBackend.OrderHandlers.Create", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 16, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "use", + "handle": "parg_0", + "line": 19 + }, + { + "stmt": "use", + "handle": "parg_0", + "line": 20 + }, + { + "stmt": "return", + "handle": null, + "line": 21 + } + ] + }, + { + "name": "OrderBackend.OrderHandlers.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 26, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "if", + "cond": "?", + "then": [ + { + "stmt": "return", + "handle": null, + "line": 34 + } + ], + "else": [], + "line": 33 + }, + { + "stmt": "if", + "cond": "?", + "then": [ + { + "stmt": "return", + "handle": null, + "line": 40 + } + ], + "else": [], + "line": 42 + }, + { + "stmt": "use", + "handle": "parg_1", + "line": 52 + }, + { + "stmt": "return", + "handle": null, + "line": 56 + } + ] + }, + { + "name": "OrderBackend.OrderHandlers.SubmitAndApprove", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 59, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "if", + "cond": "?", + "then": [ + { + "stmt": "return", + "handle": null, + "line": 63 + } + ], + "else": [], + "line": 62 + }, + { + "stmt": "if", + "cond": "?", + "then": [ + { + "stmt": "return", + "handle": null, + "line": 66 + } + ], + "else": [], + "line": 69 + }, + { + "stmt": "use", + "handle": "parg_2", + "line": 80 + }, + { + "stmt": "return", + "handle": null, + "line": 81 + } + ] + }, + { + "name": "OrderBackend.OrderHandlers.Get", + "lifetime": null, + "params": [ + { + "handle": "parg_3", + "type": { + "name": "int", + "borrowed": false, + "mutable": false + }, + "line": 84, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "return", + "handle": null, + "line": 87 + } + ] + }, + { + "name": "OrderBackend.OrderHandlers.Ship$protocol", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_4", + "resource": "Disposable", + "line": 42 + }, + { + "stmt": "borrow_mut", + "owner": "loc_4", + "binding": "brw_5", + "body": [ + { + "stmt": "acquire", + "handle": "loc_6", + "resource": "Disposable", + "line": 42 + }, + { + "stmt": "call", + "callee": "OrderBackend.Domain.ApprovedOrder.Ship", + "args": [ + "loc_6", + "brw_5" + ], + "line": 44 + } + ], + "line": 42 + }, + { + "stmt": "release", + "handle": "loc_4", + "line": 42 + } + ] + }, + { + "name": "OrderBackend.OrderHandlers.SubmitAndApprove$protocol", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_7", + "resource": "Disposable", + "line": 69 + }, + { + "stmt": "borrow_mut", + "owner": "loc_7", + "binding": "brw_8", + "body": [ + { + "stmt": "acquire", + "handle": "loc_9", + "resource": "Disposable", + "line": 69 + }, + { + "stmt": "call", + "callee": "OrderBackend.Domain.DraftOrder.Submit", + "args": [ + "loc_9", + "brw_8" + ], + "line": 71 + }, + { + "stmt": "acquire", + "handle": "loc_10", + "resource": "Disposable", + "line": 71 + }, + { + "stmt": "call", + "callee": "OrderBackend.Domain.SubmittedOrder.Approve", + "args": [ + "loc_10", + "brw_8" + ], + "line": 72 + } + ], + "line": 69 + }, + { + "stmt": "release", + "handle": "loc_7", + "line": 69 + } + ] + }, + { + "name": "OrderBackend.Domain.ApprovedOrder.Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_11", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 65, + "lifetime": null + }, + { + "handle": "parg_12", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 65, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_11", + "line": 65 + } + ] + }, + { + "name": "OrderBackend.Domain.DraftOrder.Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_13", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 37, + "lifetime": null + }, + { + "handle": "parg_14", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 37, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_13", + "line": 37 + } + ] + }, + { + "name": "OrderBackend.Domain.SubmittedOrder.Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_15", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 53, + "lifetime": null + }, + { + "handle": "parg_16", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 53, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_15", + "line": 53 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "OrderBackend.OrderHandlers.Create", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 16, + "event": "db", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_1", + "component": "OrderBackend.OrderHandlers.Ship", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 26, + "event": "db", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "OrderBackend.OrderHandlers.SubmitAndApprove", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 59, + "event": "db", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_3", + "component": "OrderBackend.OrderHandlers.Get", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 84, + "event": "db", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "loc_4", + "component": "OrderBackend.OrderHandlers.Ship$protocol", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 42, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_6", + "component": "OrderBackend.OrderHandlers.Ship$protocol", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 42, + "event": "approved", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_7", + "component": "OrderBackend.OrderHandlers.SubmitAndApprove$protocol", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 69, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_9", + "component": "OrderBackend.OrderHandlers.SubmitAndApprove$protocol", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 69, + "event": "draft", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_10", + "component": "OrderBackend.OrderHandlers.SubmitAndApprove$protocol", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 71, + "event": "submitted", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "parg_11", + "component": "OrderBackend.Domain.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "line": 65, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_12", + "component": "OrderBackend.Domain.ApprovedOrder.Ship", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "line": 65, + "event": "entity", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_13", + "component": "OrderBackend.Domain.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "line": 37, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_14", + "component": "OrderBackend.Domain.DraftOrder.Submit", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "line": 37, + "event": "entity", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_15", + "component": "OrderBackend.Domain.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "line": 53, + "event": "token", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_16", + "component": "OrderBackend.Domain.SubmittedOrder.Approve", + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "line": 53, + "event": "entity", + "resource": "flow-local", + "ever_released": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_g6_capability_not_spent.facts.json b/tests/fixtures/lowered/typestate_g6_capability_not_spent.facts.json new file mode 100644 index 00000000..a8375c28 --- /dev/null +++ b/tests/fixtures/lowered/typestate_g6_capability_not_spent.facts.json @@ -0,0 +1,169 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 14 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_g6_capability_not_spent.golden.json b/tests/fixtures/lowered/typestate_g6_capability_not_spent.golden.json new file mode 100644 index 00000000..6683db30 --- /dev/null +++ b/tests/fixtures/lowered/typestate_g6_capability_not_spent.golden.json @@ -0,0 +1,444 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + } + ], + "line": 11 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 14 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "a", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l1_stale_capability.facts.json b/tests/fixtures/lowered/typestate_l1_stale_capability.facts.json new file mode 100644 index 00000000..4331c126 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l1_stale_capability.facts.json @@ -0,0 +1,187 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "d", + "line": 12 + }, + { + "op": "call", + "callee": "Submit", + "args": [ + "d", + "r" + ], + "line": 13 + }, + { + "op": "call", + "callee": "CancelDraft", + "args": [ + "d", + "r" + ], + "line": 14 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 16 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l1_stale_capability.golden.json b/tests/fixtures/lowered/typestate_l1_stale_capability.golden.json new file mode 100644 index 00000000..bf2e5a38 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l1_stale_capability.golden.json @@ -0,0 +1,462 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Submit", + "args": [ + "loc_13", + "brw_12" + ], + "line": 13 + }, + { + "stmt": "call", + "callee": "CancelDraft", + "args": [ + "loc_13", + "brw_12" + ], + "line": 14 + } + ], + "line": 11 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 16 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "d", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l2_copied_capability.facts.json b/tests/fixtures/lowered/typestate_l2_copied_capability.facts.json new file mode 100644 index 00000000..6e627b7c --- /dev/null +++ b/tests/fixtures/lowered/typestate_l2_copied_capability.facts.json @@ -0,0 +1,193 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "d1", + "line": 12 + }, + { + "op": "move", + "var": "d2", + "src": "d1", + "line": 13 + }, + { + "op": "call", + "callee": "Submit", + "args": [ + "d1", + "r" + ], + "line": 14 + }, + { + "op": "call", + "callee": "CancelDraft", + "args": [ + "d2", + "r" + ], + "line": 15 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 17 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l2_copied_capability.golden.json b/tests/fixtures/lowered/typestate_l2_copied_capability.golden.json new file mode 100644 index 00000000..61d24705 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l2_copied_capability.golden.json @@ -0,0 +1,478 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "move", + "handle": "loc_14", + "src": "loc_13", + "line": 13 + }, + { + "stmt": "call", + "callee": "Submit", + "args": [ + "loc_13", + "brw_12" + ], + "line": 14 + }, + { + "stmt": "call", + "callee": "CancelDraft", + "args": [ + "loc_14", + "brw_12" + ], + "line": 15 + } + ], + "line": 11 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 17 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "d1", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_14", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 13, + "event": "d2", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l3_raw_entity_mutation.facts.json b/tests/fixtures/lowered/typestate_l3_raw_entity_mutation.facts.json new file mode 100644 index 00000000..94ddaf0e --- /dev/null +++ b/tests/fixtures/lowered/typestate_l3_raw_entity_mutation.facts.json @@ -0,0 +1,186 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + }, + { + "op": "call", + "callee": "CancelOrder", + "args": [ + "order" + ], + "line": 13 + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "r" + ], + "line": 14 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 16 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l3_raw_entity_mutation.golden.json b/tests/fixtures/lowered/typestate_l3_raw_entity_mutation.golden.json new file mode 100644 index 00000000..2b8f68c6 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l3_raw_entity_mutation.golden.json @@ -0,0 +1,461 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "CancelOrder", + "args": [ + "loc_11" + ], + "line": 13 + }, + { + "stmt": "call", + "callee": "Ship", + "args": [ + "loc_13", + "brw_12" + ], + "line": 14 + } + ], + "line": 11 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 16 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "a", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l3b_second_region.facts.json b/tests/fixtures/lowered/typestate_l3b_second_region.facts.json new file mode 100644 index 00000000..07033b31 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l3b_second_region.facts.json @@ -0,0 +1,194 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r2", + "line": 13, + "body": [ + { + "op": "call", + "callee": "CancelOrder", + "args": [ + "r2" + ], + "line": 14 + } + ] + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "r" + ], + "line": 16 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 18 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l3b_second_region.golden.json b/tests/fixtures/lowered/typestate_l3b_second_region.golden.json new file mode 100644 index 00000000..0e99d507 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l3b_second_region.golden.json @@ -0,0 +1,469 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_14", + "body": [ + { + "stmt": "call", + "callee": "CancelOrder", + "args": [ + "brw_14" + ], + "line": 14 + } + ], + "line": 13 + }, + { + "stmt": "call", + "callee": "Ship", + "args": [ + "loc_13", + "brw_12" + ], + "line": 16 + } + ], + "line": 11 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 18 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "a", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l4_raw_entity_unknown_call.facts.json b/tests/fixtures/lowered/typestate_l4_raw_entity_unknown_call.facts.json new file mode 100644 index 00000000..e1f9d18e --- /dev/null +++ b/tests/fixtures/lowered/typestate_l4_raw_entity_unknown_call.facts.json @@ -0,0 +1,186 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + }, + { + "op": "call", + "callee": "Unknown", + "args": [ + "order" + ], + "line": 13 + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "r" + ], + "line": 14 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 16 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l4_raw_entity_unknown_call.golden.json b/tests/fixtures/lowered/typestate_l4_raw_entity_unknown_call.golden.json new file mode 100644 index 00000000..9418b477 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l4_raw_entity_unknown_call.golden.json @@ -0,0 +1,4 @@ +{ + "lowered_version": 2, + "error": "OwnIR call to 'Unknown' inside a borrow_mut region passes tracked local 'order', but the callee has no ownership contract (Orders.cs:13) — refused: an exclusive region must not hand its entity or tokens to unanalysed code" +} diff --git a/tests/fixtures/lowered/typestate_l4b_raw_entity_shared_call.facts.json b/tests/fixtures/lowered/typestate_l4b_raw_entity_shared_call.facts.json new file mode 100644 index 00000000..2f8aeefa --- /dev/null +++ b/tests/fixtures/lowered/typestate_l4b_raw_entity_shared_call.facts.json @@ -0,0 +1,186 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + }, + { + "op": "call", + "callee": "Peek", + "args": [ + "order" + ], + "line": 13 + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "r" + ], + "line": 14 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 16 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l4b_raw_entity_shared_call.golden.json b/tests/fixtures/lowered/typestate_l4b_raw_entity_shared_call.golden.json new file mode 100644 index 00000000..b802753c --- /dev/null +++ b/tests/fixtures/lowered/typestate_l4b_raw_entity_shared_call.golden.json @@ -0,0 +1,461 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Peek", + "args": [ + "loc_11" + ], + "line": 13 + }, + { + "stmt": "call", + "callee": "Ship", + "args": [ + "loc_13", + "brw_12" + ], + "line": 14 + } + ], + "line": 11 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 16 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "a", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l4c_raw_entity_consumed.facts.json b/tests/fixtures/lowered/typestate_l4c_raw_entity_consumed.facts.json new file mode 100644 index 00000000..3707b5d2 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l4c_raw_entity_consumed.facts.json @@ -0,0 +1,181 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + }, + { + "op": "call", + "callee": "Store", + "args": [ + "order" + ], + "line": 13 + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "r" + ], + "line": 14 + } + ] + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l4c_raw_entity_consumed.golden.json b/tests/fixtures/lowered/typestate_l4c_raw_entity_consumed.golden.json new file mode 100644 index 00000000..116378e4 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l4c_raw_entity_consumed.golden.json @@ -0,0 +1,456 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Store", + "args": [ + "loc_11" + ], + "line": 13 + }, + { + "stmt": "call", + "callee": "Ship", + "args": [ + "loc_13", + "brw_12" + ], + "line": 14 + } + ], + "line": 11 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "a", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l4d_token_unknown_call.facts.json b/tests/fixtures/lowered/typestate_l4d_token_unknown_call.facts.json new file mode 100644 index 00000000..cd2b9b63 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l4d_token_unknown_call.facts.json @@ -0,0 +1,186 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + }, + { + "op": "call", + "callee": "Unknown", + "args": [ + "a" + ], + "line": 13 + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "r" + ], + "line": 14 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 16 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l4d_token_unknown_call.golden.json b/tests/fixtures/lowered/typestate_l4d_token_unknown_call.golden.json new file mode 100644 index 00000000..07241a9e --- /dev/null +++ b/tests/fixtures/lowered/typestate_l4d_token_unknown_call.golden.json @@ -0,0 +1,4 @@ +{ + "lowered_version": 2, + "error": "OwnIR call to 'Unknown' inside a borrow_mut region passes tracked local 'a', but the callee has no ownership contract (Orders.cs:13) — refused: an exclusive region must not hand its entity or tokens to unanalysed code" +} diff --git a/tests/fixtures/lowered/typestate_l5_normal_transition.facts.json b/tests/fixtures/lowered/typestate_l5_normal_transition.facts.json new file mode 100644 index 00000000..d3b4e286 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l5_normal_transition.facts.json @@ -0,0 +1,178 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "r" + ], + "line": 13 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 15 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l5_normal_transition.golden.json b/tests/fixtures/lowered/typestate_l5_normal_transition.golden.json new file mode 100644 index 00000000..28e657bc --- /dev/null +++ b/tests/fixtures/lowered/typestate_l5_normal_transition.golden.json @@ -0,0 +1,453 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Ship", + "args": [ + "loc_13", + "brw_12" + ], + "line": 13 + } + ], + "line": 11 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 15 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "a", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l5b_two_transitions.facts.json b/tests/fixtures/lowered/typestate_l5b_two_transitions.facts.json new file mode 100644 index 00000000..295e58c9 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l5b_two_transitions.facts.json @@ -0,0 +1,192 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "d", + "line": 12 + }, + { + "op": "call", + "callee": "Submit", + "args": [ + "d", + "r" + ], + "line": 13 + }, + { + "op": "acquire", + "var": "s", + "line": 13 + }, + { + "op": "call", + "callee": "Approve", + "args": [ + "s", + "r" + ], + "line": 14 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 16 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l5b_two_transitions.golden.json b/tests/fixtures/lowered/typestate_l5b_two_transitions.golden.json new file mode 100644 index 00000000..b1a36644 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l5b_two_transitions.golden.json @@ -0,0 +1,478 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Submit", + "args": [ + "loc_13", + "brw_12" + ], + "line": 13 + }, + { + "stmt": "acquire", + "handle": "loc_14", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "call", + "callee": "Approve", + "args": [ + "loc_14", + "brw_12" + ], + "line": 14 + } + ], + "line": 11 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 16 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "d", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_14", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 13, + "event": "s", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l5c_read_after_region.facts.json b/tests/fixtures/lowered/typestate_l5c_read_after_region.facts.json new file mode 100644 index 00000000..d43777d7 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l5c_read_after_region.facts.json @@ -0,0 +1,186 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "r" + ], + "line": 13 + } + ] + }, + { + "op": "call", + "callee": "Peek", + "args": [ + "order" + ], + "line": 15 + }, + { + "op": "release", + "var": "order", + "line": 16 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_l5c_read_after_region.golden.json b/tests/fixtures/lowered/typestate_l5c_read_after_region.golden.json new file mode 100644 index 00000000..3aeb08c3 --- /dev/null +++ b/tests/fixtures/lowered/typestate_l5c_read_after_region.golden.json @@ -0,0 +1,461 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "call", + "callee": "Ship", + "args": [ + "loc_13", + "brw_12" + ], + "line": 13 + } + ], + "line": 11 + }, + { + "stmt": "call", + "callee": "Peek", + "args": [ + "loc_11" + ], + "line": 15 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 16 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "a", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_n1_token_spent_on_other_entity.facts.json b/tests/fixtures/lowered/typestate_n1_token_spent_on_other_entity.facts.json new file mode 100644 index 00000000..d1dc9fc4 --- /dev/null +++ b/tests/fixtures/lowered/typestate_n1_token_spent_on_other_entity.facts.json @@ -0,0 +1,196 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "o1", + "line": 10 + }, + { + "op": "acquire", + "var": "o2", + "line": 11 + }, + { + "op": "borrow_mut", + "owner": "o1", + "binding": "r1", + "line": 12, + "body": [ + { + "op": "borrow_mut", + "owner": "o2", + "binding": "r2", + "line": 13, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 14 + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "r2" + ], + "line": 15 + } + ] + } + ] + }, + { + "op": "release", + "var": "o1", + "line": 18 + }, + { + "op": "release", + "var": "o2", + "line": 19 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_n1_token_spent_on_other_entity.golden.json b/tests/fixtures/lowered/typestate_n1_token_spent_on_other_entity.golden.json new file mode 100644 index 00000000..3b376e17 --- /dev/null +++ b/tests/fixtures/lowered/typestate_n1_token_spent_on_other_entity.golden.json @@ -0,0 +1,482 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "acquire", + "handle": "loc_12", + "resource": "Disposable", + "line": 11 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_13", + "body": [ + { + "stmt": "borrow_mut", + "owner": "loc_12", + "binding": "brw_14", + "body": [ + { + "stmt": "acquire", + "handle": "loc_15", + "resource": "Disposable", + "line": 14 + }, + { + "stmt": "call", + "callee": "Ship", + "args": [ + "loc_15", + "brw_14" + ], + "line": 15 + } + ], + "line": 13 + } + ], + "line": 12 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 18 + }, + { + "stmt": "release", + "handle": "loc_12", + "line": 19 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "o1", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_12", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 11, + "event": "o2", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_15", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 14, + "event": "a", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_n2_two_tokens_one_region.facts.json b/tests/fixtures/lowered/typestate_n2_two_tokens_one_region.facts.json new file mode 100644 index 00000000..afa9543a --- /dev/null +++ b/tests/fixtures/lowered/typestate_n2_two_tokens_one_region.facts.json @@ -0,0 +1,192 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "d", + "line": 12 + }, + { + "op": "acquire", + "var": "again", + "line": 13 + }, + { + "op": "call", + "callee": "Submit", + "args": [ + "d", + "r" + ], + "line": 14 + }, + { + "op": "call", + "callee": "CancelDraft", + "args": [ + "again", + "r" + ], + "line": 15 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 17 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_n2_two_tokens_one_region.golden.json b/tests/fixtures/lowered/typestate_n2_two_tokens_one_region.golden.json new file mode 100644 index 00000000..37dc9591 --- /dev/null +++ b/tests/fixtures/lowered/typestate_n2_two_tokens_one_region.golden.json @@ -0,0 +1,478 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + }, + { + "stmt": "acquire", + "handle": "loc_14", + "resource": "Disposable", + "line": 13 + }, + { + "stmt": "call", + "callee": "Submit", + "args": [ + "loc_13", + "brw_12" + ], + "line": 14 + }, + { + "stmt": "call", + "callee": "CancelDraft", + "args": [ + "loc_14", + "brw_12" + ], + "line": 15 + } + ], + "line": 11 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 17 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "d", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_14", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 13, + "event": "again", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_n3_raw_mutation_inferred_effect.facts.json b/tests/fixtures/lowered/typestate_n3_raw_mutation_inferred_effect.facts.json new file mode 100644 index 00000000..f0f679db --- /dev/null +++ b/tests/fixtures/lowered/typestate_n3_raw_mutation_inferred_effect.facts.json @@ -0,0 +1,197 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Touch", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "line": 170 + } + ], + "body": [] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + }, + { + "op": "call", + "callee": "Touch", + "args": [ + "order" + ], + "line": 13 + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "r" + ], + "line": 14 + } + ] + }, + { + "op": "release", + "var": "order", + "line": 16 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_n3_raw_mutation_inferred_effect.golden.json b/tests/fixtures/lowered/typestate_n3_raw_mutation_inferred_effect.golden.json new file mode 100644 index 00000000..e86f2619 --- /dev/null +++ b/tests/fixtures/lowered/typestate_n3_raw_mutation_inferred_effect.golden.json @@ -0,0 +1,4 @@ +{ + "lowered_version": 2, + "error": "OwnIR call to 'Touch' inside a borrow_mut region passes tracked local 'order' at position 0, which carries no ownership effect (Orders.cs:13) — refused: inside an exclusive region every position that receives the entity or a token must state what it does with it" +} diff --git a/tests/fixtures/lowered/typestate_n4_token_outlives_region.facts.json b/tests/fixtures/lowered/typestate_n4_token_outlives_region.facts.json new file mode 100644 index 00000000..dca24eb8 --- /dev/null +++ b/tests/fixtures/lowered/typestate_n4_token_outlives_region.facts.json @@ -0,0 +1,186 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Submit", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 100 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 101 + } + ] + }, + { + "name": "Approve", + "file": "Orders.cs", + "params": [ + { + "name": "s", + "effect": "consume", + "line": 110 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 110 + } + ], + "body": [ + { + "op": "release", + "var": "s", + "line": 111 + } + ] + }, + { + "name": "Ship", + "file": "Orders.cs", + "params": [ + { + "name": "a", + "effect": "consume", + "line": 120 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "a", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "file": "Orders.cs", + "params": [ + { + "name": "d", + "effect": "consume", + "line": 130 + }, + { + "name": "order", + "effect": "borrow_mut", + "line": 130 + } + ], + "body": [ + { + "op": "release", + "var": "d", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow_mut", + "line": 140 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "borrow", + "line": 150 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Orders.cs", + "params": [ + { + "name": "order", + "effect": "consume", + "line": 160 + } + ], + "body": [ + { + "op": "release", + "var": "order", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "file": "Orders.cs", + "body": [ + { + "op": "acquire", + "var": "order", + "line": 10 + }, + { + "op": "borrow_mut", + "owner": "order", + "binding": "r", + "line": 11, + "body": [ + { + "op": "acquire", + "var": "a", + "line": 12 + } + ] + }, + { + "op": "call", + "callee": "CancelOrder", + "args": [ + "order" + ], + "line": 14 + }, + { + "op": "call", + "callee": "Ship", + "args": [ + "a", + "order" + ], + "line": 15 + }, + { + "op": "release", + "var": "order", + "line": 16 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_n4_token_outlives_region.golden.json b/tests/fixtures/lowered/typestate_n4_token_outlives_region.golden.json new file mode 100644 index 00000000..25c7dd42 --- /dev/null +++ b/tests/fixtures/lowered/typestate_n4_token_outlives_region.golden.json @@ -0,0 +1,461 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Submit", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 100, + "lifetime": null + }, + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_0", + "line": 101 + } + ] + }, + { + "name": "Approve", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 110, + "lifetime": null + }, + { + "handle": "parg_3", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 111 + } + ] + }, + { + "name": "Ship", + "lifetime": null, + "params": [ + { + "handle": "parg_4", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + }, + { + "handle": "parg_5", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_4", + "line": 121 + } + ] + }, + { + "name": "CancelDraft", + "lifetime": null, + "params": [ + { + "handle": "parg_6", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 130, + "lifetime": null + }, + { + "handle": "parg_7", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 130, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_6", + "line": 131 + } + ] + }, + { + "name": "CancelOrder", + "lifetime": null, + "params": [ + { + "handle": "parg_8", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 140, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_9", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 150, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_10", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 160, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_10", + "line": 161 + } + ] + }, + { + "name": "Handler.Run", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 10 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 12 + } + ], + "line": 11 + }, + { + "stmt": "call", + "callee": "CancelOrder", + "args": [ + "loc_11" + ], + "line": 14 + }, + { + "stmt": "call", + "callee": "Ship", + "args": [ + "loc_13", + "loc_11" + ], + "line": 15 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 16 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_1", + "component": "Submit", + "file": "Orders.cs", + "line": 100, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "s", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_3", + "component": "Approve", + "file": "Orders.cs", + "line": 110, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_4", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "a", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_5", + "component": "Ship", + "file": "Orders.cs", + "line": 120, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_6", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "d", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "parg_7", + "component": "CancelDraft", + "file": "Orders.cs", + "line": 130, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_8", + "component": "CancelOrder", + "file": "Orders.cs", + "line": 140, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_9", + "component": "Peek", + "file": "Orders.cs", + "line": 150, + "event": "order", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_10", + "component": "Store", + "file": "Orders.cs", + "line": 160, + "event": "order", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_11", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 10, + "event": "order", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "Handler.Run", + "file": "Orders.cs", + "line": 12, + "event": "a", + "resource": "flow-local", + "ever_released": false, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_w1_loan_wordings.facts.json b/tests/fixtures/lowered/typestate_w1_loan_wordings.facts.json new file mode 100644 index 00000000..41bfc219 --- /dev/null +++ b/tests/fixtures/lowered/typestate_w1_loan_wordings.facts.json @@ -0,0 +1,219 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Reborrow", + "file": "Wordings.cs", + "params": [ + { + "name": "o", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Wordings.cs", + "params": [ + { + "name": "o", + "effect": "borrow", + "line": 110 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Wordings.cs", + "params": [ + { + "name": "o", + "effect": "consume", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "o", + "line": 121 + } + ] + }, + { + "name": "W.Moved", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "b", + "line": 1 + }, + { + "op": "move", + "var": "c", + "src": "b", + "line": 2 + }, + { + "op": "use", + "var": "b", + "line": 3 + }, + { + "op": "release", + "var": "c", + "line": 4 + } + ] + }, + { + "name": "W.Consumed", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "o", + "line": 11 + }, + { + "op": "borrow_mut", + "owner": "o", + "binding": "r", + "line": 12, + "body": [ + { + "op": "call", + "callee": "Store", + "args": [ + "o" + ], + "line": 13 + } + ] + } + ] + }, + { + "name": "W.Released", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "o", + "line": 21 + }, + { + "op": "borrow_mut", + "owner": "o", + "binding": "r", + "line": 22, + "body": [ + { + "op": "release", + "var": "o", + "line": 23 + } + ] + } + ] + }, + { + "name": "W.Reborrowed", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "o", + "line": 31 + }, + { + "op": "borrow_mut", + "owner": "o", + "binding": "r", + "line": 32, + "body": [ + { + "op": "call", + "callee": "Reborrow", + "args": [ + "o" + ], + "line": 33 + } + ] + }, + { + "op": "release", + "var": "o", + "line": 35 + } + ] + }, + { + "name": "W.Shared", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "o", + "line": 41 + }, + { + "op": "borrow_mut", + "owner": "o", + "binding": "r", + "line": 42, + "body": [ + { + "op": "call", + "callee": "Peek", + "args": [ + "o" + ], + "line": 43 + } + ] + }, + { + "op": "release", + "var": "o", + "line": 45 + } + ] + }, + { + "name": "W.Used", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "o", + "line": 51 + }, + { + "op": "borrow_mut", + "owner": "o", + "binding": "r", + "line": 52, + "body": [ + { + "op": "use", + "var": "o", + "line": 53 + } + ] + }, + { + "op": "release", + "var": "o", + "line": 55 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_w1_loan_wordings.golden.json b/tests/fixtures/lowered/typestate_w1_loan_wordings.golden.json new file mode 100644 index 00000000..12ab0372 --- /dev/null +++ b/tests/fixtures/lowered/typestate_w1_loan_wordings.golden.json @@ -0,0 +1,442 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Reborrow", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 121 + } + ] + }, + { + "name": "W.Moved", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_3", + "resource": "Disposable", + "line": 1 + }, + { + "stmt": "move", + "handle": "loc_4", + "src": "loc_3", + "line": 2 + }, + { + "stmt": "use", + "handle": "loc_3", + "line": 3 + }, + { + "stmt": "release", + "handle": "loc_4", + "line": 4 + } + ] + }, + { + "name": "W.Consumed", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_5", + "resource": "Disposable", + "line": 11 + }, + { + "stmt": "borrow_mut", + "owner": "loc_5", + "binding": "brw_6", + "body": [ + { + "stmt": "call", + "callee": "Store", + "args": [ + "loc_5" + ], + "line": 13 + } + ], + "line": 12 + } + ] + }, + { + "name": "W.Released", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_7", + "resource": "Disposable", + "line": 21 + }, + { + "stmt": "borrow_mut", + "owner": "loc_7", + "binding": "brw_8", + "body": [ + { + "stmt": "release", + "handle": "loc_7", + "line": 23 + } + ], + "line": 22 + } + ] + }, + { + "name": "W.Reborrowed", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_9", + "resource": "Disposable", + "line": 31 + }, + { + "stmt": "borrow_mut", + "owner": "loc_9", + "binding": "brw_10", + "body": [ + { + "stmt": "call", + "callee": "Reborrow", + "args": [ + "loc_9" + ], + "line": 33 + } + ], + "line": 32 + }, + { + "stmt": "release", + "handle": "loc_9", + "line": 35 + } + ] + }, + { + "name": "W.Shared", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 41 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "call", + "callee": "Peek", + "args": [ + "loc_11" + ], + "line": 43 + } + ], + "line": 42 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 45 + } + ] + }, + { + "name": "W.Used", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 51 + }, + { + "stmt": "borrow_mut", + "owner": "loc_13", + "binding": "brw_14", + "body": [ + { + "stmt": "use", + "handle": "loc_13", + "line": 53 + } + ], + "line": 52 + }, + { + "stmt": "release", + "handle": "loc_13", + "line": 55 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Reborrow", + "file": "Wordings.cs", + "line": 100, + "event": "o", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_1", + "component": "Peek", + "file": "Wordings.cs", + "line": 110, + "event": "o", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Store", + "file": "Wordings.cs", + "line": 120, + "event": "o", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_3", + "component": "W.Moved", + "file": "Wordings.cs", + "line": 1, + "event": "b", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_4", + "component": "W.Moved", + "file": "Wordings.cs", + "line": 2, + "event": "c", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_5", + "component": "W.Consumed", + "file": "Wordings.cs", + "line": 11, + "event": "o", + "resource": "flow-local", + "ever_released": false, + "pool": false + }, + { + "handle": "loc_7", + "component": "W.Released", + "file": "Wordings.cs", + "line": 21, + "event": "o", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_9", + "component": "W.Reborrowed", + "file": "Wordings.cs", + "line": 31, + "event": "o", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_11", + "component": "W.Shared", + "file": "Wordings.cs", + "line": 41, + "event": "o", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_13", + "component": "W.Used", + "file": "Wordings.cs", + "line": 51, + "event": "o", + "resource": "flow-local", + "ever_released": true, + "pool": false + } + ] +} diff --git a/tests/fixtures/lowered/typestate_w2_loan_wordings_pooled.facts.json b/tests/fixtures/lowered/typestate_w2_loan_wordings_pooled.facts.json new file mode 100644 index 00000000..113a898f --- /dev/null +++ b/tests/fixtures/lowered/typestate_w2_loan_wordings_pooled.facts.json @@ -0,0 +1,225 @@ +{ + "ownir_version": 1, + "module": "TypestateGate", + "functions": [ + { + "name": "Reborrow", + "file": "Wordings.cs", + "params": [ + { + "name": "o", + "effect": "borrow_mut", + "line": 100 + } + ], + "body": [] + }, + { + "name": "Peek", + "file": "Wordings.cs", + "params": [ + { + "name": "o", + "effect": "borrow", + "line": 110 + } + ], + "body": [] + }, + { + "name": "Store", + "file": "Wordings.cs", + "params": [ + { + "name": "o", + "effect": "consume", + "line": 120 + } + ], + "body": [ + { + "op": "release", + "var": "o", + "line": 121 + } + ] + }, + { + "name": "W.Moved", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "b", + "line": 1, + "kind": "pool" + }, + { + "op": "move", + "var": "c", + "src": "b", + "line": 2 + }, + { + "op": "use", + "var": "b", + "line": 3 + }, + { + "op": "release", + "var": "c", + "line": 4 + } + ] + }, + { + "name": "W.Consumed", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "o", + "line": 11, + "kind": "pool" + }, + { + "op": "borrow_mut", + "owner": "o", + "binding": "r", + "line": 12, + "body": [ + { + "op": "call", + "callee": "Store", + "args": [ + "o" + ], + "line": 13 + } + ] + } + ] + }, + { + "name": "W.Released", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "o", + "line": 21, + "kind": "pool" + }, + { + "op": "borrow_mut", + "owner": "o", + "binding": "r", + "line": 22, + "body": [ + { + "op": "release", + "var": "o", + "line": 23 + } + ] + } + ] + }, + { + "name": "W.Reborrowed", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "o", + "line": 31, + "kind": "pool" + }, + { + "op": "borrow_mut", + "owner": "o", + "binding": "r", + "line": 32, + "body": [ + { + "op": "call", + "callee": "Reborrow", + "args": [ + "o" + ], + "line": 33 + } + ] + }, + { + "op": "release", + "var": "o", + "line": 35 + } + ] + }, + { + "name": "W.Shared", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "o", + "line": 41, + "kind": "pool" + }, + { + "op": "borrow_mut", + "owner": "o", + "binding": "r", + "line": 42, + "body": [ + { + "op": "call", + "callee": "Peek", + "args": [ + "o" + ], + "line": 43 + } + ] + }, + { + "op": "release", + "var": "o", + "line": 45 + } + ] + }, + { + "name": "W.Used", + "file": "Wordings.cs", + "body": [ + { + "op": "acquire", + "var": "o", + "line": 51, + "kind": "pool" + }, + { + "op": "borrow_mut", + "owner": "o", + "binding": "r", + "line": 52, + "body": [ + { + "op": "use", + "var": "o", + "line": 53 + } + ] + }, + { + "op": "release", + "var": "o", + "line": 55 + } + ] + } + ] +} diff --git a/tests/fixtures/lowered/typestate_w2_loan_wordings_pooled.golden.json b/tests/fixtures/lowered/typestate_w2_loan_wordings_pooled.golden.json new file mode 100644 index 00000000..52138627 --- /dev/null +++ b/tests/fixtures/lowered/typestate_w2_loan_wordings_pooled.golden.json @@ -0,0 +1,442 @@ +{ + "lowered_version": 2, + "module": "TypestateGate", + "resources": [ + { + "name": "Subscription", + "kind": "subscription token", + "members": [ + { + "role": "acquire", + "name": "Subscribe" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "Timer", + "kind": "timer", + "members": [ + { + "role": "acquire", + "name": "Start" + }, + { + "role": "release", + "name": "Stop" + } + ] + }, + { + "name": "Disposable", + "kind": "disposable field", + "members": [ + { + "role": "acquire", + "name": "New" + }, + { + "role": "release", + "name": "Dispose" + } + ] + }, + { + "name": "PooledBuffer", + "kind": "pooled buffer", + "members": [ + { + "role": "acquire", + "name": "Rent" + }, + { + "role": "release", + "name": "Return" + } + ] + } + ], + "externs": [ + { + "name": "$consume", + "params": [ + { + "effect": "consume", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow", + "params": [ + { + "effect": "borrow", + "type": "Disposable" + } + ] + }, + { + "name": "$borrow_mut", + "params": [ + { + "effect": "borrow_mut", + "type": "Disposable" + } + ] + } + ], + "lifetimes": [], + "functions": [ + { + "name": "Reborrow", + "lifetime": null, + "params": [ + { + "handle": "parg_0", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": true + }, + "line": 100, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Peek", + "lifetime": null, + "params": [ + { + "handle": "parg_1", + "type": { + "name": "Disposable", + "borrowed": true, + "mutable": false + }, + "line": 110, + "lifetime": null + } + ], + "ret": null, + "body": [] + }, + { + "name": "Store", + "lifetime": null, + "params": [ + { + "handle": "parg_2", + "type": { + "name": "Disposable", + "borrowed": false, + "mutable": false + }, + "line": 120, + "lifetime": null + } + ], + "ret": null, + "body": [ + { + "stmt": "release", + "handle": "parg_2", + "line": 121 + } + ] + }, + { + "name": "W.Moved", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_3", + "resource": "Disposable", + "line": 1 + }, + { + "stmt": "move", + "handle": "loc_4", + "src": "loc_3", + "line": 2 + }, + { + "stmt": "use", + "handle": "loc_3", + "line": 3 + }, + { + "stmt": "release", + "handle": "loc_4", + "line": 4 + } + ] + }, + { + "name": "W.Consumed", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_5", + "resource": "Disposable", + "line": 11 + }, + { + "stmt": "borrow_mut", + "owner": "loc_5", + "binding": "brw_6", + "body": [ + { + "stmt": "call", + "callee": "Store", + "args": [ + "loc_5" + ], + "line": 13 + } + ], + "line": 12 + } + ] + }, + { + "name": "W.Released", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_7", + "resource": "Disposable", + "line": 21 + }, + { + "stmt": "borrow_mut", + "owner": "loc_7", + "binding": "brw_8", + "body": [ + { + "stmt": "release", + "handle": "loc_7", + "line": 23 + } + ], + "line": 22 + } + ] + }, + { + "name": "W.Reborrowed", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_9", + "resource": "Disposable", + "line": 31 + }, + { + "stmt": "borrow_mut", + "owner": "loc_9", + "binding": "brw_10", + "body": [ + { + "stmt": "call", + "callee": "Reborrow", + "args": [ + "loc_9" + ], + "line": 33 + } + ], + "line": 32 + }, + { + "stmt": "release", + "handle": "loc_9", + "line": 35 + } + ] + }, + { + "name": "W.Shared", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_11", + "resource": "Disposable", + "line": 41 + }, + { + "stmt": "borrow_mut", + "owner": "loc_11", + "binding": "brw_12", + "body": [ + { + "stmt": "call", + "callee": "Peek", + "args": [ + "loc_11" + ], + "line": 43 + } + ], + "line": 42 + }, + { + "stmt": "release", + "handle": "loc_11", + "line": 45 + } + ] + }, + { + "name": "W.Used", + "lifetime": null, + "params": [], + "ret": null, + "body": [ + { + "stmt": "acquire", + "handle": "loc_13", + "resource": "Disposable", + "line": 51 + }, + { + "stmt": "borrow_mut", + "owner": "loc_13", + "binding": "brw_14", + "body": [ + { + "stmt": "use", + "handle": "loc_13", + "line": 53 + } + ], + "line": 52 + }, + { + "stmt": "release", + "handle": "loc_13", + "line": 55 + } + ] + } + ], + "handles": [ + { + "handle": "parg_0", + "component": "Reborrow", + "file": "Wordings.cs", + "line": 100, + "event": "o", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_1", + "component": "Peek", + "file": "Wordings.cs", + "line": 110, + "event": "o", + "resource": "flow-local", + "ever_released": false + }, + { + "handle": "parg_2", + "component": "Store", + "file": "Wordings.cs", + "line": 120, + "event": "o", + "resource": "flow-local", + "ever_released": true + }, + { + "handle": "loc_3", + "component": "W.Moved", + "file": "Wordings.cs", + "line": 1, + "event": "b", + "resource": "flow-local", + "ever_released": false, + "pool": true + }, + { + "handle": "loc_4", + "component": "W.Moved", + "file": "Wordings.cs", + "line": 2, + "event": "c", + "resource": "flow-local", + "ever_released": true, + "pool": false + }, + { + "handle": "loc_5", + "component": "W.Consumed", + "file": "Wordings.cs", + "line": 11, + "event": "o", + "resource": "flow-local", + "ever_released": false, + "pool": true + }, + { + "handle": "loc_7", + "component": "W.Released", + "file": "Wordings.cs", + "line": 21, + "event": "o", + "resource": "flow-local", + "ever_released": true, + "pool": true + }, + { + "handle": "loc_9", + "component": "W.Reborrowed", + "file": "Wordings.cs", + "line": 31, + "event": "o", + "resource": "flow-local", + "ever_released": true, + "pool": true + }, + { + "handle": "loc_11", + "component": "W.Shared", + "file": "Wordings.cs", + "line": 41, + "event": "o", + "resource": "flow-local", + "ever_released": true, + "pool": true + }, + { + "handle": "loc_13", + "component": "W.Used", + "file": "Wordings.cs", + "line": 51, + "event": "o", + "resource": "flow-local", + "ever_released": true, + "pool": true + } + ] +} diff --git a/tests/fixtures/lowered/vocab_unknown_op.facts.json b/tests/fixtures/lowered/vocab_unknown_op.facts.json index 46091dc2..f091a7fc 100644 --- a/tests/fixtures/lowered/vocab_unknown_op.facts.json +++ b/tests/fixtures/lowered/vocab_unknown_op.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Vocab", "functions": [ { diff --git a/tests/fixtures/lowered/vocab_unknown_op.golden.json b/tests/fixtures/lowered/vocab_unknown_op.golden.json index 10d4fa1d..9405464d 100644 --- a/tests/fixtures/lowered/vocab_unknown_op.golden.json +++ b/tests/fixtures/lowered/vocab_unknown_op.golden.json @@ -1,4 +1,4 @@ { - "lowered_version": 1, + "lowered_version": 2, "error": "unknown OwnIR flow op 'try' (F.cs:2) — extractor/core vocabulary skew; a new op must bump OWNIR_VERSION (see spec/OwnIR.md)" } diff --git a/tests/fixtures/ownir/capture.facts.json b/tests/fixtures/ownir/capture.facts.json index aba82fba..5ff5b528 100644 --- a/tests/fixtures/ownir/capture.facts.json +++ b/tests/fixtures/ownir/capture.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "WpfApp", "components": [ { diff --git a/tests/fixtures/ownir/contract_inference.facts.json b/tests/fixtures/ownir/contract_inference.facts.json index a2ebcac0..b7704a95 100644 --- a/tests/fixtures/ownir/contract_inference.facts.json +++ b/tests/fixtures/ownir/contract_inference.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "InferBridge", "functions": [ { diff --git a/tests/fixtures/ownir/di.facts.json b/tests/fixtures/ownir/di.facts.json index 3b91a586..53a90c0e 100644 --- a/tests/fixtures/ownir/di.facts.json +++ b/tests/fixtures/ownir/di.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DiDemo", "components": [], "services": [ diff --git a/tests/fixtures/ownir/di_capture.facts.json b/tests/fixtures/ownir/di_capture.facts.json index 65698ac3..c5f0f536 100644 --- a/tests/fixtures/ownir/di_capture.facts.json +++ b/tests/fixtures/ownir/di_capture.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DiZombie", "components": [ { diff --git a/tests/fixtures/ownir/disposable.facts.json b/tests/fixtures/ownir/disposable.facts.json index e8cbbd1f..b5e87e10 100644 --- a/tests/fixtures/ownir/disposable.facts.json +++ b/tests/fixtures/ownir/disposable.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "WpfDisposables", "components": [ { diff --git a/tests/fixtures/ownir/flow_column_anchors.facts.json b/tests/fixtures/ownir/flow_column_anchors.facts.json index b6b3e821..b0990a35 100644 --- a/tests/fixtures/ownir/flow_column_anchors.facts.json +++ b/tests/fixtures/ownir/flow_column_anchors.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "ColumnAnchors", "_doc": [ "Own.NET#317: the optional 1-based `column` on the finding-anchor path.", diff --git a/tests/fixtures/ownir/flow_finally_switch.facts.json b/tests/fixtures/ownir/flow_finally_switch.facts.json index fb38f435..bf285a54 100644 --- a/tests/fixtures/ownir/flow_finally_switch.facts.json +++ b/tests/fixtures/ownir/flow_finally_switch.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "comment": "IR the extractor now emits for finally-before-return and switch lowering. (1) FinallyReturnClean: a `return` inside try-with-finally runs the finally (release r) FIRST, so r is released on the return path -> silent (was bailed before). (2) FinallyReturnLeak: an early return with the dispose AFTER the try (empty finally) leaks on that path. (3) SwitchAllDispose: a no-default switch where every case disposes — modelled with the last case as the tail (no empty no-match branch), so it stays silent (Model A: no phantom-leak FP on an exhaustive switch). (4) SwitchOneLeak: a switch whose default/else branch leaks.", "components": [], diff --git a/tests/fixtures/ownir/flow_leak_on_else.facts.json b/tests/fixtures/ownir/flow_leak_on_else.facts.json index e67c533c..38ac668d 100644 --- a/tests/fixtures/ownir/flow_leak_on_else.facts.json +++ b/tests/fixtures/ownir/flow_leak_on_else.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "components": [], "functions": [ diff --git a/tests/fixtures/ownir/flow_leak_two_exits.facts.json b/tests/fixtures/ownir/flow_leak_two_exits.facts.json index 685cf399..bdfdbc90 100644 --- a/tests/fixtures/ownir/flow_leak_two_exits.facts.json +++ b/tests/fixtures/ownir/flow_leak_two_exits.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "components": [], "functions": [ diff --git a/tests/fixtures/ownir/flow_nested_throw.facts.json b/tests/fixtures/ownir/flow_nested_throw.facts.json index 644a2b07..dd988b71 100644 --- a/tests/fixtures/ownir/flow_nested_throw.facts.json +++ b/tests/fixtures/ownir/flow_nested_throw.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "comment": "Exception-edge RECALL slice: the IR the extractor now emits for three try shapes. (1) NestedThrowLeaks: the throw edge recurses into the `if` and lands before MayThrow() (a nested LEAF), where nestedLeak is still owned -> leaks. (2) DisposeInsideIfWithThrow: the same recursion, but the dispose precedes the throw in each branch, so cif is already released at the edge -> silent. (3) CtorThrowLeaksPrior: a `new` is a throw point; the edge before `var ctorLater = new ...` finds ctorPrior owned -> leaks, while ctorLater (acquired after the edge) is silent.", "components": [], diff --git a/tests/fixtures/ownir/flow_pool_partial.facts.json b/tests/fixtures/ownir/flow_pool_partial.facts.json index a2b2e5a4..312f2987 100644 --- a/tests/fixtures/ownir/flow_pool_partial.facts.json +++ b/tests/fixtures/ownir/flow_pool_partial.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "comment": "Pool buffers on the FLOW path must read as a 'pooled buffer' (Return wording / [resource: pooled buffer]), not the generic 'disposable' — the extractor stamps the acquire kind 'pool' for an ArrayPool Rent so the bridge words it right. (1) PartialPoolLeak: a Rent returned on the fall-through but NOT on the throw edge -> 'may not be returned to the pool on every path'. (2) NeverReturnedPool: a Rent never returned -> 'rented but never returned to the pool'. (3) DisposableControl: a plain disposable on the same partial shape keeps the IDisposable wording. Regression for the flow-path pool mislabel surfaced by the --body-throw-edges Npgsql capstone (CompositeBuilder/BitStringConverters ArrayPool rents).", "components": [], diff --git a/tests/fixtures/ownir/flow_while.facts.json b/tests/fixtures/ownir/flow_while.facts.json index 2a46da9a..b080c970 100644 --- a/tests/fixtures/ownir/flow_while.facts.json +++ b/tests/fixtures/ownir/flow_while.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "components": [], "functions": [ diff --git a/tests/fixtures/ownir/handoff_contract.facts.json b/tests/fixtures/ownir/handoff_contract.facts.json index 4f2eebb7..31f7ede0 100644 --- a/tests/fixtures/ownir/handoff_contract.facts.json +++ b/tests/fixtures/ownir/handoff_contract.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "HandoffBridge", "functions": [ { diff --git a/tests/fixtures/ownir/local_disposable.facts.json b/tests/fixtures/ownir/local_disposable.facts.json index de628c69..d4db5f31 100644 --- a/tests/fixtures/ownir/local_disposable.facts.json +++ b/tests/fixtures/ownir/local_disposable.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Streams", "components": [ { diff --git a/tests/fixtures/ownir/pool.facts.json b/tests/fixtures/ownir/pool.facts.json index d46b58b4..02b261d3 100644 --- a/tests/fixtures/ownir/pool.facts.json +++ b/tests/fixtures/ownir/pool.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "PoolApp", "components": [ { diff --git a/tests/fixtures/ownir/protocol_isloaded_clean.facts.json b/tests/fixtures/ownir/protocol_isloaded_clean.facts.json index 5b55a906..d6655206 100644 --- a/tests/fixtures/ownir/protocol_isloaded_clean.facts.json +++ b/tests/fixtures/ownir/protocol_isloaded_clean.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "components": [], "protocols": [ diff --git a/tests/fixtures/ownir/protocol_isloaded_violation.facts.json b/tests/fixtures/ownir/protocol_isloaded_violation.facts.json index 5c34234f..0daae80f 100644 --- a/tests/fixtures/ownir/protocol_isloaded_violation.facts.json +++ b/tests/fixtures/ownir/protocol_isloaded_violation.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "components": [], "protocols": [ diff --git a/tests/fixtures/ownir/sample.facts.json b/tests/fixtures/ownir/sample.facts.json index baced1c5..81bbac18 100644 --- a/tests/fixtures/ownir/sample.facts.json +++ b/tests/fixtures/ownir/sample.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "WpfApp", "components": [ { diff --git a/tests/fixtures/ownir/subscribe.facts.json b/tests/fixtures/ownir/subscribe.facts.json index f43e72b1..61ec1a06 100644 --- a/tests/fixtures/ownir/subscribe.facts.json +++ b/tests/fixtures/ownir/subscribe.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "WpfMessenger", "components": [ { diff --git a/tests/fixtures/ownir/timer.facts.json b/tests/fixtures/ownir/timer.facts.json index 370d5672..d0e257d6 100644 --- a/tests/fixtures/ownir/timer.facts.json +++ b/tests/fixtures/ownir/timer.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "WpfTimers", "components": [ { diff --git a/tests/fixtures/ownir/unitofwork_flow.facts.json b/tests/fixtures/ownir/unitofwork_flow.facts.json index 2a79f5d7..217885de 100644 --- a/tests/fixtures/ownir/unitofwork_flow.facts.json +++ b/tests/fixtures/ownir/unitofwork_flow.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "components": [], "functions": [ diff --git a/tests/fixtures/ownir/unresolved.facts.json b/tests/fixtures/ownir/unresolved.facts.json index 37ab2b70..6a420b51 100644 --- a/tests/fixtures/ownir/unresolved.facts.json +++ b/tests/fixtures/ownir/unresolved.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "TierA", "components": [ { diff --git a/tests/fixtures/ownir_validation.json b/tests/fixtures/ownir_validation.json index 3b687c83..b90bbffd 100644 --- a/tests/fixtures/ownir_validation.json +++ b/tests/fixtures/ownir_validation.json @@ -41,7 +41,7 @@ "why": "the current version stated explicitly", "section": "version", "document": { - "ownir_version": 0 + "ownir_version": 1 }, "raw": false, "verdict": "accept", @@ -53,7 +53,7 @@ "why": "every known section present but empty — shape-valid, nothing to check", "section": "root", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [], "services": [], "effects": [], @@ -71,7 +71,7 @@ "why": "an unrecognised TOP-LEVEL key is additive and accepted; the strict door gates known vocabulary, it is not a closed-world schema", "section": "root", "document": { - "ownir_version": 0, + "ownir_version": 1, "future_section": [ { "whatever": 1 @@ -88,7 +88,7 @@ "why": "a subscription with no `resource` defaults to 'subscription', which is a known kind", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -107,7 +107,7 @@ "why": "all eight known kinds in one document — the acceptance side of the closed vocabulary", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -149,7 +149,7 @@ "why": "column 1 is the smallest legal column — the boundary just inside the 1-based contract", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -170,7 +170,7 @@ "why": "all three DI lifetimes accepted", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "A", @@ -196,7 +196,7 @@ "why": "all four parameter effects accepted", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -230,7 +230,7 @@ "why": "`effect` is optional — absent is not the same as an unknown value", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -300,7 +300,7 @@ "raw": false, "verdict": "reject", "category": "version", - "message": "OwnIR facts are schema v99, but this core understands v0. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it." + "message": "OwnIR facts are schema v99, but this core understands v1. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it." }, { "name": "version-string", @@ -355,7 +355,7 @@ "why": "`components` must be an array", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": { "a": 1 } @@ -370,7 +370,7 @@ "why": "an array, but not of objects", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ 1, 2 @@ -386,7 +386,7 @@ "why": "each component's `subscriptions` must be an array of objects", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": 7 @@ -403,7 +403,7 @@ "why": "…of OBJECTS, not scalars", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -422,7 +422,7 @@ "why": "`resource` must be a string before its value can be checked", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -443,7 +443,7 @@ "why": "IR4: a present-but-unknown kind changes routing, so it is rejected at the door rather than mis-routed. A new kind must bump OWNIR_VERSION", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -464,7 +464,7 @@ "why": "the empty string is present-but-unknown, not absent", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -485,7 +485,7 @@ "why": "optional `type`, present ⇒ string", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -506,7 +506,7 @@ "why": "optional `source_type`, present ⇒ string", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -527,7 +527,7 @@ "why": "optional `source_provenance`, present ⇒ string", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -548,7 +548,7 @@ "why": "optional `ignore_reason`, present ⇒ string", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -569,7 +569,7 @@ "why": "#317: a column is 1-based or absent. `0` is a producer bug, and reading it as 'unknown' would hide the bug while looking correct", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -590,7 +590,7 @@ "why": "…and so is a negative column", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -611,7 +611,7 @@ "why": "the bool-is-int trap again: `True` would otherwise be accepted as column 1 — a fabricated coordinate. `shape`, not `location`: a bool has no integer form, so the 1-based rule never gets a value to judge", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -632,7 +632,7 @@ "why": "a string column has no integer form either — same axis, and the reference funnels it through the same message", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -653,7 +653,7 @@ "why": "`services` must be an array of objects", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": { "a": 1 } @@ -668,7 +668,7 @@ "why": "the DI lifetime is a closed set", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -686,7 +686,7 @@ "why": "the service name is the identity the DI graph joins on", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "", @@ -704,7 +704,7 @@ "why": "…and it must be a string", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": 7, @@ -722,7 +722,7 @@ "why": "`deps` is an array of strings", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -741,7 +741,7 @@ "why": "…of STRINGS", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -762,7 +762,7 @@ "why": "same for `weak_deps`", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -783,7 +783,7 @@ "why": "same for `root_resolves`", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -804,7 +804,7 @@ "why": "same for `scope_cached`", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -825,7 +825,7 @@ "why": "`file` is a string", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -844,7 +844,7 @@ "why": "`line` is an integer", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -863,7 +863,7 @@ "why": "…and a bool is not an integer", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -882,7 +882,7 @@ "why": "`ctor_file` is a string", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -901,7 +901,7 @@ "why": "`ctor_line` is an integer", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -920,7 +920,7 @@ "why": "`ctor_type` is a string", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -939,7 +939,7 @@ "why": "`root_resolve_sites` is an array of {type,file,line} objects", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -960,7 +960,7 @@ "why": "same for `scope_cache_sites`", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -981,7 +981,7 @@ "why": "`effects` must be an array of objects", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": { "a": 1 } @@ -996,7 +996,7 @@ "why": "`deps` is an array of strings", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "deps": [ @@ -1015,7 +1015,7 @@ "why": "`io` is a boolean", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "io": "yes" @@ -1032,7 +1032,7 @@ "why": "`line` is an integer", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "line": "3" @@ -1049,7 +1049,7 @@ "why": "`bindings` is an array of objects", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": [ @@ -1068,7 +1068,7 @@ "why": "binding `name` is a string", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": [ @@ -1089,7 +1089,7 @@ "why": "binding `init` is a string", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": [ @@ -1110,7 +1110,7 @@ "why": "binding `refs` is string array", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": [ @@ -1133,7 +1133,7 @@ "why": "binding `line` is an integer", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": [ @@ -1154,7 +1154,7 @@ "why": "`functions` must be an array of objects", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": { "a": 1 } @@ -1169,7 +1169,7 @@ "why": "`sig` present ⇒ string. It is the overload key MOS resolution joins on, so a non-string is not a cosmetic problem", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "sig": 7 @@ -1186,7 +1186,7 @@ "why": "`params` is an array of objects", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": "x" @@ -1203,7 +1203,7 @@ "why": "…of OBJECTS", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -1222,7 +1222,7 @@ "why": "the parameter name is the identity effects attach to", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -1243,7 +1243,7 @@ "why": "…and it must be a string", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -1264,7 +1264,7 @@ "why": "param `line` is an integer", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -1286,7 +1286,7 @@ "why": "the parameter effect is a closed set", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -1308,7 +1308,7 @@ "why": "`protocols` must be an array of objects", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": { "a": 1 } @@ -1323,7 +1323,7 @@ "why": "the protocol name is the identity verdicts map back by, so a duplicate is an identity collision, not a harmless repeat. Both records are individually VALID — the older version of this control used records with no `opens`/`closes`, which the reference refused for record shape long before it compared any names", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -1363,7 +1363,7 @@ "why": "`protocol_functions` must be an array of objects", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": { "a": 1 } @@ -1386,7 +1386,7 @@ "raw": false, "verdict": "reject", "category": "version", - "message": "OwnIR facts are schema v99, but this core understands v0. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it." + "message": "OwnIR facts are schema v99, but this core understands v1. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it." }, { "name": "order-version-before-resource", @@ -1407,7 +1407,7 @@ "raw": false, "verdict": "reject", "category": "version", - "message": "OwnIR facts are schema v99, but this core understands v0. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it." + "message": "OwnIR facts are schema v99, but this core understands v1. Build the Roslyn extractor and the Python core from the same commit — the OwnIR fact vocabulary changed between the version that produced this file and the one reading it." }, { "name": "order-root-before-version", @@ -1438,7 +1438,7 @@ "why": "`resource` must be a STRING before its value can be tested against the closed set — a shape failure, not a vocabulary one", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -1460,7 +1460,7 @@ "why": "sections are validated in declaration order: `components` before `services`, so a document breaking both reports components", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": { "a": 1 }, @@ -1478,7 +1478,7 @@ "why": "there is no default lifetime: an absent one is `None`, which is outside the closed set exactly like a misspelt one. This is the case `_svc()` could not express, and the port accepted it", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S" @@ -1495,7 +1495,7 @@ "why": "a service record with nothing in it: the lifetime gate fires first, so this is a vocabulary failure and not a missing-name one", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ {} ] @@ -1510,7 +1510,7 @@ "why": "an explicit null is the same as absent here — both are `None`, and neither is in the closed set", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -1528,7 +1528,7 @@ "why": "with a valid lifetime, an absent name reaches the identity check", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "lifetime": "singleton" @@ -1545,7 +1545,7 @@ "why": "the reference checks `lifetime` BEFORE `name`, so a record that breaks both is a vocabulary failure. A port that validates identity first reports `identity` and is wrong about which rule fired", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "", @@ -1563,7 +1563,7 @@ "why": "…and `name` before the remaining service fields", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "lifetime": "singleton", @@ -1582,7 +1582,7 @@ "why": "within one subscription, the resource vocabulary precedes the column contract", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -1604,7 +1604,7 @@ "why": "…and the column precedes the optional `type`", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -1626,7 +1626,7 @@ "why": "inside a function, `sig` is checked before the body's columns", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "sig": 7, @@ -1649,7 +1649,7 @@ "why": "and the BODY's columns are checked before `params` — the least obvious edge in the whole door, because params read like the more primitive thing", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -1676,7 +1676,7 @@ "why": "within a param, identity precedes the line", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -1698,7 +1698,7 @@ "why": "…the line precedes the column", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -1721,7 +1721,7 @@ "why": "…and the column precedes the effect vocabulary", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -1744,7 +1744,7 @@ "why": "a components SHAPE failure outranks a services VOCABULARY failure, because components is validated first — completely. A door that runs all semantic gates before any shape check reports the vocabulary error and inverts the contract", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": { "a": 1 }, @@ -1764,7 +1764,7 @@ "why": "same precedence with a column failure standing in for the shape one", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -1790,7 +1790,7 @@ "why": "and the same one section later: services before effects", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "lifetime": "bad" @@ -1810,7 +1810,7 @@ "why": "effects before functions", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": { "a": 1 }, @@ -1834,7 +1834,7 @@ "why": "functions before protocols", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -1856,7 +1856,7 @@ "why": "protocols before protocol_functions — the last edge in the chain", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "" @@ -1874,7 +1874,7 @@ "why": "column 1 on a flow op, nested and not — the acceptance twin the rejections below need", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -1920,7 +1920,7 @@ "why": "a non-array `body` is SKIPPED, not rejected: the reference returns early rather than raising. Pinned because it is the kind of tolerance a port silently tightens", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": 7 @@ -1937,7 +1937,7 @@ "why": "…and a non-object op inside the body is skipped the same way", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -1958,7 +1958,7 @@ "why": "the 1-based contract reaches flow ops, not just subscriptions", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -1980,7 +1980,7 @@ "why": "…negative likewise", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -2002,7 +2002,7 @@ "why": "…and the bool-is-int trap, which is a representability failure wherever it appears", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -2024,7 +2024,7 @@ "why": "recursion into `then` — a hoisted branch acquire", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -2051,7 +2051,7 @@ "why": "…into `else`", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -2078,7 +2078,7 @@ "why": "…into a loop `body`", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -2105,7 +2105,7 @@ "why": "…and through three levels, so a one-level-deep port fails here", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -2142,7 +2142,7 @@ "why": "the 1-based boundary on a parameter coordinate", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -2164,7 +2164,7 @@ "why": "the same contract on `params[].column` — a separate call site in the reference, and one the port did not have at all", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -2186,7 +2186,7 @@ "why": "…negative likewise", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -2208,7 +2208,7 @@ "why": "…and the bool-is-int trap on the third call site", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -2230,7 +2230,7 @@ "why": "…and a string, which has no integer form to be 1-based about", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -2252,7 +2252,7 @@ "why": "a name plus an opens/closes pair is a complete protocol", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2279,7 +2279,7 @@ "why": "every optional key at once: barriers, allow with narrowed args, an explicit scope, a description, and `exit_barriers` false — legal only BECAUSE a barrier is present", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2328,7 +2328,7 @@ "why": "the other matcher kind: `call`, with and without narrowed args", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2357,7 +2357,7 @@ "why": "two protocols with DIFFERENT names — the twin that makes the duplicate-name rejection discriminating rather than a test of 'more than one protocol is refused'", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "A", @@ -2397,7 +2397,7 @@ "why": "`protocols` is checked only for LIST-ness at the top; a scalar entry is refused by the record parser", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ 7 ] @@ -2412,7 +2412,7 @@ "why": "…and null is not a record", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ null ] @@ -2427,7 +2427,7 @@ "why": "the protocol name is required, not defaulted", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "opens": {}, @@ -2445,7 +2445,7 @@ "why": "…and must be non-empty", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "", @@ -2472,7 +2472,7 @@ "why": "…and a string", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": 7, @@ -2499,7 +2499,7 @@ "why": "a protocol without `opens` cannot state what it is tracking", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2520,7 +2520,7 @@ "why": "…and likewise `closes`", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2541,7 +2541,7 @@ "why": "a matcher is an object", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2564,7 +2564,7 @@ "why": "the matcher kind is a closed vocabulary (assign | call), fail-loud like a flow op", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2590,7 +2590,7 @@ "why": "…and absent is outside that set too", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2615,7 +2615,7 @@ "why": "the assign target is the member name the rule joins events by", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2642,7 +2642,7 @@ "why": "an opens/closes assign matcher must state the written boolean — 'any write opens' is not a checkable protocol", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2668,7 +2668,7 @@ "why": "…and that value is a boolean", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2695,7 +2695,7 @@ "why": "the callee is the name a call event joins by", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2721,7 +2721,7 @@ "why": "narrowed args are strings", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2750,7 +2750,7 @@ "why": "`barriers` is an array", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2778,7 +2778,7 @@ "why": "`allow` is an array", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2806,7 +2806,7 @@ "why": "`exit_barriers` is a boolean", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2834,7 +2834,7 @@ "why": "no barriers AND no exit barriers: the rule can structurally never fire, which the reference refuses as decoration. Every value here is correctly typed and in vocabulary — what fails is meaning, so the category is `well_formedness`", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2862,7 +2862,7 @@ "why": "a barrier identical to `opens` is dead — the walk checks opens first, so the barrier can never fire. Same category, different mechanism: the record is well-typed and means nothing", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2896,7 +2896,7 @@ "why": "`exit_barriers: false` is legal WITH a barrier — the twin that makes `protocol-never-fires` a rejection about meaning rather than a rejection of the field", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2930,7 +2930,7 @@ "why": "…and a barrier that is not `opens` is legal, which is what makes the equality the defect rather than the presence", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2964,7 +2964,7 @@ "why": "`scope` is an object", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -2992,7 +2992,7 @@ "why": "`scope.methods` is an array — a CONTAINER failure", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -3022,7 +3022,7 @@ "why": "…of non-empty method names. The reference raises one message for this and the case above; the ledger separates them because a missing container and an unusable name are different defects", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -3054,7 +3054,7 @@ "why": "`description` is a string", "section": "protocols", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -3082,7 +3082,7 @@ "why": "the name is read before `opens`/`closes` are required, so a record missing everything reports identity", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "" @@ -3099,7 +3099,7 @@ "why": "`opens` is parsed before `closes`", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": [ { "name": "P", @@ -3120,7 +3120,7 @@ "why": "`events` defaults to empty, so a name alone is a valid record", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M" @@ -3137,7 +3137,7 @@ "why": "all six event kinds including the two recursive ones — the acceptance side of the closed `ev` vocabulary", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3213,7 +3213,7 @@ "why": "like `protocols`, only list-ness is checked at the top", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ 7 ] @@ -3228,7 +3228,7 @@ "why": "…and null is not a record", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ null ] @@ -3243,7 +3243,7 @@ "why": "the method name is what a protocol's scope matches against", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "" @@ -3260,7 +3260,7 @@ "why": "…and it is required", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "file": "a.cs" @@ -3277,7 +3277,7 @@ "why": "`file` is optional but, present, a string", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3295,7 +3295,7 @@ "why": "`events` is an ordered array", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3313,7 +3313,7 @@ "why": "…of objects", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3333,7 +3333,7 @@ "why": "the `ev` discriminator is closed (IR4): a present-but-unknown value is rejected, never skipped", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3355,7 +3355,7 @@ "why": "…and an absent one is outside the set too", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3377,7 +3377,7 @@ "why": "an event line is an integer", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3400,7 +3400,7 @@ "why": "…and the bool-is-int trap reaches here as well", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3423,7 +3423,7 @@ "why": "an assign event's target is a name slot", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3446,7 +3446,7 @@ "why": "…its value is a boolean or absent (absent = an opaque write)", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3470,7 +3470,7 @@ "why": "a call event's callee is a name slot", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3493,7 +3493,7 @@ "why": "…its distinguished arg is a string or absent", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3517,7 +3517,7 @@ "why": "the event vocabulary is enforced recursively — inside `then`", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3544,7 +3544,7 @@ "why": "…inside `else`", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3571,7 +3571,7 @@ "why": "…and inside a loop body", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3598,7 +3598,7 @@ "why": "…through three levels, so a one-level-deep port fails here", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3631,7 +3631,7 @@ "why": "the `ev` vocabulary is tested before the line", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3654,7 +3654,7 @@ "why": "…and the line before the per-kind fields", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -3678,7 +3678,7 @@ "why": "a present null is not an absent section", "section": "root", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": null }, "raw": false, @@ -3691,7 +3691,7 @@ "why": "…same for services", "section": "root", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": null }, "raw": false, @@ -3704,7 +3704,7 @@ "why": "…effects", "section": "root", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": null }, "raw": false, @@ -3717,7 +3717,7 @@ "why": "…functions", "section": "root", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": null }, "raw": false, @@ -3730,7 +3730,7 @@ "why": "…protocols", "section": "root", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocols": null }, "raw": false, @@ -3743,7 +3743,7 @@ "why": "…and protocol_functions", "section": "root", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": null }, "raw": false, @@ -3756,7 +3756,7 @@ "why": "…and one level down", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": null @@ -3773,7 +3773,7 @@ "why": "…likewise params", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": null @@ -3790,7 +3790,7 @@ "why": "…and a null string array", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -3809,7 +3809,7 @@ "why": "…and null bindings", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": null @@ -3826,7 +3826,7 @@ "why": "a null scalar is not an absent scalar either", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -3845,7 +3845,7 @@ "why": "…same for a string scalar", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -3864,7 +3864,7 @@ "why": "…and `resource` null fails the string check before the vocabulary", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -3885,7 +3885,7 @@ "why": "the column is the exception: the reference returns early on None, so an explicit null IS accepted where a null line is not", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -3906,7 +3906,7 @@ "why": "…and a null effect is read as absent, not as an unknown value", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -3928,7 +3928,7 @@ "why": "…and a null `sig` is accepted, because the check is `is not None`", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "sig": null @@ -3945,7 +3945,7 @@ "why": "well-formed DI004/DI005 call-site metadata", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -3977,7 +3977,7 @@ "why": "every site field is defaulted, so `{}` is a legal site", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -3998,7 +3998,7 @@ "why": "the bool-is-int trap inside a site record", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4021,7 +4021,7 @@ "why": "…and a site `type` is a string", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4044,7 +4044,7 @@ "why": "…both site arrays carry the same contract", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4067,7 +4067,7 @@ "why": "the largest REPRESENTABLE line — accepted until the coordinate domain existed, now outside it. Representability and domain are two axes: this value still HAS a signed-64 form, which is exactly why it is `location` and not `shape`", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4086,7 +4086,7 @@ "why": "…and the smallest. The range is still closed at BOTH ends and a port that bounded only the top would pass a one-sided test — the ends have simply moved from the form to the domain", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4105,7 +4105,7 @@ "why": "…and the largest column, which now carries the same upper bound a line does", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -4126,7 +4126,7 @@ "why": "a negative line is REJECTED: it is not the 1-based column rule borrowed, it is the line's own domain — no producer emits one and nothing downstream can point at it (spec/OwnIR.md §4.2)", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4145,7 +4145,7 @@ "why": "…and zero is still the line default, unchanged: it means 'unknown / file-level' and is the bottom of the domain, not an edge case that survived", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4164,7 +4164,7 @@ "why": "one below the range: no representable signed-64 form", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4183,7 +4183,7 @@ "why": "…and one above. This is the value that used to escape into serde: it is still an integer to the parser, so a raw-layer check written as 'is it an integer' waves it through and the typed model refuses it afterwards — a rule living in the model instead of the door", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4202,7 +4202,7 @@ "why": "…the top of the band that is still integer-shaped to the parser", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4221,7 +4221,7 @@ "why": "…and past it, where the parser gives up on integer-ness entirely. Same verdict, same category, different route: the taxonomy must not be able to tell these apart", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4240,7 +4240,7 @@ "why": "a float is not a representable coordinate even when it is whole — and it lands in the same branch as `line-above-u64`, which is why one category over both is the honest reading rather than a convenience", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4259,7 +4259,7 @@ "why": "the constructor coordinate", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4278,7 +4278,7 @@ "why": "a root-resolve site coordinate", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4301,7 +4301,7 @@ "why": "…and the second site array, a separate loop in the reference", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -4324,7 +4324,7 @@ "why": "an effect coordinate", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "line": 9223372036854775808 @@ -4341,7 +4341,7 @@ "why": "…and a binding coordinate", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": [ @@ -4362,7 +4362,7 @@ "why": "a parameter coordinate", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -4384,7 +4384,7 @@ "why": "…and an event coordinate, which reaches the bound through the shared obligation parser rather than through `load()` directly", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -4407,7 +4407,7 @@ "why": "an unrepresentable column is a representability failure…", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -4428,7 +4428,7 @@ "why": "…by either parser route…", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -4449,7 +4449,7 @@ "why": "…as is a float, even a whole one. Previously recorded as `location` next to `line-float`'s `shape`, with a comment calling the difference intentional — the same violation classified two ways because the reference raises one message for both and the category had been read off the message instead of the mechanism", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -4470,7 +4470,7 @@ "why": "…and the 1-based rule still fires for a value that IS representable, so the new axis did not swallow the old one", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -4491,7 +4491,7 @@ "why": "a flow body nested exactly 32 levels is accepted — the boundary case that caught the reference's own off-by-one", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -4673,7 +4673,7 @@ "why": "…and one level further is refused", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -4860,7 +4860,7 @@ "why": "…through `else` as well", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -5047,7 +5047,7 @@ "why": "…and through a loop body", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -5234,7 +5234,7 @@ "why": "an event tree nested exactly 32 levels is accepted", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -5449,7 +5449,7 @@ "why": "…and one level further is refused", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -5670,7 +5670,7 @@ "why": "…through `else`…", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -5891,7 +5891,7 @@ "why": "…and a loop body", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -6112,7 +6112,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level'", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6131,7 +6131,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6150,7 +6150,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6169,7 +6169,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6188,7 +6188,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level'", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6207,7 +6207,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6226,7 +6226,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6245,7 +6245,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6264,7 +6264,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level'", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6287,7 +6287,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6310,7 +6310,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6333,7 +6333,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6356,7 +6356,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level'", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6379,7 +6379,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6402,7 +6402,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6425,7 +6425,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "services", "document": { - "ownir_version": 0, + "ownir_version": 1, "services": [ { "name": "S", @@ -6448,7 +6448,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level'", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "line": 0 @@ -6465,7 +6465,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "line": 2147483647 @@ -6482,7 +6482,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "line": -1 @@ -6499,7 +6499,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "line": 2147483648 @@ -6516,7 +6516,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level'", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": [ @@ -6537,7 +6537,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": [ @@ -6558,7 +6558,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": [ @@ -6579,7 +6579,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "effects", "document": { - "ownir_version": 0, + "ownir_version": 1, "effects": [ { "bindings": [ @@ -6600,7 +6600,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level'", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -6622,7 +6622,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -6644,7 +6644,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -6666,7 +6666,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -6688,7 +6688,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level'", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -6711,7 +6711,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -6734,7 +6734,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -6757,7 +6757,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "protocol_functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "name": "M", @@ -6780,7 +6780,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level' — a field `load()` checked NOWHERE before this change, not even for type (§4.2's recorded exception, now closed)", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -6801,7 +6801,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -6822,7 +6822,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -6843,7 +6843,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -6864,7 +6864,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level' — a field `load()` checked NOWHERE before this change, not even for type (§4.2's recorded exception, now closed)", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -6886,7 +6886,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -6908,7 +6908,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -6930,7 +6930,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -6952,7 +6952,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level' — a field `load()` checked NOWHERE before this change, not even for type (§4.2's recorded exception, now closed)", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -6979,7 +6979,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7006,7 +7006,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7033,7 +7033,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7060,7 +7060,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level' — a field `load()` checked NOWHERE before this change, not even for type (§4.2's recorded exception, now closed)", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7087,7 +7087,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7114,7 +7114,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7141,7 +7141,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7168,7 +7168,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level' — a field `load()` checked NOWHERE before this change, not even for type (§4.2's recorded exception, now closed)", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7195,7 +7195,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7222,7 +7222,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7249,7 +7249,7 @@ "why": "…and one above the top, the value a port that kept the old signed-64 bound would still accept", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7276,7 +7276,7 @@ "why": "a string line has no integer form — `shape`, on the other axis from the domain rejections above", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -7297,7 +7297,7 @@ "why": "…and the bool-is-int trap, which would otherwise read as line 1", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -7318,7 +7318,7 @@ "why": "…and a PRESENT null, which is not the same as absent: the reference reads the slot with a `0` default, so only an absent key takes it", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -7339,7 +7339,7 @@ "why": "a string line has no integer form — `shape`, on the other axis from the domain rejections above", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7361,7 +7361,7 @@ "why": "…and the bool-is-int trap, which would otherwise read as line 1", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7383,7 +7383,7 @@ "why": "…and a PRESENT null, which is not the same as absent: the reference reads the slot with a `0` default, so only an absent key takes it", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7405,7 +7405,7 @@ "why": "a string line has no integer form — `shape`, on the other axis from the domain rejections above", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7432,7 +7432,7 @@ "why": "…and the bool-is-int trap, which would otherwise read as line 1", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7459,7 +7459,7 @@ "why": "…and a PRESENT null, which is not the same as absent: the reference reads the slot with a `0` default, so only an absent key takes it", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7486,7 +7486,7 @@ "why": "a string line has no integer form — `shape`, on the other axis from the domain rejections above", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7513,7 +7513,7 @@ "why": "…and the bool-is-int trap, which would otherwise read as line 1", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7540,7 +7540,7 @@ "why": "…and a PRESENT null, which is not the same as absent: the reference reads the slot with a `0` default, so only an absent key takes it", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7567,7 +7567,7 @@ "why": "a string line has no integer form — `shape`, on the other axis from the domain rejections above", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7594,7 +7594,7 @@ "why": "…and the bool-is-int trap, which would otherwise read as line 1", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7621,7 +7621,7 @@ "why": "…and a PRESENT null, which is not the same as absent: the reference reads the slot with a `0` default, so only an absent key takes it", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7648,7 +7648,7 @@ "why": "the top of the column domain, accepted exactly", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -7669,7 +7669,7 @@ "why": "…and one past it: representable, positive, and outside the domain — `location`, the same axis the 1-based rule is on", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -7690,7 +7690,7 @@ "why": "the top of the column domain, accepted exactly", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -7712,7 +7712,7 @@ "why": "…and one past it: representable, positive, and outside the domain — `location`, the same axis the 1-based rule is on", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "params": [ @@ -7734,7 +7734,7 @@ "why": "the top of the column domain, accepted exactly", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7756,7 +7756,7 @@ "why": "…and one past it: representable, positive, and outside the domain — `location`, the same axis the 1-based rule is on", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7778,7 +7778,7 @@ "why": "a column BELOW the representable form. It is `shape` by mechanism — there is no signed-64 integer here for a 1-based rule to be about — even though the reference's message names the 1-based rule, because it tests `v < 1` before the form. The category is read off the mechanism, which is this ledger's rule and the reason the taxonomy has two axes at all", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -7799,7 +7799,7 @@ "why": "an unknown resource kind and an out-of-domain line in one record: the kind is checked first, so this is `vocabulary`", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -7821,7 +7821,7 @@ "why": "…and the line precedes the column of the same node (§4.1), so a record breaking both reports the line's domain, not the column's type", "section": "components", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [ { "subscriptions": [ @@ -7843,7 +7843,7 @@ "why": "…and the same order inside a flow op", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7866,7 +7866,7 @@ "why": "the BODY's coordinates still precede `params` — the least obvious edge in the door, and now observable through a line as well as a column", "section": "functions", "document": { - "ownir_version": 0, + "ownir_version": 1, "functions": [ { "body": [ @@ -7893,7 +7893,7 @@ "why": "the list present and empty: nothing to check", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [] }, "raw": false, @@ -7906,7 +7906,7 @@ "why": "the four required fields alone (local, callee, file, line) — the optionals are optional", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -7926,7 +7926,7 @@ "why": "a complete family-A entry as the extractor writes it: column, method, family and the unwrapped result type", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -7950,7 +7950,7 @@ "why": "a family-B entry: a non-generic awaitable has no result type, so `result_type` is an explicit null, and `method` / `column` may be null too", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "c", @@ -7974,7 +7974,7 @@ "why": "entries are independent records; two valid ones are two sites", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8000,7 +8000,7 @@ "why": "the section must be an array of objects", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": { "local": "tx" } @@ -8015,7 +8015,7 @@ "why": "…and a PRESENT null is not absent", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": null }, "raw": false, @@ -8028,7 +8028,7 @@ "why": "an entry that is a scalar", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ 7 ] @@ -8043,7 +8043,7 @@ "why": "…and null is not a record", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ null ] @@ -8058,7 +8058,7 @@ "why": "…nor is a bare string, however much it looks like a local", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ "tx" ] @@ -8073,7 +8073,7 @@ "why": "`local` is the finding's event slot — a name slot, so empty is `identity`", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "", @@ -8093,7 +8093,7 @@ "why": "…and it is required", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "callee": "Npgsql.NpgsqlConnection.BeginTransactionAsync/1", @@ -8112,7 +8112,7 @@ "why": "…and a list is not a name — the exact shape the unbound list rendered as a finding", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": [ @@ -8136,7 +8136,7 @@ "why": "…and null is not a name either", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": null, @@ -8156,7 +8156,7 @@ "why": "`callee` is the finding's handler slot (Type.Member/arity) — a name slot", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8176,7 +8176,7 @@ "why": "…and it is required", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8195,7 +8195,7 @@ "why": "…and an object is not a name", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8217,7 +8217,7 @@ "why": "`file` is required (the anchor's file)", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8236,7 +8236,7 @@ "why": "…and it must be a string", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8256,7 +8256,7 @@ "why": "…a present null included", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8276,7 +8276,7 @@ "why": "`line` is required — unlike the defaulted lines elsewhere, an entry with no line is not a site", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8295,7 +8295,7 @@ "why": "a string line has no integer form", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8315,7 +8315,7 @@ "why": "…and the bool-is-int trap", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8335,7 +8335,7 @@ "why": "…and a present null", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8355,7 +8355,7 @@ "why": "…and a float, which is not a coordinate", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8375,7 +8375,7 @@ "why": "a line with no signed-64 form: `shape` by mechanism, on the other axis from the domain controls below", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8395,7 +8395,7 @@ "why": "the 1-based boundary on the site column", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8416,7 +8416,7 @@ "why": "the same column contract as every other column: 0 is a producer bug, not 'unknown'", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8437,7 +8437,7 @@ "why": "…negative likewise", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8458,7 +8458,7 @@ "why": "…and the bool-is-int trap on the column", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8479,7 +8479,7 @@ "why": "…and a string, which has no integer form to be 1-based about", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8500,7 +8500,7 @@ "why": "`method` is a string or null", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8521,7 +8521,7 @@ "why": "`family` is a closed set: a third family does not exist until a witness earns it", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8542,7 +8542,7 @@ "why": "…and a non-string is outside the set the same way a non-string parameter effect is", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8563,7 +8563,7 @@ "why": "…and so is the empty string", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8584,7 +8584,7 @@ "why": "`result_type` is a string or null — the number the unbound list would have rendered as a type name", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8605,7 +8605,7 @@ "why": "both name slots broken: `local` is checked first — observable only through the message, so the control pins the identity category and the pair is kept for a reader", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "", @@ -8625,7 +8625,7 @@ "why": "identity precedes the anchor: a broken callee outranks a missing file", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8644,7 +8644,7 @@ "why": "…and the file precedes the line", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8664,7 +8664,7 @@ "why": "…the line's domain precedes the column's type (§4.1 order)", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8685,7 +8685,7 @@ "why": "…and the column precedes the family vocabulary", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8707,7 +8707,7 @@ "why": "…and the family precedes the result type", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8729,7 +8729,7 @@ "why": "across sections: `protocol_functions` is validated before `orphaned_awaitables`, so a protocol function without a name (identity) outranks a non-array site list (shape)", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "protocol_functions": [ { "file": "a.cs" @@ -8749,7 +8749,7 @@ "why": "…and nothing is validated after it: a document whose only defect is in the site list reports that defect", "section": "order", "document": { - "ownir_version": 0, + "ownir_version": 1, "components": [], "services": [], "effects": [], @@ -8775,7 +8775,7 @@ "why": "`0` is the bottom of the domain and means 'unknown / file-level'", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8795,7 +8795,7 @@ "why": "…and 2147483647 is the top, accepted exactly", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8815,7 +8815,7 @@ "why": "one below the bottom: a representable coordinate outside its domain, so `location` rather than `shape`", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8835,7 +8835,7 @@ "why": "…and one above the top — the value the unbound list degraded to 0 and the strict door now refuses", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8855,7 +8855,7 @@ "why": "the top of the column domain, accepted exactly", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", @@ -8876,7 +8876,7 @@ "why": "…and one past it: representable, positive, and outside the domain — `location`, the same axis the 1-based rule is on", "section": "orphaned_awaitables", "document": { - "ownir_version": 0, + "ownir_version": 1, "orphaned_awaitables": [ { "local": "tx", diff --git a/tests/fixtures/repro/canonical_key_order.facts.json b/tests/fixtures/repro/canonical_key_order.facts.json index 9c843ef4..24a0a3ef 100644 --- a/tests/fixtures/repro/canonical_key_order.facts.json +++ b/tests/fixtures/repro/canonical_key_order.facts.json @@ -10,5 +10,5 @@ "name": "Zed" } ], - "ownir_version": 0 + "ownir_version": 1 } diff --git a/tests/fixtures/repro/canonical_key_order.repro.json b/tests/fixtures/repro/canonical_key_order.repro.json index 0e8772f8..353447a5 100644 --- a/tests/fixtures/repro/canonical_key_order.repro.json +++ b/tests/fixtures/repro/canonical_key_order.repro.json @@ -1,16 +1,16 @@ { "repro_version": 3, "input": { - "ownir_version": 0, + "ownir_version": 1, "raw": { "algorithm": "sha256", - "digest": "ab2653de96439e538502e2689ddd93fdf8fd6a8956190320245653af75ea0790", + "digest": "fbb8fcbd328fd7ccc555d9f41d3878991ce628f92e3642091b4218eacb6ad3dc", "bytes": 377, - "base64": "ewogICJtb2R1bGUiOiAiS2V5T3JkZXIiLAogICJjb21wb25lbnRzIjogWwogICAgewogICAgICAic3Vic2NyaXB0aW9ucyI6IFsKICAgICAgICB7InJlbGVhc2VkIjogZmFsc2UsICJyZXNvdXJjZSI6ICJzdWJzY3JpYmUiLCAibGluZSI6IDMsICJldmVudCI6ICJiLlpldGEiLCAiaGFuZGxlciI6ICJPblpldGEifSwKICAgICAgICB7ImV2ZW50IjogImEuQWxwaGEiLCAibGluZSI6IDQsICJyZXNvdXJjZSI6ICJzdWJzY3JpYmUiLCAicmVsZWFzZWQiOiB0cnVlLCAiaGFuZGxlciI6ICJPbkFscGhhIn0KICAgICAgXSwKICAgICAgImZpbGUiOiAiS2V5T3JkZXIuY3MiLAogICAgICAibmFtZSI6ICJaZWQiCiAgICB9CiAgXSwKICAib3duaXJfdmVyc2lvbiI6IDAKfQo=" + "base64": "ewogICJtb2R1bGUiOiAiS2V5T3JkZXIiLAogICJjb21wb25lbnRzIjogWwogICAgewogICAgICAic3Vic2NyaXB0aW9ucyI6IFsKICAgICAgICB7InJlbGVhc2VkIjogZmFsc2UsICJyZXNvdXJjZSI6ICJzdWJzY3JpYmUiLCAibGluZSI6IDMsICJldmVudCI6ICJiLlpldGEiLCAiaGFuZGxlciI6ICJPblpldGEifSwKICAgICAgICB7ImV2ZW50IjogImEuQWxwaGEiLCAibGluZSI6IDQsICJyZXNvdXJjZSI6ICJzdWJzY3JpYmUiLCAicmVsZWFzZWQiOiB0cnVlLCAiaGFuZGxlciI6ICJPbkFscGhhIn0KICAgICAgXSwKICAgICAgImZpbGUiOiAiS2V5T3JkZXIuY3MiLAogICAgICAibmFtZSI6ICJaZWQiCiAgICB9CiAgXSwKICAib3duaXJfdmVyc2lvbiI6IDEKfQo=" }, "canonical": { "algorithm": "sha256", - "digest": "e48d4893337f2a3180388946f64524119451eecf4b55c84b9d1cdd6ede17e0cb", + "digest": "84301b7dadc06e52b558b3da71322a8f1d863d45694e9ebe7647c9dce5ebb049", "bytes": 283 }, "document": { @@ -37,7 +37,7 @@ "name": "Zed" } ], - "ownir_version": 0 + "ownir_version": 1 } }, "engines": [ @@ -45,19 +45,19 @@ "id": "python-ownlang", "consumed": { "algorithm": "sha256", - "digest": "ab2653de96439e538502e2689ddd93fdf8fd6a8956190320245653af75ea0790", + "digest": "fbb8fcbd328fd7ccc555d9f41d3878991ce628f92e3642091b4218eacb6ad3dc", "bytes": 377 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "KeyOrder", "resources": [ { @@ -208,7 +208,7 @@ "document": { "degraded": null, "module": "KeyOrder", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -249,7 +249,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "635f4f6808ead896f8e16de2a44bbbfb04410e66bd8fc3326eb9c5d98062424f", + "digest": "d41ab0ff6d94e1967ac19effc4eaf992fc23821d1f2d52f5fba79ccb934f5fe4", "bytes": 793 } } @@ -259,19 +259,19 @@ "id": "rust-own-bridge", "consumed": { "algorithm": "sha256", - "digest": "ab2653de96439e538502e2689ddd93fdf8fd6a8956190320245653af75ea0790", + "digest": "fbb8fcbd328fd7ccc555d9f41d3878991ce628f92e3642091b4218eacb6ad3dc", "bytes": 377 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "KeyOrder", "resources": [ { @@ -422,7 +422,7 @@ "document": { "degraded": null, "module": "KeyOrder", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -463,7 +463,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "635f4f6808ead896f8e16de2a44bbbfb04410e66bd8fc3326eb9c5d98062424f", + "digest": "d41ab0ff6d94e1967ac19effc4eaf992fc23821d1f2d52f5fba79ccb934f5fe4", "bytes": 793 } } diff --git a/tests/fixtures/repro/canonical_key_order.trace.json b/tests/fixtures/repro/canonical_key_order.trace.json index 3e599680..61b16fee 100644 --- a/tests/fixtures/repro/canonical_key_order.trace.json +++ b/tests/fixtures/repro/canonical_key_order.trace.json @@ -7,7 +7,7 @@ "engine": "python-ownlang", "input": { "algorithm": "sha256", - "digest": "e48d4893337f2a3180388946f64524119451eecf4b55c84b9d1cdd6ede17e0cb", + "digest": "84301b7dadc06e52b558b3da71322a8f1d863d45694e9ebe7647c9dce5ebb049", "bytes": 283 }, "layers": [ @@ -21,7 +21,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -210,7 +210,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", @@ -258,7 +258,7 @@ "engine": "rust-own-bridge", "input": { "algorithm": "sha256", - "digest": "e48d4893337f2a3180388946f64524119451eecf4b55c84b9d1cdd6ede17e0cb", + "digest": "84301b7dadc06e52b558b3da71322a8f1d863d45694e9ebe7647c9dce5ebb049", "bytes": 283 }, "layers": [ @@ -272,7 +272,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -461,7 +461,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", diff --git a/tests/fixtures/repro/canonical_minimal.facts.json b/tests/fixtures/repro/canonical_minimal.facts.json index 46c14f81..47940bbf 100644 --- a/tests/fixtures/repro/canonical_minimal.facts.json +++ b/tests/fixtures/repro/canonical_minimal.facts.json @@ -1,4 +1,4 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Minimal" } diff --git a/tests/fixtures/repro/canonical_minimal.repro.json b/tests/fixtures/repro/canonical_minimal.repro.json index ce33249d..ea712740 100644 --- a/tests/fixtures/repro/canonical_minimal.repro.json +++ b/tests/fixtures/repro/canonical_minimal.repro.json @@ -1,20 +1,20 @@ { "repro_version": 3, "input": { - "ownir_version": 0, + "ownir_version": 1, "raw": { "algorithm": "sha256", - "digest": "bc5f3772f24bbbb76ca24828da224d4ab991efe07a87d69db69d0bbef175460a", + "digest": "4573241a7888cac6145dd1005623c1edd6573a221d6779515781eb247041ebc7", "bytes": 48, - "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMCwKICAibW9kdWxlIjogIk1pbmltYWwiCn0K" + "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMSwKICAibW9kdWxlIjogIk1pbmltYWwiCn0K" }, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 }, "document": { - "ownir_version": 0, + "ownir_version": 1, "module": "Minimal" } }, @@ -23,19 +23,19 @@ "id": "python-ownlang", "consumed": { "algorithm": "sha256", - "digest": "bc5f3772f24bbbb76ca24828da224d4ab991efe07a87d69db69d0bbef175460a", + "digest": "4573241a7888cac6145dd1005623c1edd6573a221d6779515781eb247041ebc7", "bytes": 48 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "Minimal", "resources": [ { @@ -139,7 +139,7 @@ "document": { "degraded": null, "module": "Minimal", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -163,7 +163,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "4757bdfa72fd168dda7a1ad95f5eec18c6d72bf792166227faf83ac1b2e4a393", + "digest": "aa7b2312f4da58d124b29b75b86b5f05c767ef43cac802cffa19e566740b3096", "bytes": 289 } } @@ -173,19 +173,19 @@ "id": "rust-own-bridge", "consumed": { "algorithm": "sha256", - "digest": "bc5f3772f24bbbb76ca24828da224d4ab991efe07a87d69db69d0bbef175460a", + "digest": "4573241a7888cac6145dd1005623c1edd6573a221d6779515781eb247041ebc7", "bytes": 48 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "Minimal", "resources": [ { @@ -289,7 +289,7 @@ "document": { "degraded": null, "module": "Minimal", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -313,7 +313,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "4757bdfa72fd168dda7a1ad95f5eec18c6d72bf792166227faf83ac1b2e4a393", + "digest": "aa7b2312f4da58d124b29b75b86b5f05c767ef43cac802cffa19e566740b3096", "bytes": 289 } } diff --git a/tests/fixtures/repro/canonical_minimal.trace.json b/tests/fixtures/repro/canonical_minimal.trace.json index ec1d76eb..420af5cd 100644 --- a/tests/fixtures/repro/canonical_minimal.trace.json +++ b/tests/fixtures/repro/canonical_minimal.trace.json @@ -7,7 +7,7 @@ "engine": "python-ownlang", "input": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 }, "layers": [ @@ -21,7 +21,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -147,7 +147,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", @@ -176,7 +176,7 @@ "engine": "rust-own-bridge", "input": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 }, "layers": [ @@ -190,7 +190,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -316,7 +316,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", diff --git a/tests/fixtures/repro/canonical_torture.facts.json b/tests/fixtures/repro/canonical_torture.facts.json index 2ac2851a..c9361052 100644 --- a/tests/fixtures/repro/canonical_torture.facts.json +++ b/tests/fixtures/repro/canonical_torture.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Tortureé漢字😀", "canonical_probe": { "i64_max": 9223372036854775807, diff --git a/tests/fixtures/repro/canonical_torture.repro.json b/tests/fixtures/repro/canonical_torture.repro.json index 86f702b1..b4e8bb5e 100644 --- a/tests/fixtures/repro/canonical_torture.repro.json +++ b/tests/fixtures/repro/canonical_torture.repro.json @@ -1,20 +1,20 @@ { "repro_version": 3, "input": { - "ownir_version": 0, + "ownir_version": 1, "raw": { "algorithm": "sha256", - "digest": "93ef10f5f3541d1abc5fb75a4ffe74c26a764484b7505ab9039ab151e3883e99", + "digest": "a1c896ce83130584dcbb113c751547e4b488fae6798b00fcc919c8a1cdd8a170", "bytes": 1049, - "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMCwKICAibW9kdWxlIjogIlRvcnR1cmXDqea8ouWtl/CfmIAiLAogICJjYW5vbmljYWxfcHJvYmUiOiB7CiAgICAiaTY0X21heCI6IDkyMjMzNzIwMzY4NTQ3NzU4MDcsCiAgICAiaTY0X21pbiI6IC05MjIzMzcyMDM2ODU0Nzc1ODA4LAogICAgInplcm8iOiAwLAogICAgImJvb2xlYW5zIjogW3RydWUsIGZhbHNlXSwKICAgICJudWxsIjogbnVsbCwKICAgICJlbXB0eV9vYmplY3QiOiB7fSwKICAgICJlbXB0eV9hcnJheSI6IFtdLAogICAgImVtcHR5X3N0cmluZyI6ICIiLAogICAgInR3b19jaGFyX2VzY2FwZXMiOiAiXGJcdFxuXGZcciIsCiAgICAib3RoZXJfYzBfY29udHJvbHMiOiAiXHUwMDAwXHUwMDAxXHUwMDFmIiwKICAgICJkZWxldGVfaXNfbm90X2VzY2FwZWQiOiAiXHUwMDdmIiwKICAgICJxdW90ZV9hbmRfYmFja3NsYXNoIjogImhlIHNhaWQgXCJoaVwiIFxcIGJhY2siLAogICAgIm5ic3AiOiAiwqAiLAogICAgImxpbmVfYW5kX3BhcmFncmFwaF9zZXBhcmF0b3JzIjogIuKAqOKAqSIsCiAgICAiYnl0ZV9vcmRlcl9tYXJrIjogIu+7vyIsCiAgICAiYXN0cmFsIjogIvCfmIAiLAogICAgIvCfmIAiOiAiYW4gYXN0cmFsIGtleSBzb3J0cyBhZnRlciBldmVyeSBBU0NJSSBrZXkiLAogICAgIsOpIjogImFuIGFjY2VudGVkIGtleSBzb3J0cyBhZnRlciBldmVyeSBBU0NJSSBrZXkiLAogICAgIiI6ICJ0aGUgZW1wdHkga2V5IHNvcnRzIGZpcnN0IiwKICAgICJaIjogInVwcGVyY2FzZSBaIHNvcnRzIGJlZm9yZSBsb3dlcmNhc2UgYSIsCiAgICAiYSI6ICJsb3dlcmNhc2UgYSIKICB9LAogICJjb21wb25lbnRzIjogWwogICAgewogICAgICAibmFtZSI6ICJUb3J0dXJlVmlldyIsCiAgICAgICJmaWxlIjogIlTDtnJ0dXJlLmNzIiwKICAgICAgInN1YnNjcmlwdGlvbnMiOiBbCiAgICAgICAgeyJldmVudCI6ICJidXMuU3Vic2NyaWJlIiwgImhhbmRsZXIiOiAiT27mvKIiLCAibGluZSI6IDcsICJyZWxlYXNlZCI6IGZhbHNlLCAicmVzb3VyY2UiOiAic3Vic2NyaWJlIn0KICAgICAgXQogICAgfQogIF0KfQo=" + "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMSwKICAibW9kdWxlIjogIlRvcnR1cmXDqea8ouWtl/CfmIAiLAogICJjYW5vbmljYWxfcHJvYmUiOiB7CiAgICAiaTY0X21heCI6IDkyMjMzNzIwMzY4NTQ3NzU4MDcsCiAgICAiaTY0X21pbiI6IC05MjIzMzcyMDM2ODU0Nzc1ODA4LAogICAgInplcm8iOiAwLAogICAgImJvb2xlYW5zIjogW3RydWUsIGZhbHNlXSwKICAgICJudWxsIjogbnVsbCwKICAgICJlbXB0eV9vYmplY3QiOiB7fSwKICAgICJlbXB0eV9hcnJheSI6IFtdLAogICAgImVtcHR5X3N0cmluZyI6ICIiLAogICAgInR3b19jaGFyX2VzY2FwZXMiOiAiXGJcdFxuXGZcciIsCiAgICAib3RoZXJfYzBfY29udHJvbHMiOiAiXHUwMDAwXHUwMDAxXHUwMDFmIiwKICAgICJkZWxldGVfaXNfbm90X2VzY2FwZWQiOiAiXHUwMDdmIiwKICAgICJxdW90ZV9hbmRfYmFja3NsYXNoIjogImhlIHNhaWQgXCJoaVwiIFxcIGJhY2siLAogICAgIm5ic3AiOiAiwqAiLAogICAgImxpbmVfYW5kX3BhcmFncmFwaF9zZXBhcmF0b3JzIjogIuKAqOKAqSIsCiAgICAiYnl0ZV9vcmRlcl9tYXJrIjogIu+7vyIsCiAgICAiYXN0cmFsIjogIvCfmIAiLAogICAgIvCfmIAiOiAiYW4gYXN0cmFsIGtleSBzb3J0cyBhZnRlciBldmVyeSBBU0NJSSBrZXkiLAogICAgIsOpIjogImFuIGFjY2VudGVkIGtleSBzb3J0cyBhZnRlciBldmVyeSBBU0NJSSBrZXkiLAogICAgIiI6ICJ0aGUgZW1wdHkga2V5IHNvcnRzIGZpcnN0IiwKICAgICJaIjogInVwcGVyY2FzZSBaIHNvcnRzIGJlZm9yZSBsb3dlcmNhc2UgYSIsCiAgICAiYSI6ICJsb3dlcmNhc2UgYSIKICB9LAogICJjb21wb25lbnRzIjogWwogICAgewogICAgICAibmFtZSI6ICJUb3J0dXJlVmlldyIsCiAgICAgICJmaWxlIjogIlTDtnJ0dXJlLmNzIiwKICAgICAgInN1YnNjcmlwdGlvbnMiOiBbCiAgICAgICAgeyJldmVudCI6ICJidXMuU3Vic2NyaWJlIiwgImhhbmRsZXIiOiAiT27mvKIiLCAibGluZSI6IDcsICJyZWxlYXNlZCI6IGZhbHNlLCAicmVzb3VyY2UiOiAic3Vic2NyaWJlIn0KICAgICAgXQogICAgfQogIF0KfQo=" }, "canonical": { "algorithm": "sha256", - "digest": "239383fae8175fd42dc773922af7e3dcf26c2148f99a365f8e4404db58224edd", + "digest": "abe4b1afa5a4f287401f9b50c1dec00c57588ab6baabc77968f3f1af232b49f2", "bytes": 834 }, "document": { - "ownir_version": 0, + "ownir_version": 1, "module": "Tortureé漢字😀", "canonical_probe": { "i64_max": 9223372036854775807, @@ -64,19 +64,19 @@ "id": "python-ownlang", "consumed": { "algorithm": "sha256", - "digest": "93ef10f5f3541d1abc5fb75a4ffe74c26a764484b7505ab9039ab151e3883e99", + "digest": "a1c896ce83130584dcbb113c751547e4b488fae6798b00fcc919c8a1cdd8a170", "bytes": 1049 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "Tortureé漢字😀", "resources": [ { @@ -206,7 +206,7 @@ "document": { "degraded": null, "module": "Tortureé漢字😀", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -247,7 +247,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "f9cd8d129d9b8cb698602b840fe50bd8313891ed814b96a20f97fce78b50632a", + "digest": "78ece332c38aa64e10136c8a809552dc47aafaa5bede557d020be4090fe689da", "bytes": 822 } } @@ -257,19 +257,19 @@ "id": "rust-own-bridge", "consumed": { "algorithm": "sha256", - "digest": "93ef10f5f3541d1abc5fb75a4ffe74c26a764484b7505ab9039ab151e3883e99", + "digest": "a1c896ce83130584dcbb113c751547e4b488fae6798b00fcc919c8a1cdd8a170", "bytes": 1049 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "Tortureé漢字😀", "resources": [ { @@ -399,7 +399,7 @@ "document": { "degraded": null, "module": "Tortureé漢字😀", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -440,7 +440,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "f9cd8d129d9b8cb698602b840fe50bd8313891ed814b96a20f97fce78b50632a", + "digest": "78ece332c38aa64e10136c8a809552dc47aafaa5bede557d020be4090fe689da", "bytes": 822 } } diff --git a/tests/fixtures/repro/canonical_torture.trace.json b/tests/fixtures/repro/canonical_torture.trace.json index 5ca0d22f..f12e3106 100644 --- a/tests/fixtures/repro/canonical_torture.trace.json +++ b/tests/fixtures/repro/canonical_torture.trace.json @@ -7,7 +7,7 @@ "engine": "python-ownlang", "input": { "algorithm": "sha256", - "digest": "239383fae8175fd42dc773922af7e3dcf26c2148f99a365f8e4404db58224edd", + "digest": "abe4b1afa5a4f287401f9b50c1dec00c57588ab6baabc77968f3f1af232b49f2", "bytes": 834 }, "layers": [ @@ -21,7 +21,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -179,7 +179,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", @@ -227,7 +227,7 @@ "engine": "rust-own-bridge", "input": { "algorithm": "sha256", - "digest": "239383fae8175fd42dc773922af7e3dcf26c2148f99a365f8e4404db58224edd", + "digest": "abe4b1afa5a4f287401f9b50c1dec00c57588ab6baabc77968f3f1af232b49f2", "bytes": 834 }, "layers": [ @@ -241,7 +241,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -399,7 +399,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", diff --git a/tests/fixtures/repro/di.repro.json b/tests/fixtures/repro/di.repro.json index 434cb96c..518aa99d 100644 --- a/tests/fixtures/repro/di.repro.json +++ b/tests/fixtures/repro/di.repro.json @@ -1,20 +1,20 @@ { "repro_version": 3, "input": { - "ownir_version": 0, + "ownir_version": 1, "raw": { "algorithm": "sha256", - "digest": "dd16be56d7ba44e9c7720a2a05fc110ed7b6ed0e439825dde28b623a11bcd6c0", + "digest": "0d87c5f755986f17d7e7a4e7f5193030113ecd8549049c98b3108696fcf036da", "bytes": 884, - "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMCwKICAibW9kdWxlIjogIkRpRGVtbyIsCiAgImNvbXBvbmVudHMiOiBbXSwKICAic2VydmljZXMiOiBbCiAgICB7Im5hbWUiOiAiRW1haWxTZW5kZXIiLCAibGlmZXRpbWUiOiAic2luZ2xldG9uIiwgImZpbGUiOiAiU3RhcnR1cC5jcyIsICJsaW5lIjogMTIsICJkZXBzIjogWyJBcHBEYkNvbnRleHQiXSwgImN0b3JfZmlsZSI6ICJFbWFpbFNlbmRlci5jcyIsICJjdG9yX2xpbmUiOiA1LCAiY3Rvcl90eXBlIjogIkVtYWlsU2VuZGVyIn0sCiAgICB7Im5hbWUiOiAiQXBwRGJDb250ZXh0IiwgImxpZmV0aW1lIjogInNjb3BlZCIsICJmaWxlIjogIlN0YXJ0dXAuY3MiLCAibGluZSI6IDEzLCAiZGVwcyI6IFtdfSwKICAgIHsibmFtZSI6ICJDbG9jayIsICJsaWZldGltZSI6ICJzaW5nbGV0b24iLCAiZmlsZSI6ICJTdGFydHVwLmNzIiwgImxpbmUiOiAxNCwgImRlcHMiOiBbXX0sCiAgICB7Im5hbWUiOiAiUmVwb3J0U2VydmljZSIsICJsaWZldGltZSI6ICJzaW5nbGV0b24iLCAiZmlsZSI6ICJTdGFydHVwLmNzIiwgImxpbmUiOiAxNSwgImRlcHMiOiBbIlVuaXRPZldvcmsiXSwgImN0b3JfZmlsZSI6ICJSZXBvcnRTZXJ2aWNlLmNzIiwgImN0b3JfbGluZSI6IDcsICJjdG9yX3R5cGUiOiAiUmVwb3J0U2VydmljZSJ9LAogICAgeyJuYW1lIjogIlVuaXRPZldvcmsiLCAibGlmZXRpbWUiOiAidHJhbnNpZW50IiwgImZpbGUiOiAiU3RhcnR1cC5jcyIsICJsaW5lIjogMTYsICJkZXBzIjogWyJBcHBEYkNvbnRleHQiXX0sCiAgICB7Im5hbWUiOiAiUmVxdWVzdExvZyIsICJsaWZldGltZSI6ICJzY29wZWQiLCAiZmlsZSI6ICJTdGFydHVwLmNzIiwgImxpbmUiOiAxNywgImRlcHMiOiBbIkFwcERiQ29udGV4dCJdfQogIF0KfQo=" + "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMSwKICAibW9kdWxlIjogIkRpRGVtbyIsCiAgImNvbXBvbmVudHMiOiBbXSwKICAic2VydmljZXMiOiBbCiAgICB7Im5hbWUiOiAiRW1haWxTZW5kZXIiLCAibGlmZXRpbWUiOiAic2luZ2xldG9uIiwgImZpbGUiOiAiU3RhcnR1cC5jcyIsICJsaW5lIjogMTIsICJkZXBzIjogWyJBcHBEYkNvbnRleHQiXSwgImN0b3JfZmlsZSI6ICJFbWFpbFNlbmRlci5jcyIsICJjdG9yX2xpbmUiOiA1LCAiY3Rvcl90eXBlIjogIkVtYWlsU2VuZGVyIn0sCiAgICB7Im5hbWUiOiAiQXBwRGJDb250ZXh0IiwgImxpZmV0aW1lIjogInNjb3BlZCIsICJmaWxlIjogIlN0YXJ0dXAuY3MiLCAibGluZSI6IDEzLCAiZGVwcyI6IFtdfSwKICAgIHsibmFtZSI6ICJDbG9jayIsICJsaWZldGltZSI6ICJzaW5nbGV0b24iLCAiZmlsZSI6ICJTdGFydHVwLmNzIiwgImxpbmUiOiAxNCwgImRlcHMiOiBbXX0sCiAgICB7Im5hbWUiOiAiUmVwb3J0U2VydmljZSIsICJsaWZldGltZSI6ICJzaW5nbGV0b24iLCAiZmlsZSI6ICJTdGFydHVwLmNzIiwgImxpbmUiOiAxNSwgImRlcHMiOiBbIlVuaXRPZldvcmsiXSwgImN0b3JfZmlsZSI6ICJSZXBvcnRTZXJ2aWNlLmNzIiwgImN0b3JfbGluZSI6IDcsICJjdG9yX3R5cGUiOiAiUmVwb3J0U2VydmljZSJ9LAogICAgeyJuYW1lIjogIlVuaXRPZldvcmsiLCAibGlmZXRpbWUiOiAidHJhbnNpZW50IiwgImZpbGUiOiAiU3RhcnR1cC5jcyIsICJsaW5lIjogMTYsICJkZXBzIjogWyJBcHBEYkNvbnRleHQiXX0sCiAgICB7Im5hbWUiOiAiUmVxdWVzdExvZyIsICJsaWZldGltZSI6ICJzY29wZWQiLCAiZmlsZSI6ICJTdGFydHVwLmNzIiwgImxpbmUiOiAxNywgImRlcHMiOiBbIkFwcERiQ29udGV4dCJdfQogIF0KfQo=" }, "canonical": { "algorithm": "sha256", - "digest": "1dd40fe8691e32cbab0252b749d17fecfc905382907a1ea48b2a9eae8ae9d929", + "digest": "f032d100186d884fc1778e501715e23675460cef64271ddd00525e42f2a88d85", "bytes": 767 }, "document": { - "ownir_version": 0, + "ownir_version": 1, "module": "DiDemo", "components": [], "services": [ @@ -82,19 +82,19 @@ "id": "python-ownlang", "consumed": { "algorithm": "sha256", - "digest": "dd16be56d7ba44e9c7720a2a05fc110ed7b6ed0e439825dde28b623a11bcd6c0", + "digest": "0d87c5f755986f17d7e7a4e7f5193030113ecd8549049c98b3108696fcf036da", "bytes": 884 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "DiDemo", "resources": [ { @@ -198,7 +198,7 @@ "document": { "degraded": null, "module": "DiDemo", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -294,7 +294,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "e231066acedcbd88fff8bb10f2fa7e658f40d09c2a615f0eeb2331f1ed27dd93", + "digest": "1dc9b97ea182ba82d79f49123f5e491306bc99e1e5fd33349c1fd369986655d8", "bytes": 2564 } } @@ -304,19 +304,19 @@ "id": "rust-own-bridge", "consumed": { "algorithm": "sha256", - "digest": "dd16be56d7ba44e9c7720a2a05fc110ed7b6ed0e439825dde28b623a11bcd6c0", + "digest": "0d87c5f755986f17d7e7a4e7f5193030113ecd8549049c98b3108696fcf036da", "bytes": 884 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "DiDemo", "resources": [ { @@ -420,7 +420,7 @@ "document": { "degraded": null, "module": "DiDemo", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -516,7 +516,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "e231066acedcbd88fff8bb10f2fa7e658f40d09c2a615f0eeb2331f1ed27dd93", + "digest": "1dc9b97ea182ba82d79f49123f5e491306bc99e1e5fd33349c1fd369986655d8", "bytes": 2564 } } diff --git a/tests/fixtures/repro/di.trace.json b/tests/fixtures/repro/di.trace.json index 6e00e31f..ea677c81 100644 --- a/tests/fixtures/repro/di.trace.json +++ b/tests/fixtures/repro/di.trace.json @@ -7,7 +7,7 @@ "engine": "python-ownlang", "input": { "algorithm": "sha256", - "digest": "1dd40fe8691e32cbab0252b749d17fecfc905382907a1ea48b2a9eae8ae9d929", + "digest": "f032d100186d884fc1778e501715e23675460cef64271ddd00525e42f2a88d85", "bytes": 767 }, "layers": [ @@ -21,7 +21,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -147,7 +147,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", @@ -253,7 +253,7 @@ "engine": "rust-own-bridge", "input": { "algorithm": "sha256", - "digest": "1dd40fe8691e32cbab0252b749d17fecfc905382907a1ea48b2a9eae8ae9d929", + "digest": "f032d100186d884fc1778e501715e23675460cef64271ddd00525e42f2a88d85", "bytes": 767 }, "layers": [ @@ -267,7 +267,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -393,7 +393,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", diff --git a/tests/fixtures/repro/digests.json b/tests/fixtures/repro/digests.json index 73d4f446..e673f0d6 100644 --- a/tests/fixtures/repro/digests.json +++ b/tests/fixtures/repro/digests.json @@ -6,595 +6,817 @@ { "case": "alias_join_cases", "corpus": "lowered", - "digest": "f3ac08b8799096024dc96f9c740cdeb8838102c485440a4338da02bc1cf11a5f", + "digest": "05a2e24920ee8d36006b4dba4b6a10ba398ef3f37a224b9770bb8f9d13e37f54", "bytes": 377 }, { "case": "canonical_key_order", "corpus": "repro", - "digest": "e48d4893337f2a3180388946f64524119451eecf4b55c84b9d1cdd6ede17e0cb", + "digest": "84301b7dadc06e52b558b3da71322a8f1d863d45694e9ebe7647c9dce5ebb049", "bytes": 283 }, { "case": "canonical_minimal", "corpus": "repro", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 }, { "case": "canonical_torture", "corpus": "repro", - "digest": "239383fae8175fd42dc773922af7e3dcf26c2148f99a365f8e4404db58224edd", + "digest": "abe4b1afa5a4f287401f9b50c1dec00c57588ab6baabc77968f3f1af232b49f2", "bytes": 834 }, { "case": "capture", "corpus": "ownir", - "digest": "a3e8dbaa4f3bb7acd77fcd870ef8bec725e705197c219bcc02638e6acc65daf0", + "digest": "a34f862ff561b0649c879d2bca226bf21cc107f4601c3720c45f3b419ed494b6", "bytes": 696 }, { "case": "contract_inference", "corpus": "ownir", - "digest": "4441c9b0bc8bdcf1a16c9c157214988a80c8fe962dd32c560cd41c596e58c109", + "digest": "96f4fc97febff178709e22be42e6ba4f54c00fa018117605499deeb1e4765fdc", "bytes": 785 }, { "case": "di", "corpus": "ownir", - "digest": "1dd40fe8691e32cbab0252b749d17fecfc905382907a1ea48b2a9eae8ae9d929", + "digest": "f032d100186d884fc1778e501715e23675460cef64271ddd00525e42f2a88d85", "bytes": 767 }, { "case": "di_capture", "corpus": "ownir", - "digest": "acd247ddd2d7ffdd4ebaae20eba8bdb43408ae3ef0914e2a9bb5e9481bb67005", + "digest": "718ba4d6bfd8a4a450a3f22fe6e2fc3774819681605be87009af54752ea7f03b", "bytes": 684 }, { "case": "disposable", "corpus": "ownir", - "digest": "9a3942afd5b77c8930e43d9b931ca84dc7722b801907775a41381aab6c7e8b34", + "digest": "c6a27c0be85a5f41f8f0d7527d6ddb3eb14138bb6993f6759061d97285636fed", "bytes": 430 }, { "case": "flow_column_anchors", "corpus": "ownir", - "digest": "a31d297c8484e461a8dd2ba9d6ddc7d28c5a5b023ad110cc3c116d2dd2e9d58e", + "digest": "fd7aa188032f84027570465837631a31ebffbe33e98f9672640f4978dddf75c8", "bytes": 2288 }, { "case": "flow_finally_switch", "corpus": "ownir", - "digest": "455d7bb9e579975b883274656ddef2f4b2c5283245053255f0cb2ebbc17043d5", + "digest": "5091a185081323ef890cab84c7779443e317c7960b1b6cd38c2ac636a7445ea8", "bytes": 1675 }, { "case": "flow_kill_on_rebind", "corpus": "lowered", - "digest": "495304a931624ee28c79d8b2a6910d06b53b193165afd7ac965419ee99c00335", + "digest": "78534e41a0e95815c779cf7b6ddf8ce292580dc16688d0274ca2f9de2ad916f1", "bytes": 229 }, { "case": "flow_leak_on_else", "corpus": "ownir", - "digest": "d0ebae6b7d708fb28904932181eba56e8c6edd91488a3c7f0650ff1eb91f517f", + "digest": "e5f0bf314e3e335b7444565303b11ebacee6def8e4a1a13d9bb75548e5642645", "bytes": 268 }, { "case": "flow_leak_two_exits", "corpus": "ownir", - "digest": "da3952837918230ce159c9d320b3820854a4fbbcdd013b8a3e0a130c86f092b4", + "digest": "3e1bfac01192596271a025941ff40216743b1be6d010681bc20bd66ebb64f834", "bytes": 315 }, { "case": "flow_nested_throw", "corpus": "ownir", - "digest": "f009d8950f48fd37302564747c364d58f49a64430f2c37978bfb6c2c2fd1460b", + "digest": "98eb6b1074373135d1816a92864c8f6aff0c58679af25e3b2bd2d849129bfd3b", "bytes": 1667 }, { "case": "flow_pool_partial", "corpus": "ownir", - "digest": "59c43eda99a86ee30cb2a4c7781b3044142844c62f8042dbf100233ac8e0c8e6", + "digest": "bf9e24dbce660556fb5028ec2927eccb288267beecab4c1f47065bc02bd27715", "bytes": 1426 }, { "case": "flow_unmapped_refs", "corpus": "lowered", - "digest": "8f19e263ab72914d43f5ae18da36d4196f9142f5b97810374074740eec3328f9", + "digest": "8cab4874d2309bbf2719a3a9bf14bcf9ef0ae91ca254811e3ab90c5986609f12", "bytes": 245 }, { "case": "flow_while", "corpus": "ownir", - "digest": "2c67be045fad2a800d27121117af04b1f58ac42fe69ef3f63c1fabeaab5f0b94", + "digest": "eea40449080bab8241995977bd6bfcb16e12976b576f2b7f7101aab68b3f29a3", "bytes": 255 }, { "case": "fn_params_ordering", "corpus": "lowered", - "digest": "5a639b7c8ac76e5d87cb33b6196c8baf67b4f055266367123207ad924d42d260", + "digest": "bb0f0fa3ff63fec2871244f4ff21c42b3d9bb3a7999ebd37e331e3340cd9c015", "bytes": 479 }, { "case": "handles_global_counters", "corpus": "lowered", - "digest": "cd5112cae07211e5c99f4b4d30c73612d61d8e1a7298b2396d5242253635965b", + "digest": "6822d42983b9130a9bb75265e31fc579ac3786a9f4a9afb11a0d6c0508a8558b", "bytes": 500 }, { "case": "handles_null_metadata", "corpus": "lowered", - "digest": "fa2b63f3f16a0ab9a2d73b43dd666f79ea8690c3eb2754de071d5ee90d83826b", + "digest": "924d57ab06917000b7ba05b04fedaddbdcc82ea586b0ae4c1836c59bf391f5e1", "bytes": 304 }, { "case": "handoff_contract", "corpus": "ownir", - "digest": "a85e62876839d352a5d31d6cab2a23be7bd06cd40793a13fddb40816e06f27a8", + "digest": "aea2a6cb9b81cd4efd70f577e2e163187bf461e883b29bb781e5ab1b17617319", "bytes": 658 }, { "case": "hoist_neg_early_return", "corpus": "lowered", - "digest": "e2ad1e5c33eb5cdfe18b057c059d59e1097217e58b4a70b708794e4f1078c9a1", + "digest": "00b86b9298b97dbc78b6152fb1865f36800a8ff2e672da7fd4b7a8e8a1fc4588", "bytes": 226 }, { "case": "hoist_neg_nested_depth", "corpus": "lowered", - "digest": "d588e0d8103c327b2fad4418906b3cfe38eaf97769b17963274bf3c85b75e2b1", + "digest": "f0baa68324567f1543eccdf08ba4ec91a20059311625d9bef6b8cf2bb1c7a055", "bytes": 242 }, { "case": "hoist_neg_while_body", "corpus": "lowered", - "digest": "d2ae2309b105c985d6eeda13a2eb53b72bcd56fe895ac6919023ecdca72ea1e4", + "digest": "8f4807d8dd0a671659335446601ca8ec5db2c7e21bfd0c50164393f5e0478b0a", "bytes": 195 }, { "case": "hoist_pool_kind", "corpus": "lowered", - "digest": "578e1892bfa7932d76846c4216e0f2e749782e43afcf3d2dddabfbfbd28f4cb1", + "digest": "ff611d1b198ad3febbfab220c8c2b64fa5542cdb599c20c40aeb17701b38bb1b", "bytes": 271 }, { "case": "hoist_positive_release", "corpus": "lowered", - "digest": "cf6479caae0c2bb8122ceffc3056de9ac7bc58da78f33dd440e4a9b4c313bdb2", + "digest": "1d04e37ca5ab97b1bd0baa47a4d41fd4176d142204ebc046958fed9e9a9d07bb", "bytes": 233 }, { "case": "hoist_positive_use_only", "corpus": "lowered", - "digest": "0d02a23d958c3444865c17fd50e4b1cb29ea89bb3a1f382546bbb4d26d512038", + "digest": "155e1c1323bc0dfd414b41ef3cb1e4df01a92b72ec52e8d3af3f020aa409f206", "bytes": 197 }, { "case": "lines_preserved", "corpus": "lowered", - "digest": "48b075d0a88ecf2d5d6d96f310e9a94f31e571fc7d70b2ea6f52723d459d319b", + "digest": "6c49de6c378938a2d3967a37ec3a8a5a584042f3d1c4700666157e1c69264bc6", "bytes": 383 }, { "case": "local_disposable", "corpus": "ownir", - "digest": "e5472c04b60a3916349df8fbb9e36d804be4a2548518de2f539c67e7fe2f589b", + "digest": "128e51ecd78928f091c18bdf8730146cbaa4c020178b3d543df58874131e831f", "bytes": 319 }, { "case": "mos_call_channel_overload_sig", "corpus": "lowered", - "digest": "1ae342b45f6fadead130794925ddc7d0d96788dadf2c1b6cc531888d566ce3b6", + "digest": "88f8295d4e8c8627686e12a7a854233da12104755eca10e78932cf7249eb7b83", "bytes": 601 }, { "case": "mos_call_direct_consume", "corpus": "lowered", - "digest": "d6657c687e33de4fd69be1e1b61c3bf37dc09dd75d1f9b49a3d96e936f8bbf60", + "digest": "e262529ab03eaee2d9720e2dfcfbac2291785bbfd9c5e937870fe87d78b87f63", "bytes": 269 }, { "case": "mos_call_unknown_drop", "corpus": "lowered", - "digest": "bc99586d256861fcf585c68b53b5899a52fbee1c42deea91ce53ccfc1c58c5bd", + "digest": "03a7cf5bf7a61004779897db9107147602d36dd6a8c0ccc92dc7f6eb00ed72ad", "bytes": 245 }, { "case": "mos_fresh_mint", "corpus": "lowered", - "digest": "caef5f8298cf98addbbece7a24487b831dbd5bc806ac0b4225391486c9840a7e", + "digest": "76651f7fb27bf41fdf0711e5fa41caa6a7245f4410774d6254c50833cb13bb4d", "bytes": 409 }, { "case": "mos_killsite_toplevel", "corpus": "lowered", - "digest": "b54f9fa40ee79929fe93cf51bdf1bb754b38fae729b53b8717684026fb29bec2", + "digest": "7b082c4968589063a94944caaec515e9935098510c239673d85297040392f8b2", "bytes": 403 }, { "case": "mos_untrack_inbranch", "corpus": "lowered", - "digest": "603a39cdf16770f6bdb843b5b6af1e174d018b0842cab149cf245335587e3fc3", + "digest": "065f5b2d64412dbf5d7a4aa88cc3e56d3bcdec63444ae349d316299a88ec3023", "bytes": 410 }, { "case": "mosdump_degraded_duplicate_key", "corpus": "summaries", - "digest": "92f052ccef71d87b1b80ff9e9bcd9c74ec9db30b7ad34c883af0096a83088fdd", + "digest": "5d67d6918c18d93df76a29b2d58f50202444d3b95e2a7de6cca64541bb71e06d", "bytes": 376 }, { "case": "mosdump_explicit_effects", "corpus": "summaries", - "digest": "0c052dc3634aed1263f4ec1eff3019d27052617390dcc0f18fc61bc5982003a6", + "digest": "6f1e70cf978838a74c41b26683af4baa0f780a6147888d2ef33ccc9725f10def", "bytes": 461 }, { "case": "mosdump_nonascii_escaping", "corpus": "summaries", - "digest": "75932fdf06e0fbbca45369c8d86672f0c252415695e5c41224f9b5c130b82037", + "digest": "2514d4aef9c1b78656d03bd79afec9aa197f12e6ccea178d1e959e94e4ed5e61", "bytes": 219 }, { "case": "mosdump_overload_merge_tiebreaks", "corpus": "summaries", - "digest": "c84e2e6bfac8830df855205fca738c3a8a14d667cc96a30198f753cf7102059c", + "digest": "ea7627b5b854c959f48cbe7606c728c3a55b199869e0cc33941279067c8f4042", "bytes": 403 }, { "case": "mosdump_partial_and_guarded", "corpus": "summaries", - "digest": "fe5b033ed5e348728bcb9ae6223ffaddc72d1388bffe581275ac73117f6c0fc6", + "digest": "83b3f724c3dfa41e0de104d9d5b68bf2cec8886ec8b5cef4b5e0103e5c825ff2", "bytes": 525 }, { "case": "mosdump_return_chains", "corpus": "summaries", - "digest": "233213ac3f8dd75194e25a66a5d784e9622be282d88f1fe4a546d9b8f66dd36d", + "digest": "1ca46385a7b194fa197ae668a9d093036a338db13dde3fc9649c232db188e200", "bytes": 894 }, { "case": "mosdump_scc_cycles", "corpus": "summaries", - "digest": "15f6a6b43a638b766baef273e5fcaa086f57ab469c44664edd15eea3a6c7fc0e", + "digest": "fbdc666a60dcc512f968caa772efc366b53eae7b88f2f34eb7f8503880ba5c7b", "bytes": 655 }, { "case": "mosdump_sig_vocabulary", "corpus": "summaries", - "digest": "b9683de7109d84886fe703cc9a32c63e27149a976d0447121d49cbc13e81224f", + "digest": "5803620f7c3c4099d4fa460faccee4f2632bf551be95909dfbf2a54014e6be13", "bytes": 514 }, { "case": "mosdump_sink_channels", "corpus": "summaries", - "digest": "a71c3f96df86155c36ecc1b1bf7450636b19d18cb9395f56bfe1cad4c967478d", + "digest": "b42ffde2dd251354d30c072db40e471c0783c13b7e11a5809d52424052eefb88", "bytes": 440 }, { "case": "pool", "corpus": "ownir", - "digest": "79cb88310fefc2641559688cf9851f6199927c5ee4eed43ada7711f2547667ae", + "digest": "8e18fd84acdaa4383c9c72d57ec184d448881cd2ae447284d4d1bafdb01e1399", "bytes": 241 }, { "case": "protocol_isloaded_clean", "corpus": "ownir", - "digest": "cc7539104ac5357e0ed76599177da95f8ea271751e64fa94adff49a399f0a95f", + "digest": "31025ef88e97214db901824cca982f64f98cc91c63b2029671347f4ee65eaa87", "bytes": 1193 }, { "case": "protocol_isloaded_violation", "corpus": "ownir", - "digest": "f821b58b0da7e5ecb94798d1868db377876d945242a4e4d013d6499d7af7ee13", + "digest": "1025d2dadba8f7f00604e5d40a264d286a0d5cf62a243b16578fd00b3430d813", "bytes": 1217 }, { "case": "routing_r1_unresolved", "corpus": "lowered", - "digest": "d1b7da34ce0ad0069211e3fa05d8881ab8ed1da2a5d5c5c4d472a6f14d9633a0", + "digest": "d1d165c2e00d1d312a8afa683917ac7805c48ada9e3a8680660a267012e4b5c5", "bytes": 171 }, { "case": "routing_r2_subscribe_self", "corpus": "lowered", - "digest": "25f7d643e602b10195cfe7358b2715f9c511bb8feb5049265fde6c6c826e6bf8", + "digest": "4c675495f03c095a7ab785d90e625d6aa1781a52cfbd0fd68ad11fcd60e749f1", "bytes": 208 }, { "case": "routing_r3_capture_static", "corpus": "lowered", - "digest": "41cf768f49af1bf0179db32a31870f0e7a2bcdc6e0f732627664935a576becc5", + "digest": "7ef0b85183514bbf77a9df2694bb48320edc1f78da5bd3788e3336696685eee0", "bytes": 421 }, { "case": "routing_r4_returned_fresh", "corpus": "lowered", - "digest": "6b4b0ef2a9a66fe9917a78fa64adcb120e152eabb8164dd2c1aa54bffbcd87e1", + "digest": "b60e041a1c4d5a9ba7c614e75d37ef10998c09ae3ad48fb8d63ce7b01a1e6c38", "bytes": 358 }, { "case": "routing_r5_di_capture", "corpus": "lowered", - "digest": "da3a45a5961c42e43b75f486c081a69bb129c00d4a60e8d7210877467d41e125", + "digest": "ad071a1320ce2d33dc2b24e3fa3b87ad97a42bac3293a407e249b5a999c60258", "bytes": 511 }, { "case": "routing_r6_token_kinds", "corpus": "lowered", - "digest": "4ada77267b035f2148303ed7174761f04d96bb36fa5bd28f4ffd7c34b0bafcf0", + "digest": "b9f462df47c6a5940281e06d5baa5de874587d737b1f818fc0fb6e727f7104e1", "bytes": 675 }, { "case": "sample", "corpus": "ownir", - "digest": "fff7156e1bb4e3de0e54b88042a8ed3f9fac9be535c339d4699f916621484db1", + "digest": "74547157cb2ff329176205cd8e9227b9564d8f57c2f7ff0de99e07250e5db955", "bytes": 375 }, { "case": "subscribe", "corpus": "ownir", - "digest": "c883235a21110fc4f4271b40453e6f786fbe3efdea32cecab065e774f174ec31", + "digest": "1fd329e0c89dc4934b2729c3abf8bad890ff989606820e1cf69c2aae0cd10982", "bytes": 216 }, { "case": "timer", "corpus": "ownir", - "digest": "62804547e0b08ed25035805e4a7ecbc69e46fdde977d6ea12683c6165fac1044", + "digest": "1689f54850d2f09a8ed66d1d24ca52e1bb8cef6bf62e648854b9837e58a3e029", "bytes": 379 }, { "case": "tolerant_unknown_kind", "corpus": "lowered", - "digest": "b33cea96ebe7256e92543b8fc5c131a9b0be52157ee73300ca00a1f092d958d9", + "digest": "22a44716bf2ed49acdb8e373c516b4c86429f0db1bf5f4d8f503c02af384cbe4", "bytes": 150 }, + { + "case": "typestate_cs_a1_alias_of_entity", + "corpus": "lowered", + "digest": "82f4a95de310c4646b7517d3b57bd6edfe3bc9c1c58bf885e501e097fac1e58f", + "bytes": 928 + }, + { + "case": "typestate_cs_a2_entity_through_indexer", + "corpus": "lowered", + "digest": "e7b606b6462ae08b09142b0089c0b7120f14ff0a83d0f7ff288d59a9ac28e79f", + "bytes": 942 + }, + { + "case": "typestate_cs_g6_capability_not_spent", + "corpus": "lowered", + "digest": "ef4c3465e8a2b525c362e46a18a072f1cb64310a8ea13b357bbe5cfbd496e700", + "bytes": 521 + }, + { + "case": "typestate_cs_l10_region_inside_try", + "corpus": "lowered", + "digest": "8e5cbb0fec8d12d14589d77f7432bc73f2f114357d7bee82fcc61bafc69d0ab8", + "bytes": 897 + }, + { + "case": "typestate_cs_l11_region_beside_disposable", + "corpus": "lowered", + "digest": "24a25a98be12223eb1c46244fab02489fa0279f1b852bb55cec8c0bd4babe639", + "bytes": 1250 + }, + { + "case": "typestate_cs_l12_region_beside_leaked_disposable", + "corpus": "lowered", + "digest": "1f854d323f991c27c697c58f96768bf6d13d8d59d01f92f4d716745da794c467", + "bytes": 1237 + }, + { + "case": "typestate_cs_l13_values_captured_into_region", + "corpus": "lowered", + "digest": "3c0912f100d55c783873bb54361d9a6e1a369df110462408da4bff5d1b34ec69", + "bytes": 1107 + }, + { + "case": "typestate_cs_l1_stale_capability", + "corpus": "lowered", + "digest": "ab9295ee55b27c9cf3009f0714f8b27170bba776a93a3c56575c9e7b6f893888", + "bytes": 1695 + }, + { + "case": "typestate_cs_l2_copied_capability", + "corpus": "lowered", + "digest": "064172fda48442fec636584b1642d94a382aa5410b8f67de9f6fe2c5164c58cb", + "bytes": 1045 + }, + { + "case": "typestate_cs_l3_raw_mutation", + "corpus": "lowered", + "digest": "15c824bb3c749f78a1c14331f5092977479e15be6ffdfce719bcc8d70ba53498", + "bytes": 923 + }, + { + "case": "typestate_cs_l4_raw_escape", + "corpus": "lowered", + "digest": "c342366a634db5f0ef31cc3edf35860c7e36b78b59643550961b617c21c5718f", + "bytes": 919 + }, + { + "case": "typestate_cs_l5_normal_transition", + "corpus": "lowered", + "digest": "fc645e613bce7fd4bc85951c2b2cd5ac86e727c9eb422810f08ca9ebaa6628c8", + "bytes": 896 + }, + { + "case": "typestate_cs_l6_two_transitions", + "corpus": "lowered", + "digest": "96bfa97439d1f8ee4dc855f029c3c5a57088bd97492915df4b27f602fe300c49", + "bytes": 1318 + }, + { + "case": "typestate_cs_l6b_chained_transitions", + "corpus": "lowered", + "digest": "8cc7bf2bc99e27de18416db155c5949433707b0b795f546982386a6441e7ce12", + "bytes": 1316 + }, + { + "case": "typestate_cs_l7_read_after_region", + "corpus": "lowered", + "digest": "19c9148385ee6ea47086a927c97323eb646e47cd94271d7020198c56409f3daf", + "bytes": 895 + }, + { + "case": "typestate_cs_l8_branch_inside_region", + "corpus": "lowered", + "digest": "4ecb5a073972e2ded095ac1eed365c2db4f1794d4ed1eb331657e25e04feba88", + "bytes": 1093 + }, + { + "case": "typestate_cs_l9_opaque_calls_around_region", + "corpus": "lowered", + "digest": "adfc9ac66558d84d79360ea4654c8ac4ca3cc5aa6f1f21eb556e40f9d526fdcf", + "bytes": 912 + }, + { + "case": "typestate_cs_x1_nested_region_same_entity", + "corpus": "lowered", + "digest": "28fbaa59b3087ed3261c36f5e8e17e1efceddccabc14f2956c2e31eec273d93d", + "bytes": 1407 + }, + { + "case": "typestate_ef_orderbackend", + "corpus": "lowered", + "digest": "64fcc2e1bfb81147e463666c77fdecdb9b606527cbdc90fe5f6a0342bdb9a2a5", + "bytes": 3796 + }, + { + "case": "typestate_g6_capability_not_spent", + "corpus": "lowered", + "digest": "6fc85ee6d17cf09a6614f23a3c566b6c7db1e897df4ad1fa7738557197710c1b", + "bytes": 1413 + }, + { + "case": "typestate_l1_stale_capability", + "corpus": "lowered", + "digest": "930619b44065043eb7a91379f7f2cb84f21f467ee7deae7f1683b392ec74c12b", + "bytes": 1536 + }, + { + "case": "typestate_l2_copied_capability", + "corpus": "lowered", + "digest": "5e0436c98d213fddad7c135a2ba0a9fbcd0e71eef830a13f325223f57d565153", + "bytes": 1585 + }, + { + "case": "typestate_l3_raw_entity_mutation", + "corpus": "lowered", + "digest": "5f2a4467308b602eab4545156f12dc725072fc23c4b79414b8cb8107a492f86d", + "bytes": 1534 + }, + { + "case": "typestate_l3b_second_region", + "corpus": "lowered", + "digest": "3195d8ce58c7a6eb206a6ee1244bab49e5118e68fff0261f3902df3f19787038", + "bytes": 1601 + }, + { + "case": "typestate_l4_raw_entity_unknown_call", + "corpus": "lowered", + "digest": "9e3a7a14fe8deefe265e929d7c51f0d9cd4da2c71e1c065444c0c3ff665e42d6", + "bytes": 1530 + }, + { + "case": "typestate_l4b_raw_entity_shared_call", + "corpus": "lowered", + "digest": "08d2b6968d802c685faeca531f2af0d4d6ad213662f91073144c0e17aed543e8", + "bytes": 1527 + }, + { + "case": "typestate_l4c_raw_entity_consumed", + "corpus": "lowered", + "digest": "4e6a05dbdfb7a2450d3ebc93eb448b6acae0372ade2d31d21c35a88b8eac2d1f", + "bytes": 1487 + }, + { + "case": "typestate_l4d_token_unknown_call", + "corpus": "lowered", + "digest": "c48148d384e05b06c5070e3c0bc89186740bf27588b069894ed4cc865af519ae", + "bytes": 1526 + }, + { + "case": "typestate_l5_normal_transition", + "corpus": "lowered", + "digest": "28b2a5e8152aa574a07f449056d60f06cd48da5e1ff49f50940bd01199fdf383", + "bytes": 1470 + }, + { + "case": "typestate_l5b_two_transitions", + "corpus": "lowered", + "digest": "cc0bb549463056b5eef0aa9a4fd04ffa8d72adb4f4bb32305c09110e061ffe12", + "bytes": 1569 + }, + { + "case": "typestate_l5c_read_after_region", + "corpus": "lowered", + "digest": "52783299f4959c94d4ed5f549f9cd3fbdfe163fa4698807d46d7d9201fdf6652", + "bytes": 1527 + }, + { + "case": "typestate_n1_token_spent_on_other_entity", + "corpus": "lowered", + "digest": "008d1e473674853be2eb7f4ce27047c3a0db3ec4d1344138d38dddfa86cccaa3", + "bytes": 1606 + }, + { + "case": "typestate_n2_two_tokens_one_region", + "corpus": "lowered", + "digest": "7e478c42d5750c276800fa1e5a3599903f01aa492db6633597dbae5a2b587a99", + "bytes": 1581 + }, + { + "case": "typestate_n3_raw_mutation_inferred_effect", + "corpus": "lowered", + "digest": "8195d3b979b6baa824402f891ff95428a4a0f28d2508f14b887b58e7df0dd2e9", + "bytes": 1613 + }, + { + "case": "typestate_n4_token_outlives_region", + "corpus": "lowered", + "digest": "34cd617242d25cbd6649a0351f4934a5bad835b025a62aeb4efe53cb8218c36d", + "bytes": 1538 + }, + { + "case": "typestate_w1_loan_wordings", + "corpus": "lowered", + "digest": "fa2099dab08f4d510f0d3175d62ccad9b704d99bba5da31ac4b1de64847e7eb6", + "bytes": 1712 + }, + { + "case": "typestate_w2_loan_wordings_pooled", + "corpus": "lowered", + "digest": "c112f0ac827146734d2d89ee70a77e9629893ad100122beacb3063a4d2051f34", + "bytes": 1796 + }, { "case": "unitofwork_flow", "corpus": "ownir", - "digest": "2aa3bdb9963c1a74d7559ddf30ecacbf03b8a73f86979454bbe903c2ac956862", + "digest": "f40ec31aeb8c76fdf377cd8f8e9ac7f8b8e345fcf7a2722c30f2732b583de0a4", "bytes": 324 }, { "case": "unresolved", "corpus": "ownir", - "digest": "3475a764d4449355270566bc27f7457535bd465e8294e40519ea8748525c4cbc", + "digest": "ada74fec0dfc74dbaba397622f4b8aa86766d1398b4ae3ea95fd9a5903f67c30", "bytes": 309 }, { "case": "verdict_boundary_effect_line_negative", "corpus": "verdicts", - "digest": "741485197684324305e4424ef715c7bdb0eefc5fff958b9dffa879041603475c", + "digest": "b3385658d5e763c4a3c14ad3f1e338826df85554f072e8f571966a31ce854c00", "bytes": 336 }, { "case": "verdict_boundary_line_above_u32", "corpus": "verdicts", - "digest": "65bf5f41f6af899cfd01e5b8b371d1d765e477d60ed18a537eacad72de0263a1", + "digest": "592b6343827472c8b8a1e9356441f730f940841abec3515ae3361c5be32f71eb", "bytes": 434 }, { "case": "verdict_boundary_line_negative", "corpus": "verdicts", - "digest": "083698faa3f6aba6d3da9ccc86b9dcdb7326f6a3c967ed6e71e250f1f6993cb5", + "digest": "051678520a5b3c8a926ea635db29560b4eb14424d1e3f15691a28aa9c22a4315", "bytes": 541 }, { "case": "verdict_boundary_service_line_negative", "corpus": "verdicts", - "digest": "50b78714f0ef7f3b080cb537dd8820f80a5a17765e15db39e0d5183558142cf1", + "digest": "5fb548d3e58c11a19d8894a6d6406ea1c8469ce7644977d3c0297fb5b43b88c2", "bytes": 480 }, { "case": "verdict_column_sort_order", "corpus": "verdicts", - "digest": "33f0ab59bd9c1dadc09aa5b2c4f110b9540116f9b51a4e4d2e0c0085e9c96169", + "digest": "2c3f97e4065a1f0ff00732ef10dd2238523d14d4e6105ce863b8537123380aba", "bytes": 960 }, { "case": "verdict_dedup_key_members", "corpus": "verdicts", - "digest": "510950daa897efb50b527b16a15165441d8d84f76299d662402935a19e0c2a05", + "digest": "80e51b34954837db6d2e62c6c700732b7f24e09dc01dbadf078d2a1b8afcd075", "bytes": 973 }, { "case": "verdict_dedup_needs_the_message", "corpus": "verdicts", - "digest": "81fc98c8a762811e57040baeb5b02f19fa6e5b58ad1388056b73811da863f685", + "digest": "6062283edcf11bf49a3464872121f0d73daa269b49f979e1fe1b5ab35c0cec52", "bytes": 663 }, { "case": "verdict_degenerate_metadata", "corpus": "verdicts", - "digest": "b068af472cf610e2860561fe4dc7177f61bc170fdfec5e81279413e7f05d9524", + "digest": "31895c280f2ec7cc7072c60b238c0b3346f63b5a3d6acdf066b2a3e0aabcb461", "bytes": 856 }, { "case": "verdict_di004_call_site_anchor", "corpus": "verdicts", - "digest": "09be7af7d79b67f5d79e462b3b9a9a5ac04eb313c1021344fdf16caf081b8aeb", + "digest": "2bab34529d15196ab3aa1a260e84f2f851a74b7b585430da49e19ef616ebd1f7", "bytes": 1410 }, { "case": "verdict_di005_cache_site_anchor", "corpus": "verdicts", - "digest": "ae041b3d718acac511214765f00efaac3ef77b70d2f0296ff7b1abeaf17f6292", + "digest": "9c36e23eecc9f737ce4df8e4437e52c6c5ec856a1914269d67675982eefe4236", "bytes": 1137 }, { "case": "verdict_di_duplicate_sites_last_wins", "corpus": "verdicts", - "digest": "33aff7fd9961eed97afe9bd78b0271d0333ab27734df86bccfee2e892a226fb6", + "digest": "10904137f0d7efdcf79ef99052ae57f10a9cab99d3c9a09e7bcdd9a0566c25e0", "bytes": 1888 }, { "case": "verdict_di_evidence_degradations", "corpus": "verdicts", - "digest": "e56949c13fd63bceb00fb098bbd9ddab806cfbb00bcc9a80b2a2e49f7cf6584a", + "digest": "37a0e719e16d2c256ca3b9f27e0af509156d9a8b0046aa9e1a064842f340498b", "bytes": 851 }, { "case": "verdict_di_graph_families", "corpus": "verdicts", - "digest": "f6f1dd6bc8ac40468e2252b10e6856dc510be0a38ac4c426fb656c25ecffd457", + "digest": "dd691c530acb0667019af74adea6e1fe6076afe5249a30678063b78e249229ce", "bytes": 1077 }, { "case": "verdict_di_tolerant_typed_coercions", "corpus": "verdicts", - "digest": "db35f35c937b9014c3c3ca14c983ad9f0504925b233cbfbb457885fd60e9ddf0", + "digest": "398d4f6271fd938ec4f11682d5cf1e881c7d52bc7475cd0529ced60847c910d1", "bytes": 901 }, { "case": "verdict_domain_tolerant_readers", "corpus": "verdicts", - "digest": "361da587ce14c818d776f824bb563adaa6ff3e315c337bf21f339abf0a503c55", + "digest": "6da7a9a361830a55d2ab2d32eb05290be3fc93f3323efe72a3650ca4b71a4019", "bytes": 1307 }, { "case": "verdict_door_effect_deps_not_strings", "corpus": "verdicts", - "digest": "9ac5b570e4a2956f2d771aa0cc5de5e1a7584683d0feefe453df6da4d5007c7b", + "digest": "b85df11e6d8bd400d38b209009a3517bce2bce543e65fd2faac863dcfd057cf1", "bytes": 622 }, { "case": "verdict_door_service_unknown_lifetime", "corpus": "verdicts", - "digest": "f812c4f014338788c67b3e3f29f035d074d84714f048b0ff8b696b57432a3752", + "digest": "e7820a76b22a9c562e7533d3f429ee16535c85bef592209d4466dcfa9d83f613", "bytes": 541 }, { "case": "verdict_eff001_slice_dropped", "corpus": "verdicts", - "digest": "5cefb40937373c3f12d6fe5c35f1c97851fc9a071556855c4823c369689ec67b", + "digest": "08def69c7e11a67c510b08cc58e6541bdbd9667a548a253c3f39145991ae6cd5", "bytes": 417 }, { "case": "verdict_eff001_storm_and_memo", "corpus": "verdicts", - "digest": "68d132b1eb434c314635ace94f186ea4f080cb04e79fc26d0d2feb3846f80fb5", + "digest": "94ed663fe27fa19b913bd7cb1696040b5043d908c71995c53ae944d40634a8d3", "bytes": 1054 }, { "case": "verdict_flow_local_wordings", "corpus": "verdicts", - "digest": "59d7ecea9efc0547acddc90d4868713dd50c10abede3b41250f96e66592404c3", + "digest": "9f4f197a3efb607880a2e75a7425c45f8672f06f8f2c43eeba117a4bfb16b60a", "bytes": 1273 }, { "case": "verdict_multi_file_ordering", "corpus": "verdicts", - "digest": "ba871ddc6cc81bd4e3185e51855561ab4b9ed5bd3b400f308a87987bad80d2a0", + "digest": "e111eabe5fbd8fcb152fc4b28b2ab5b4fdb8b92725ea240349c27389837bf8e0", "bytes": 1036 }, { "case": "verdict_own014_escape_slice_dropped", "corpus": "verdicts", - "digest": "48c6d1f5ad01e10b73d984a1140f542b9c56fb1c462a1e17002398362f66ed32", + "digest": "666dc9182ccbb4adc9b6122a90a59b6b38534d22e7f27061289f343c4cfe9b46", "bytes": 598 }, { "case": "verdict_own014_wordings", "corpus": "verdicts", - "digest": "af69dbeed1437c27cc5fcb634231842c4ab0525ea7cc1f68e13e0148a23b12b9", + "digest": "fefa681ee9eda9ed9161d8bf66cfddd865fcc5114b83a200a8fd83e66d048e56", "bytes": 1035 }, { "case": "verdict_own051_gates", "corpus": "verdicts", - "digest": "ff3d7627f6143425985ad86aedb3f6fb962118c72de6e1b047ba8bf0026238ec", + "digest": "4590bdda62b257e16b225991ca1203e050e2627905346ea55d793cdced15b5a2", "bytes": 1262 }, { "case": "verdict_own053_orphaned_awaitable", "corpus": "verdicts", - "digest": "749bd19c7f9d55daf062a251fa21bb64de3abc5614809d562856a8ee457abc00", + "digest": "8c3a714def4bd36329fc4d88ae157c98c90ea354a67859815fb3408686441304", "bytes": 1980 }, { "case": "verdict_pool_view_anchor", "corpus": "verdicts", - "digest": "67a62185aec92d3afdd043816def76b1d69fce13a3fa5339c61cefb69c823504", + "digest": "0c425103a62f8d845d620663d8fbe067e80c2967d9505d7f72466c8840fe549a", "bytes": 493 }, { "case": "verdict_protocol_absent_rules_are_silent", "corpus": "verdicts", - "digest": "6a2c86794db9155f50e8d2f49b5a0750e89bbb2308ddb3e745cbad04cba1debb", + "digest": "cdea8afef32c64801071e43fd6d2cc1bff323372640b3b7801818795b2559bc0", "bytes": 1158 }, { "case": "verdict_protocol_barrier_maybe_two_step_slice", "corpus": "verdicts", - "digest": "10070bdf723cddb776b8bcddbe0ec201d4d58f9018ff8271572436b8c96c5955", + "digest": "40328aaf2b11a6c715eb9a873f39562788fef78b22c0d62363d78cb072ba955b", "bytes": 1309 }, { "case": "verdict_protocol_beside_other_families", "corpus": "verdicts", - "digest": "ad5e4f3f36a1d359ccb8532365801cc4043babd9176556f2a072a85bc334e0f5", + "digest": "30dea8e128ba72742004db04be010e7424b79ae82d3c76b58cd9abc704c7ab7c", "bytes": 1709 }, { "case": "verdict_protocol_exit_codes_and_wordings", "corpus": "verdicts", - "digest": "443ca8012688649cd1f1af51d7fe31b421af9af9518c775f07ff33ff1cecfd31", + "digest": "8533d5e4452f7c353cc81ce0ee4bb1ba7df3267edf5830737aeee90f9d786629", "bytes": 1679 }, { "case": "verdict_protocol_identity_and_line_guards", "corpus": "verdicts", - "digest": "addb7b7e66c3716aa048eb46a7dd49e45f17bca06c82d54bcfd3e314485c2e28", + "digest": "326c47e5ee40b908ae49481c2afdd4647fb29b5f10d8a4770af58d52869fc0f1", "bytes": 1771 }, { "case": "verdict_protocol_obl005_dead_rule", "corpus": "verdicts", - "digest": "cb3e6c15db1365ee93db746d073de313083cbe592a22aaa366d83bc5019c0254", + "digest": "b33de9a202cde29dce6c253c33860af9aebe6e639b03817699712bf4373c715f", "bytes": 2220 }, { "case": "verdict_protocol_tolerant_door_rules", "corpus": "verdicts", - "digest": "d98ab7fa30b2680cf0dbb605fec21bf62a44cd824b6bee6d98a27d23c3994edc", + "digest": "1816d2f2c5e90d64fda2b8edb55d946ac6091fcd6840d74c3c8e03432c444fb0", "bytes": 2018 }, { "case": "verdict_same_site_distinct_events", "corpus": "verdicts", - "digest": "657cb50c6df9feecf3c9791f02a6555aed08810d622b182313ca507623e37c41", + "digest": "2e4358f94b476b9abb5e655d263cfe3e385b0b66fbb626910df6933a1f11967e", "bytes": 1543 }, { "case": "verdict_severity_tiers_and_suppression", "corpus": "verdicts", - "digest": "10ffbd221bd11913531b3b672dabd966dee52983330856941358b0d9416819ad", + "digest": "b769397a6dd2afbfdf5ccbfe7300fee31b5c5b2824288389db0e19f4630bdd29", "bytes": 1916 }, { "case": "verdict_skip_list_artifacts", "corpus": "verdicts", - "digest": "7cec84e88b7002fc0dced5d9c086cbf5763f6b26a6d4f5b8236f47bb67646299", + "digest": "a7db24c76096b3d1214ede7180abcc542f0c460bb0e1e3156cfcc7a41ef79b76", "bytes": 1460 }, { "case": "verdict_subscription_lambda_note", "corpus": "verdicts", - "digest": "526566f9b3ceb3fb45fea6af1d86d0fe722df32159a05410b5cc15fcefa48001", + "digest": "1b3566896123392c76e5b5694b12a68db5c2ca613821e81b0bc44dfdf522199a", "bytes": 589 }, { "case": "verdict_unknown_line_guards", "corpus": "verdicts", - "digest": "94ee4ea27864e84ae6113ed4b17856f1c6882714a3865602a73f289bdb7ab8d2", + "digest": "188ca5752faf2f440513511c65ac823ce48c69bf8effa7af403516f7c0bde9aa", "bytes": 1216 }, { "case": "vocab_unknown_op", "corpus": "lowered", - "digest": "c07494fb952154bcb0f026969754a20bf856c5c12b54a1c9b2aca0468315838d", + "digest": "866a9d0b4bf4898bbcb2a52b9522201efea52c0a0ff7a75ee2963ad4c88851a9", "bytes": 108 } ] diff --git a/tests/fixtures/repro/domain_exponent.facts.json b/tests/fixtures/repro/domain_exponent.facts.json index e2f26a41..641ad6a3 100644 --- a/tests/fixtures/repro/domain_exponent.facts.json +++ b/tests/fixtures/repro/domain_exponent.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DomainExponent", "canonical_probe": 1e3 } diff --git a/tests/fixtures/repro/domain_float.facts.json b/tests/fixtures/repro/domain_float.facts.json index 7ed98021..10ece038 100644 --- a/tests/fixtures/repro/domain_float.facts.json +++ b/tests/fixtures/repro/domain_float.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DomainFloat", "canonical_probe": 1.5 } diff --git a/tests/fixtures/repro/domain_int_above_i64.facts.json b/tests/fixtures/repro/domain_int_above_i64.facts.json index f9393931..9ee63f5d 100644 --- a/tests/fixtures/repro/domain_int_above_i64.facts.json +++ b/tests/fixtures/repro/domain_int_above_i64.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DomainIntAboveI64", "canonical_probe": 9223372036854775808 } diff --git a/tests/fixtures/repro/domain_int_below_i64.facts.json b/tests/fixtures/repro/domain_int_below_i64.facts.json index 6f9efdca..b1fb1c19 100644 --- a/tests/fixtures/repro/domain_int_below_i64.facts.json +++ b/tests/fixtures/repro/domain_int_below_i64.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DomainIntBelowI64", "canonical_probe": -9223372036854775809 } diff --git a/tests/fixtures/repro/domain_negative_zero.facts.json b/tests/fixtures/repro/domain_negative_zero.facts.json index 62e554f3..6d336d98 100644 --- a/tests/fixtures/repro/domain_negative_zero.facts.json +++ b/tests/fixtures/repro/domain_negative_zero.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DomainNegativeZero", "canonical_probe": -0 } diff --git a/tests/fixtures/repro/domain_non_finite.facts.json b/tests/fixtures/repro/domain_non_finite.facts.json index 8dd18dbb..3e33dbf1 100644 --- a/tests/fixtures/repro/domain_non_finite.facts.json +++ b/tests/fixtures/repro/domain_non_finite.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DomainNonFinite", "canonical_probe": NaN } diff --git a/tests/fixtures/repro/hoist_neg_while_body.repro.json b/tests/fixtures/repro/hoist_neg_while_body.repro.json index 050ace09..7d0ee0c2 100644 --- a/tests/fixtures/repro/hoist_neg_while_body.repro.json +++ b/tests/fixtures/repro/hoist_neg_while_body.repro.json @@ -1,20 +1,20 @@ { "repro_version": 3, "input": { - "ownir_version": 0, + "ownir_version": 1, "raw": { "algorithm": "sha256", - "digest": "c1440b469739846502d5f4530184c535580de0f1cbb3f11a88db408c32cf0b4a", + "digest": "a7f863be7b028758543a21c7981207f446de936b37927a3cb1d0bac5289fb977", "bytes": 446, - "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMCwKICAibW9kdWxlIjogIkhvaXN0TmVnMiIsCiAgImZ1bmN0aW9ucyI6IFsKICAgIHsKICAgICAgIm5hbWUiOiAiTSIsCiAgICAgICJmaWxlIjogIkYuY3MiLAogICAgICAiYm9keSI6IFsKICAgICAgICB7CiAgICAgICAgICAib3AiOiAid2hpbGUiLAogICAgICAgICAgImxpbmUiOiAyLAogICAgICAgICAgImJvZHkiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAib3AiOiAiYWNxdWlyZSIsCiAgICAgICAgICAgICAgInZhciI6ICJyIiwKICAgICAgICAgICAgICAibGluZSI6IDMKICAgICAgICAgICAgfQogICAgICAgICAgXQogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgIm9wIjogInJlbGVhc2UiLAogICAgICAgICAgInZhciI6ICJyIiwKICAgICAgICAgICJsaW5lIjogNQogICAgICAgIH0KICAgICAgXQogICAgfQogIF0KfQo=" + "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMSwKICAibW9kdWxlIjogIkhvaXN0TmVnMiIsCiAgImZ1bmN0aW9ucyI6IFsKICAgIHsKICAgICAgIm5hbWUiOiAiTSIsCiAgICAgICJmaWxlIjogIkYuY3MiLAogICAgICAiYm9keSI6IFsKICAgICAgICB7CiAgICAgICAgICAib3AiOiAid2hpbGUiLAogICAgICAgICAgImxpbmUiOiAyLAogICAgICAgICAgImJvZHkiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAib3AiOiAiYWNxdWlyZSIsCiAgICAgICAgICAgICAgInZhciI6ICJyIiwKICAgICAgICAgICAgICAibGluZSI6IDMKICAgICAgICAgICAgfQogICAgICAgICAgXQogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgIm9wIjogInJlbGVhc2UiLAogICAgICAgICAgInZhciI6ICJyIiwKICAgICAgICAgICJsaW5lIjogNQogICAgICAgIH0KICAgICAgXQogICAgfQogIF0KfQo=" }, "canonical": { "algorithm": "sha256", - "digest": "d2ae2309b105c985d6eeda13a2eb53b72bcd56fe895ac6919023ecdca72ea1e4", + "digest": "8f4807d8dd0a671659335446601ca8ec5db2c7e21bfd0c50164393f5e0478b0a", "bytes": 195 }, "document": { - "ownir_version": 0, + "ownir_version": 1, "module": "HoistNeg2", "functions": [ { @@ -47,19 +47,19 @@ "id": "python-ownlang", "consumed": { "algorithm": "sha256", - "digest": "c1440b469739846502d5f4530184c535580de0f1cbb3f11a88db408c32cf0b4a", + "digest": "a7f863be7b028758543a21c7981207f446de936b37927a3cb1d0bac5289fb977", "bytes": 446 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "HoistNeg2", "resources": [ { @@ -201,7 +201,7 @@ "document": { "degraded": null, "module": "HoistNeg2", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", @@ -239,19 +239,19 @@ "id": "rust-own-bridge", "consumed": { "algorithm": "sha256", - "digest": "c1440b469739846502d5f4530184c535580de0f1cbb3f11a88db408c32cf0b4a", + "digest": "a7f863be7b028758543a21c7981207f446de936b37927a3cb1d0bac5289fb977", "bytes": 446 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "HoistNeg2", "resources": [ { @@ -393,7 +393,7 @@ "document": { "degraded": null, "module": "HoistNeg2", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/repro/hoist_neg_while_body.trace.json b/tests/fixtures/repro/hoist_neg_while_body.trace.json index 2f7e2f85..e65040a3 100644 --- a/tests/fixtures/repro/hoist_neg_while_body.trace.json +++ b/tests/fixtures/repro/hoist_neg_while_body.trace.json @@ -7,7 +7,7 @@ "engine": "python-ownlang", "input": { "algorithm": "sha256", - "digest": "d2ae2309b105c985d6eeda13a2eb53b72bcd56fe895ac6919023ecdca72ea1e4", + "digest": "8f4807d8dd0a671659335446601ca8ec5db2c7e21bfd0c50164393f5e0478b0a", "bytes": 195 }, "layers": [ @@ -21,7 +21,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -194,7 +194,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", @@ -233,7 +233,7 @@ "engine": "rust-own-bridge", "input": { "algorithm": "sha256", - "digest": "d2ae2309b105c985d6eeda13a2eb53b72bcd56fe895ac6919023ecdca72ea1e4", + "digest": "8f4807d8dd0a671659335446601ca8ec5db2c7e21bfd0c50164393f5e0478b0a", "bytes": 195 }, "layers": [ @@ -247,7 +247,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -420,7 +420,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", diff --git a/tests/fixtures/repro/mosdump_degraded_duplicate_key.repro.json b/tests/fixtures/repro/mosdump_degraded_duplicate_key.repro.json index 8a49b262..27f0e7f1 100644 --- a/tests/fixtures/repro/mosdump_degraded_duplicate_key.repro.json +++ b/tests/fixtures/repro/mosdump_degraded_duplicate_key.repro.json @@ -1,20 +1,20 @@ { "repro_version": 3, "input": { - "ownir_version": 0, + "ownir_version": 1, "raw": { "algorithm": "sha256", - "digest": "a8f0744b8bdbf9b5cdbbd55b381a44b53d49345f915b852b2019e9cb9aeb2d5a", + "digest": "60debca1e8aede04c2048c023af7f29a7af41131d9b081abaace6d40761bfae5", "bytes": 747, - "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMCwKICAibW9kdWxlIjogIkRlZ3JhZGVkIiwKICAiZnVuY3Rpb25zIjogWwogICAgewogICAgICAibmFtZSI6ICJUYWtlIiwKICAgICAgInNpZyI6ICJTeXN0ZW0uSU8uU3RyZWFtIiwKICAgICAgImZpbGUiOiAidDEuY3MiLAogICAgICAicGFyYW1zIjogWwogICAgICAgIHsKICAgICAgICAgICJuYW1lIjogInAiLAogICAgICAgICAgImxpbmUiOiAxCiAgICAgICAgfQogICAgICBdLAogICAgICAiYm9keSI6IFsKICAgICAgICB7CiAgICAgICAgICAib3AiOiAicmVsZWFzZSIsCiAgICAgICAgICAidmFyIjogInAiLAogICAgICAgICAgImxpbmUiOiAyCiAgICAgICAgfQogICAgICBdCiAgICB9LAogICAgewogICAgICAibmFtZSI6ICJUYWtlIiwKICAgICAgInNpZyI6ICJTeXN0ZW0uU3RyaW5nIiwKICAgICAgImZpbGUiOiAidDIuY3MiLAogICAgICAicGFyYW1zIjogWwogICAgICAgIHsKICAgICAgICAgICJuYW1lIjogInAiLAogICAgICAgICAgImxpbmUiOiA1CiAgICAgICAgfQogICAgICBdLAogICAgICAiYm9keSI6IFsKICAgICAgICB7CiAgICAgICAgICAib3AiOiAidXNlIiwKICAgICAgICAgICJ2YXIiOiAicCIsCiAgICAgICAgICAibGluZSI6IDYKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICJuYW1lIjogIlRha2UoU3lzdGVtLklPLlN0cmVhbSkiLAogICAgICAiZmlsZSI6ICJjbGFzaC5jcyIsCiAgICAgICJib2R5IjogW10KICAgIH0KICBdCn0K" + "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMSwKICAibW9kdWxlIjogIkRlZ3JhZGVkIiwKICAiZnVuY3Rpb25zIjogWwogICAgewogICAgICAibmFtZSI6ICJUYWtlIiwKICAgICAgInNpZyI6ICJTeXN0ZW0uSU8uU3RyZWFtIiwKICAgICAgImZpbGUiOiAidDEuY3MiLAogICAgICAicGFyYW1zIjogWwogICAgICAgIHsKICAgICAgICAgICJuYW1lIjogInAiLAogICAgICAgICAgImxpbmUiOiAxCiAgICAgICAgfQogICAgICBdLAogICAgICAiYm9keSI6IFsKICAgICAgICB7CiAgICAgICAgICAib3AiOiAicmVsZWFzZSIsCiAgICAgICAgICAidmFyIjogInAiLAogICAgICAgICAgImxpbmUiOiAyCiAgICAgICAgfQogICAgICBdCiAgICB9LAogICAgewogICAgICAibmFtZSI6ICJUYWtlIiwKICAgICAgInNpZyI6ICJTeXN0ZW0uU3RyaW5nIiwKICAgICAgImZpbGUiOiAidDIuY3MiLAogICAgICAicGFyYW1zIjogWwogICAgICAgIHsKICAgICAgICAgICJuYW1lIjogInAiLAogICAgICAgICAgImxpbmUiOiA1CiAgICAgICAgfQogICAgICBdLAogICAgICAiYm9keSI6IFsKICAgICAgICB7CiAgICAgICAgICAib3AiOiAidXNlIiwKICAgICAgICAgICJ2YXIiOiAicCIsCiAgICAgICAgICAibGluZSI6IDYKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICJuYW1lIjogIlRha2UoU3lzdGVtLklPLlN0cmVhbSkiLAogICAgICAiZmlsZSI6ICJjbGFzaC5jcyIsCiAgICAgICJib2R5IjogW10KICAgIH0KICBdCn0K" }, "canonical": { "algorithm": "sha256", - "digest": "92f052ccef71d87b1b80ff9e9bcd9c74ec9db30b7ad34c883af0096a83088fdd", + "digest": "5d67d6918c18d93df76a29b2d58f50202444d3b95e2a7de6cca64541bb71e06d", "bytes": 376 }, "document": { - "ownir_version": 0, + "ownir_version": 1, "module": "Degraded", "functions": [ { @@ -66,19 +66,19 @@ "id": "python-ownlang", "consumed": { "algorithm": "sha256", - "digest": "a8f0744b8bdbf9b5cdbbd55b381a44b53d49345f915b852b2019e9cb9aeb2d5a", + "digest": "60debca1e8aede04c2048c023af7f29a7af41131d9b081abaace6d40761bfae5", "bytes": 747 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "Degraded", "resources": [ { @@ -257,7 +257,7 @@ "document": { "degraded": "ValueError: duplicate MethodSkeleton key: Take(System.IO.Stream)", "module": "Degraded", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -298,7 +298,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "4e4a0768c50f8218e945ee0ed0801127681eca2fea72f4d7bdfbe3fd63a2d9f6", + "digest": "11420b28e02f7d9cf9e1ba3791c8420f1565f9f25f0c8e57fb43eac932a2f152", "bytes": 822 } } @@ -308,19 +308,19 @@ "id": "rust-own-bridge", "consumed": { "algorithm": "sha256", - "digest": "a8f0744b8bdbf9b5cdbbd55b381a44b53d49345f915b852b2019e9cb9aeb2d5a", + "digest": "60debca1e8aede04c2048c023af7f29a7af41131d9b081abaace6d40761bfae5", "bytes": 747 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "Degraded", "resources": [ { @@ -499,7 +499,7 @@ "document": { "degraded": "ValueError: duplicate MethodSkeleton key: Take(System.IO.Stream)", "module": "Degraded", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -540,7 +540,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "4e4a0768c50f8218e945ee0ed0801127681eca2fea72f4d7bdfbe3fd63a2d9f6", + "digest": "11420b28e02f7d9cf9e1ba3791c8420f1565f9f25f0c8e57fb43eac932a2f152", "bytes": 822 } } diff --git a/tests/fixtures/repro/mosdump_degraded_duplicate_key.trace.json b/tests/fixtures/repro/mosdump_degraded_duplicate_key.trace.json index 928e619e..afd5a7f4 100644 --- a/tests/fixtures/repro/mosdump_degraded_duplicate_key.trace.json +++ b/tests/fixtures/repro/mosdump_degraded_duplicate_key.trace.json @@ -7,7 +7,7 @@ "engine": "python-ownlang", "input": { "algorithm": "sha256", - "digest": "92f052ccef71d87b1b80ff9e9bcd9c74ec9db30b7ad34c883af0096a83088fdd", + "digest": "5d67d6918c18d93df76a29b2d58f50202444d3b95e2a7de6cca64541bb71e06d", "bytes": 376 }, "layers": [ @@ -21,7 +21,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -238,7 +238,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", @@ -286,7 +286,7 @@ "engine": "rust-own-bridge", "input": { "algorithm": "sha256", - "digest": "92f052ccef71d87b1b80ff9e9bcd9c74ec9db30b7ad34c883af0096a83088fdd", + "digest": "5d67d6918c18d93df76a29b2d58f50202444d3b95e2a7de6cca64541bb71e06d", "bytes": 376 }, "layers": [ @@ -300,7 +300,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -517,7 +517,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", diff --git a/tests/fixtures/repro/protocol_isloaded_violation.repro.json b/tests/fixtures/repro/protocol_isloaded_violation.repro.json index 9c68ced9..a655fe9b 100644 --- a/tests/fixtures/repro/protocol_isloaded_violation.repro.json +++ b/tests/fixtures/repro/protocol_isloaded_violation.repro.json @@ -1,20 +1,20 @@ { "repro_version": 3, "input": { - "ownir_version": 0, + "ownir_version": 1, "raw": { "algorithm": "sha256", - "digest": "02b88bac6b1c9a22f1c410fda97c9d428fc54a1253ab16ca74a5397a4319e8fc", + "digest": "b5fd4f02066e01f09661c2a68b00faa58ec2b5dd6b43a640ff15514cd1f74033", "bytes": 1559, - "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMCwKICAibW9kdWxlIjogIkV4dHJhY3RlZCIsCiAgImNvbXBvbmVudHMiOiBbXSwKICAicHJvdG9jb2xzIjogWwogICAgewogICAgICAibmFtZSI6ICJEb2N1bWVudExvYWRpbmciLAogICAgICAiZGVzY3JpcHRpb24iOiAiVGhlIGRvY3VtZW50IHRyZWUgaXMgaW5jb25zaXN0ZW50IHdoaWxlIElzTG9hZGVkID09IGZhbHNlOyBwdWJsaXNoaW5nIERvY3VtZW50L1Jvd3MvVG90YWxzIGluIHRoYXQgd2luZG93IGhhbmRzIGJpbmRpbmdzIGEgYnJva2VuIG9iamVjdC4iLAogICAgICAib3BlbnMiOiAgeyJraW5kIjogImFzc2lnbiIsICJ0YXJnZXQiOiAiSXNMb2FkZWQiLCAidmFsdWUiOiBmYWxzZX0sCiAgICAgICJjbG9zZXMiOiB7ImtpbmQiOiAiYXNzaWduIiwgInRhcmdldCI6ICJJc0xvYWRlZCIsICJ2YWx1ZSI6IHRydWV9LAogICAgICAiYmFycmllcnMiOiBbCiAgICAgICAgeyJraW5kIjogImNhbGwiLCAiY2FsbGVlIjogIk9uUHJvcGVydHlDaGFuZ2VkIiwKICAgICAgICAgImFyZ3MiOiBbIkRvY3VtZW50IiwgIlJvd3MiLCAiVG90YWxzIiwgIlNlbGVjdGVkSXRlbSJdfQogICAgICBdLAogICAgICAiYWxsb3ciOiBbCiAgICAgICAgeyJraW5kIjogImNhbGwiLCAiY2FsbGVlIjogIk9uUHJvcGVydHlDaGFuZ2VkIiwKICAgICAgICAgImFyZ3MiOiBbIklzTG9hZGVkIiwgIklzQnVzeSIsICJQcm9ncmVzcyIsICJTdGF0dXNUZXh0Il19CiAgICAgIF0sCiAgICAgICJleGl0X2JhcnJpZXJzIjogdHJ1ZSwKICAgICAgInNjb3BlIjogeyJtZXRob2RzIjogWyJCaWdEb2N1bWVudFZpZXdNb2RlbC5Mb2FkQmlnRG9jdW1lbnQiXX0KICAgIH0KICBdLAogICJwcm90b2NvbF9mdW5jdGlvbnMiOiBbCiAgICB7CiAgICAgICJuYW1lIjogIkJyb2tlci5CaWdEb2N1bWVudFZpZXdNb2RlbC5Mb2FkQmlnRG9jdW1lbnQiLAogICAgICAiZmlsZSI6ICJCaWdEb2N1bWVudFZpZXdNb2RlbC5jcyIsCiAgICAgICJldmVudHMiOiBbCiAgICAgICAgeyJldiI6ICJhc3NpZ24iLCAidGFyZ2V0IjogIklzTG9hZGVkIiwgInZhbHVlIjogZmFsc2UsICJsaW5lIjogMTg0fSwKICAgICAgICB7ImV2IjogImNhbGwiLCAiY2FsbGVlIjogIk9uUHJvcGVydHlDaGFuZ2VkIiwgImFyZyI6ICJJc0J1c3kiLCAibGluZSI6IDE4NX0sCiAgICAgICAgeyJldiI6ICJjYWxsIiwgImNhbGxlZSI6ICJSZWJ1aWxkSW5kZXhlcyIsICJsaW5lIjogMTkwfSwKICAgICAgICB7ImV2IjogImlmIiwgImxpbmUiOiAyMjAsICJ0aGVuIjogWwogICAgICAgICAgeyJldiI6ICJjYWxsIiwgImNhbGxlZSI6ICJPblByb3BlcnR5Q2hhbmdlZCIsICJhcmciOiAiRG9jdW1lbnQiLCAibGluZSI6IDI0MX0KICAgICAgICBdLCAiZWxzZSI6IFtdfSwKICAgICAgICB7ImV2IjogImFzc2lnbiIsICJ0YXJnZXQiOiAiSXNMb2FkZWQiLCAidmFsdWUiOiB0cnVlLCAibGluZSI6IDI2MH0sCiAgICAgICAgeyJldiI6ICJjYWxsIiwgImNhbGxlZSI6ICJPblByb3BlcnR5Q2hhbmdlZCIsICJhcmciOiAiRG9jdW1lbnQiLCAibGluZSI6IDI2MX0KICAgICAgXQogICAgfQogIF0KfQo=" + "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMSwKICAibW9kdWxlIjogIkV4dHJhY3RlZCIsCiAgImNvbXBvbmVudHMiOiBbXSwKICAicHJvdG9jb2xzIjogWwogICAgewogICAgICAibmFtZSI6ICJEb2N1bWVudExvYWRpbmciLAogICAgICAiZGVzY3JpcHRpb24iOiAiVGhlIGRvY3VtZW50IHRyZWUgaXMgaW5jb25zaXN0ZW50IHdoaWxlIElzTG9hZGVkID09IGZhbHNlOyBwdWJsaXNoaW5nIERvY3VtZW50L1Jvd3MvVG90YWxzIGluIHRoYXQgd2luZG93IGhhbmRzIGJpbmRpbmdzIGEgYnJva2VuIG9iamVjdC4iLAogICAgICAib3BlbnMiOiAgeyJraW5kIjogImFzc2lnbiIsICJ0YXJnZXQiOiAiSXNMb2FkZWQiLCAidmFsdWUiOiBmYWxzZX0sCiAgICAgICJjbG9zZXMiOiB7ImtpbmQiOiAiYXNzaWduIiwgInRhcmdldCI6ICJJc0xvYWRlZCIsICJ2YWx1ZSI6IHRydWV9LAogICAgICAiYmFycmllcnMiOiBbCiAgICAgICAgeyJraW5kIjogImNhbGwiLCAiY2FsbGVlIjogIk9uUHJvcGVydHlDaGFuZ2VkIiwKICAgICAgICAgImFyZ3MiOiBbIkRvY3VtZW50IiwgIlJvd3MiLCAiVG90YWxzIiwgIlNlbGVjdGVkSXRlbSJdfQogICAgICBdLAogICAgICAiYWxsb3ciOiBbCiAgICAgICAgeyJraW5kIjogImNhbGwiLCAiY2FsbGVlIjogIk9uUHJvcGVydHlDaGFuZ2VkIiwKICAgICAgICAgImFyZ3MiOiBbIklzTG9hZGVkIiwgIklzQnVzeSIsICJQcm9ncmVzcyIsICJTdGF0dXNUZXh0Il19CiAgICAgIF0sCiAgICAgICJleGl0X2JhcnJpZXJzIjogdHJ1ZSwKICAgICAgInNjb3BlIjogeyJtZXRob2RzIjogWyJCaWdEb2N1bWVudFZpZXdNb2RlbC5Mb2FkQmlnRG9jdW1lbnQiXX0KICAgIH0KICBdLAogICJwcm90b2NvbF9mdW5jdGlvbnMiOiBbCiAgICB7CiAgICAgICJuYW1lIjogIkJyb2tlci5CaWdEb2N1bWVudFZpZXdNb2RlbC5Mb2FkQmlnRG9jdW1lbnQiLAogICAgICAiZmlsZSI6ICJCaWdEb2N1bWVudFZpZXdNb2RlbC5jcyIsCiAgICAgICJldmVudHMiOiBbCiAgICAgICAgeyJldiI6ICJhc3NpZ24iLCAidGFyZ2V0IjogIklzTG9hZGVkIiwgInZhbHVlIjogZmFsc2UsICJsaW5lIjogMTg0fSwKICAgICAgICB7ImV2IjogImNhbGwiLCAiY2FsbGVlIjogIk9uUHJvcGVydHlDaGFuZ2VkIiwgImFyZyI6ICJJc0J1c3kiLCAibGluZSI6IDE4NX0sCiAgICAgICAgeyJldiI6ICJjYWxsIiwgImNhbGxlZSI6ICJSZWJ1aWxkSW5kZXhlcyIsICJsaW5lIjogMTkwfSwKICAgICAgICB7ImV2IjogImlmIiwgImxpbmUiOiAyMjAsICJ0aGVuIjogWwogICAgICAgICAgeyJldiI6ICJjYWxsIiwgImNhbGxlZSI6ICJPblByb3BlcnR5Q2hhbmdlZCIsICJhcmciOiAiRG9jdW1lbnQiLCAibGluZSI6IDI0MX0KICAgICAgICBdLCAiZWxzZSI6IFtdfSwKICAgICAgICB7ImV2IjogImFzc2lnbiIsICJ0YXJnZXQiOiAiSXNMb2FkZWQiLCAidmFsdWUiOiB0cnVlLCAibGluZSI6IDI2MH0sCiAgICAgICAgeyJldiI6ICJjYWxsIiwgImNhbGxlZSI6ICJPblByb3BlcnR5Q2hhbmdlZCIsICJhcmciOiAiRG9jdW1lbnQiLCAibGluZSI6IDI2MX0KICAgICAgXQogICAgfQogIF0KfQo=" }, "canonical": { "algorithm": "sha256", - "digest": "f821b58b0da7e5ecb94798d1868db377876d945242a4e4d013d6499d7af7ee13", + "digest": "1025d2dadba8f7f00604e5d40a264d286a0d5cf62a243b16578fd00b3430d813", "bytes": 1217 }, "document": { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "components": [], "protocols": [ @@ -120,19 +120,19 @@ "id": "python-ownlang", "consumed": { "algorithm": "sha256", - "digest": "02b88bac6b1c9a22f1c410fda97c9d428fc54a1253ab16ca74a5397a4319e8fc", + "digest": "b5fd4f02066e01f09661c2a68b00faa58ec2b5dd6b43a640ff15514cd1f74033", "bytes": 1559 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "Extracted", "resources": [ { @@ -236,7 +236,7 @@ "document": { "degraded": null, "module": "Extracted", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -293,7 +293,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "734ea3f64a91b959b6189ab66c1abb3f35bce0276f882cbbc68c74394cbe8509", + "digest": "8cc50bd50c0c89ba50889e19589622969af9607dc7e43e843156391070340f39", "bytes": 1556 } } @@ -303,19 +303,19 @@ "id": "rust-own-bridge", "consumed": { "algorithm": "sha256", - "digest": "02b88bac6b1c9a22f1c410fda97c9d428fc54a1253ab16ca74a5397a4319e8fc", + "digest": "b5fd4f02066e01f09661c2a68b00faa58ec2b5dd6b43a640ff15514cd1f74033", "bytes": 1559 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "Extracted", "resources": [ { @@ -419,7 +419,7 @@ "document": { "degraded": null, "module": "Extracted", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -476,7 +476,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "734ea3f64a91b959b6189ab66c1abb3f35bce0276f882cbbc68c74394cbe8509", + "digest": "8cc50bd50c0c89ba50889e19589622969af9607dc7e43e843156391070340f39", "bytes": 1556 } } diff --git a/tests/fixtures/repro/protocol_isloaded_violation.trace.json b/tests/fixtures/repro/protocol_isloaded_violation.trace.json index e159cf7a..a5f231f2 100644 --- a/tests/fixtures/repro/protocol_isloaded_violation.trace.json +++ b/tests/fixtures/repro/protocol_isloaded_violation.trace.json @@ -7,7 +7,7 @@ "engine": "python-ownlang", "input": { "algorithm": "sha256", - "digest": "f821b58b0da7e5ecb94798d1868db377876d945242a4e4d013d6499d7af7ee13", + "digest": "1025d2dadba8f7f00604e5d40a264d286a0d5cf62a243b16578fd00b3430d813", "bytes": 1217 }, "layers": [ @@ -21,7 +21,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -147,7 +147,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", @@ -211,7 +211,7 @@ "engine": "rust-own-bridge", "input": { "algorithm": "sha256", - "digest": "f821b58b0da7e5ecb94798d1868db377876d945242a4e4d013d6499d7af7ee13", + "digest": "1025d2dadba8f7f00604e5d40a264d286a0d5cf62a243b16578fd00b3430d813", "bytes": 1217 }, "layers": [ @@ -225,7 +225,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -351,7 +351,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", diff --git a/tests/fixtures/repro/variants/bom.bin b/tests/fixtures/repro/variants/bom.bin index 936fa079..f74ea8de 100644 --- a/tests/fixtures/repro/variants/bom.bin +++ b/tests/fixtures/repro/variants/bom.bin @@ -1,4 +1,4 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Minimal" } diff --git a/tests/fixtures/repro/variants/byte_variants.json b/tests/fixtures/repro/variants/byte_variants.json index 37f68aa2..1571f8a5 100644 --- a/tests/fixtures/repro/variants/byte_variants.json +++ b/tests/fixtures/repro/variants/byte_variants.json @@ -10,7 +10,7 @@ ], "raw": { "algorithm": "sha256", - "digest": "bc2eb8d0b2dd4644ef71114ff85902cfe2c3cbaa1b0ed8d7d679d9d4f87eae19", + "digest": "dcb356dc38153f87557fca387626f9141f3b7e7c0e56a60de05ee3382fb93386", "bytes": 51 }, "python": { @@ -35,7 +35,7 @@ ], "raw": { "algorithm": "sha256", - "digest": "8a55a9878421cf6b34613a885a794bd45b027394d9fd098f3337fbcf691cd08e", + "digest": "b5517c9a81f5beeb40ed922a8513b07be328ee9657c96c8437da7054e39a19bf", "bytes": 52 }, "python": { @@ -50,13 +50,13 @@ "typed_door_accepted": true, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, @@ -68,7 +68,7 @@ ], "raw": { "algorithm": "sha256", - "digest": "cf1235ec70bd51243afc010f749e824c8708e0e847ef979cbfc203b5a9b08de3", + "digest": "2b6f6f3963575300fd43ca5e771be0bbc9f9c2cbf9d628832df6e5c1d3879ca5", "bytes": 49 }, "python": { @@ -83,13 +83,13 @@ "typed_door_accepted": true, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, @@ -101,7 +101,7 @@ ], "raw": { "algorithm": "sha256", - "digest": "85dbfe4aaf6b983a4e953cc4715e98d85b803103f787ea993c664dbbf0908219", + "digest": "6394abbd914117b7da2699abbc12e791a5a78b9699aad8bfd1e6232c8d5236b6", "bytes": 48 }, "python": { @@ -126,7 +126,7 @@ ], "raw": { "algorithm": "sha256", - "digest": "daf4baa39138c6c5c4b08de8483ecf395de2c7c1d4767edb65fac626c0a2bbf2", + "digest": "5a7a1a044ea315d567f9a0777031b7b5ba7d16f32606a3e331acdab7cf47d7df", "bytes": 48 }, "python": { @@ -141,13 +141,13 @@ "typed_door_accepted": true, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, @@ -159,7 +159,7 @@ ], "raw": { "algorithm": "sha256", - "digest": "9ac14b4869fb80a85e6e24299145189a393613b278f746007f3fec2a3e4552e3", + "digest": "ed5c01c1831c9a090b346c96334da79b70b85951d851f92621a5d896e03935b8", "bytes": 46 }, "python": { @@ -184,7 +184,7 @@ ], "raw": { "algorithm": "sha256", - "digest": "932481c5c66c42b5be67ece2fc1ebd326ff3d88f24c1313b48581b1c55251c09", + "digest": "b3d45f877b03fc8129e6343f1b2344f8d493ae8590a5ca8c9dad12edfbc58b21", "bytes": 47 }, "python": { @@ -199,13 +199,13 @@ "typed_door_accepted": true, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, @@ -217,7 +217,7 @@ ], "raw": { "algorithm": "sha256", - "digest": "bc5f3772f24bbbb76ca24828da224d4ab991efe07a87d69db69d0bbef175460a", + "digest": "4573241a7888cac6145dd1005623c1edd6573a221d6779515781eb247041ebc7", "bytes": 48 }, "python": { @@ -232,13 +232,13 @@ "typed_door_accepted": true, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, @@ -250,7 +250,7 @@ ], "raw": { "algorithm": "sha256", - "digest": "125efc27f3f0d62857b16bd305557332692df8396892a77485b559004d64ca0e", + "digest": "6fe99998f020698c05a07209e1de1c86ee9eef20fcde2ad4eab5e0ee18192dbc", "bytes": 38 }, "python": { @@ -265,13 +265,13 @@ "typed_door_accepted": true, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, @@ -283,7 +283,7 @@ ], "raw": { "algorithm": "sha256", - "digest": "3482b974719a7f7e9465b9db87016cc59688ac86dce80a7bb94c0db6d6c9e3b1", + "digest": "74c40b0a7c1b78ed452f72dc9f61894c9f601b9b5de73a1f97cd6d7ec416d963", "bytes": 52 }, "python": { @@ -298,13 +298,13 @@ "typed_door_accepted": true, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } }, "canonical": { "algorithm": "sha256", - "digest": "c5387976673a8a5a1cc3078398935ae907cddf9c0fc9fdf9cb1c63ed74722313", + "digest": "0f3af651cbd63f59131e16da784820e334fa68ed69b29fb068076abf4374d319", "bytes": 38 } } diff --git a/tests/fixtures/repro/variants/crlf.bin b/tests/fixtures/repro/variants/crlf.bin index 9d17f39b..14a675ad 100644 --- a/tests/fixtures/repro/variants/crlf.bin +++ b/tests/fixtures/repro/variants/crlf.bin @@ -1,4 +1,4 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Minimal" } diff --git a/tests/fixtures/repro/variants/extra_trailing_newline.bin b/tests/fixtures/repro/variants/extra_trailing_newline.bin index 95b3fb24..735741ec 100644 --- a/tests/fixtures/repro/variants/extra_trailing_newline.bin +++ b/tests/fixtures/repro/variants/extra_trailing_newline.bin @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Minimal" } diff --git a/tests/fixtures/repro/variants/invalid_utf8.bin b/tests/fixtures/repro/variants/invalid_utf8.bin index 14637283..323c1c03 100644 --- a/tests/fixtures/repro/variants/invalid_utf8.bin +++ b/tests/fixtures/repro/variants/invalid_utf8.bin @@ -1,4 +1,4 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Minim€l" } diff --git a/tests/fixtures/repro/variants/key_order_reversed.bin b/tests/fixtures/repro/variants/key_order_reversed.bin index 6c942cd0..893cc908 100644 --- a/tests/fixtures/repro/variants/key_order_reversed.bin +++ b/tests/fixtures/repro/variants/key_order_reversed.bin @@ -1,4 +1,4 @@ { "module": "Minimal", - "ownir_version": 0 + "ownir_version": 1 } diff --git a/tests/fixtures/repro/variants/malformed_json.bin b/tests/fixtures/repro/variants/malformed_json.bin index f0c2dc1c..849e3c97 100644 --- a/tests/fixtures/repro/variants/malformed_json.bin +++ b/tests/fixtures/repro/variants/malformed_json.bin @@ -1,3 +1,3 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Minimal" diff --git a/tests/fixtures/repro/variants/no_trailing_newline.bin b/tests/fixtures/repro/variants/no_trailing_newline.bin index dd0aa2e6..4cbc3f44 100644 --- a/tests/fixtures/repro/variants/no_trailing_newline.bin +++ b/tests/fixtures/repro/variants/no_trailing_newline.bin @@ -1,4 +1,4 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Minimal" } \ No newline at end of file diff --git a/tests/fixtures/repro/variants/plain.bin b/tests/fixtures/repro/variants/plain.bin index 46c14f81..47940bbf 100644 --- a/tests/fixtures/repro/variants/plain.bin +++ b/tests/fixtures/repro/variants/plain.bin @@ -1,4 +1,4 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Minimal" } diff --git a/tests/fixtures/repro/variants/whitespace_compact.bin b/tests/fixtures/repro/variants/whitespace_compact.bin index e26d3bec..c3d1a7f4 100644 --- a/tests/fixtures/repro/variants/whitespace_compact.bin +++ b/tests/fixtures/repro/variants/whitespace_compact.bin @@ -1 +1 @@ -{"ownir_version":0,"module":"Minimal"} \ No newline at end of file +{"ownir_version":1,"module":"Minimal"} \ No newline at end of file diff --git a/tests/fixtures/repro/variants/whitespace_expanded.bin b/tests/fixtures/repro/variants/whitespace_expanded.bin index fcc7fc9f..b425f44e 100644 --- a/tests/fixtures/repro/variants/whitespace_expanded.bin +++ b/tests/fixtures/repro/variants/whitespace_expanded.bin @@ -1,4 +1,4 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Minimal" } diff --git a/tests/fixtures/repro/verdict_door_effect_deps_not_strings.repro.json b/tests/fixtures/repro/verdict_door_effect_deps_not_strings.repro.json index 6bc75a9e..cb344746 100644 --- a/tests/fixtures/repro/verdict_door_effect_deps_not_strings.repro.json +++ b/tests/fixtures/repro/verdict_door_effect_deps_not_strings.repro.json @@ -1,20 +1,20 @@ { "repro_version": 3, "input": { - "ownir_version": 0, + "ownir_version": 1, "raw": { "algorithm": "sha256", - "digest": "1709103f7676c80ef52d6d0ad42ce4040842a61f6b63f55a5b133620e778b069", + "digest": "c28447881206b741a6c80335c945308cbbf16b8eb7a44e6490a44e1c17a9ab05", "bytes": 948, - "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMCwKICAibW9kdWxlIjogIkRvb3IiLAogICJjb21wb25lbnRzIjogW10sCiAgIl9kb2MiOiBbCiAgICAiIzI5NCBPRC0xOiBCUi1EMidzIHNraXAtbm90LWNvZXJjZSBvbiB0aGUgdG9sZXJhbnQgZG9vci4gVGhlIHJlZmVyZW5jZSBTS0lQUyIsCiAgICAidGhlIGVmZmVjdCB3aG9zZSBkZXBzIGlzIGEgYmFyZSBzdHJpbmcgKG5vIHNwdXJpb3VzIEVGRjAwMSkgYW5kIHJlcG9ydHMgdGhlIiwKICAgICJ3ZWxsLWZvcm1lZCBzaWJsaW5nOyB0aGUgUnVzdCB0b2xlcmFudCBlbnRyeSBpcyB0aGUgdHlwZWQgY29uc3RydWN0b3IsIHdoaWNoIiwKICAgICJyZWZ1c2VzIHRoZSBkb2N1bWVudCBiZWZvcmUgdGhlIGJyaWRnZSdzIHNraXAgcnVsZSBjYW4gcnVuLiIKICBdLAogICJlZmZlY3RzIjogWwogICAgewogICAgICAiY29tcG9uZW50IjogIlgiLAogICAgICAiZmlsZSI6ICJYLnRzeCIsCiAgICAgICJsaW5lIjogMSwKICAgICAgImlvIjogdHJ1ZSwKICAgICAgImRlcHMiOiAiYSIsCiAgICAgICJiaW5kaW5ncyI6IFsKICAgICAgICB7CiAgICAgICAgICAibmFtZSI6ICJhIiwKICAgICAgICAgICJpbml0IjogIm9iamVjdCIsCiAgICAgICAgICAicmVmcyI6IFtdLAogICAgICAgICAgImxpbmUiOiAxCiAgICAgICAgfQogICAgICBdCiAgICB9LAogICAgewogICAgICAiY29tcG9uZW50IjogIk9rIiwKICAgICAgImZpbGUiOiAiT2sudHN4IiwKICAgICAgImxpbmUiOiA5LAogICAgICAiaW8iOiB0cnVlLAogICAgICAiZGVwcyI6IFsKICAgICAgICAibyIKICAgICAgXSwKICAgICAgImJpbmRpbmdzIjogWwogICAgICAgIHsKICAgICAgICAgICJuYW1lIjogIm8iLAogICAgICAgICAgImluaXQiOiAib2JqZWN0IiwKICAgICAgICAgICJyZWZzIjogW10sCiAgICAgICAgICAibGluZSI6IDgKICAgICAgICB9CiAgICAgIF0KICAgIH0KICBdCn0K" + "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMSwKICAibW9kdWxlIjogIkRvb3IiLAogICJjb21wb25lbnRzIjogW10sCiAgIl9kb2MiOiBbCiAgICAiIzI5NCBPRC0xOiBCUi1EMidzIHNraXAtbm90LWNvZXJjZSBvbiB0aGUgdG9sZXJhbnQgZG9vci4gVGhlIHJlZmVyZW5jZSBTS0lQUyIsCiAgICAidGhlIGVmZmVjdCB3aG9zZSBkZXBzIGlzIGEgYmFyZSBzdHJpbmcgKG5vIHNwdXJpb3VzIEVGRjAwMSkgYW5kIHJlcG9ydHMgdGhlIiwKICAgICJ3ZWxsLWZvcm1lZCBzaWJsaW5nOyB0aGUgUnVzdCB0b2xlcmFudCBlbnRyeSBpcyB0aGUgdHlwZWQgY29uc3RydWN0b3IsIHdoaWNoIiwKICAgICJyZWZ1c2VzIHRoZSBkb2N1bWVudCBiZWZvcmUgdGhlIGJyaWRnZSdzIHNraXAgcnVsZSBjYW4gcnVuLiIKICBdLAogICJlZmZlY3RzIjogWwogICAgewogICAgICAiY29tcG9uZW50IjogIlgiLAogICAgICAiZmlsZSI6ICJYLnRzeCIsCiAgICAgICJsaW5lIjogMSwKICAgICAgImlvIjogdHJ1ZSwKICAgICAgImRlcHMiOiAiYSIsCiAgICAgICJiaW5kaW5ncyI6IFsKICAgICAgICB7CiAgICAgICAgICAibmFtZSI6ICJhIiwKICAgICAgICAgICJpbml0IjogIm9iamVjdCIsCiAgICAgICAgICAicmVmcyI6IFtdLAogICAgICAgICAgImxpbmUiOiAxCiAgICAgICAgfQogICAgICBdCiAgICB9LAogICAgewogICAgICAiY29tcG9uZW50IjogIk9rIiwKICAgICAgImZpbGUiOiAiT2sudHN4IiwKICAgICAgImxpbmUiOiA5LAogICAgICAiaW8iOiB0cnVlLAogICAgICAiZGVwcyI6IFsKICAgICAgICAibyIKICAgICAgXSwKICAgICAgImJpbmRpbmdzIjogWwogICAgICAgIHsKICAgICAgICAgICJuYW1lIjogIm8iLAogICAgICAgICAgImluaXQiOiAib2JqZWN0IiwKICAgICAgICAgICJyZWZzIjogW10sCiAgICAgICAgICAibGluZSI6IDgKICAgICAgICB9CiAgICAgIF0KICAgIH0KICBdCn0K" }, "canonical": { "algorithm": "sha256", - "digest": "9ac5b570e4a2956f2d771aa0cc5de5e1a7584683d0feefe453df6da4d5007c7b", + "digest": "b85df11e6d8bd400d38b209009a3517bce2bce543e65fd2faac863dcfd057cf1", "bytes": 622 }, "document": { - "ownir_version": 0, + "ownir_version": 1, "module": "Door", "components": [], "_doc": [ @@ -64,19 +64,19 @@ "id": "python-ownlang", "consumed": { "algorithm": "sha256", - "digest": "1709103f7676c80ef52d6d0ad42ce4040842a61f6b63f55a5b133620e778b069", + "digest": "c28447881206b741a6c80335c945308cbbf16b8eb7a44e6490a44e1c17a9ab05", "bytes": 948 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "Door", "resources": [ { @@ -180,7 +180,7 @@ "document": { "degraded": null, "module": "Door", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -232,7 +232,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "2d8c03c893da95c8f84ac51786a70f37c10cefb5fa060ca9acf513638f0b1a27", + "digest": "77b36d9af18fb0d999b5c37a36ea82da135413dddb3f4a1ae9cda738736e46fc", "bytes": 1299 } } @@ -242,7 +242,7 @@ "id": "rust-own-bridge", "consumed": { "algorithm": "sha256", - "digest": "1709103f7676c80ef52d6d0ad42ce4040842a61f6b63f55a5b133620e778b069", + "digest": "c28447881206b741a6c80335c945308cbbf16b8eb7a44e6490a44e1c17a9ab05", "bytes": 948 }, "layers": [ diff --git a/tests/fixtures/repro/verdict_door_effect_deps_not_strings.trace.json b/tests/fixtures/repro/verdict_door_effect_deps_not_strings.trace.json index 1b843568..060b9146 100644 --- a/tests/fixtures/repro/verdict_door_effect_deps_not_strings.trace.json +++ b/tests/fixtures/repro/verdict_door_effect_deps_not_strings.trace.json @@ -7,7 +7,7 @@ "engine": "python-ownlang", "input": { "algorithm": "sha256", - "digest": "9ac5b570e4a2956f2d771aa0cc5de5e1a7584683d0feefe453df6da4d5007c7b", + "digest": "b85df11e6d8bd400d38b209009a3517bce2bce543e65fd2faac863dcfd057cf1", "bytes": 622 }, "layers": [ @@ -21,7 +21,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -147,7 +147,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", @@ -206,7 +206,7 @@ "engine": "rust-own-bridge", "input": { "algorithm": "sha256", - "digest": "9ac5b570e4a2956f2d771aa0cc5de5e1a7584683d0feefe453df6da4d5007c7b", + "digest": "b85df11e6d8bd400d38b209009a3517bce2bce543e65fd2faac863dcfd057cf1", "bytes": 622 }, "layers": [ diff --git a/tests/fixtures/repro/verdict_door_service_unknown_lifetime.repro.json b/tests/fixtures/repro/verdict_door_service_unknown_lifetime.repro.json index 1b688f3a..0d4f951f 100644 --- a/tests/fixtures/repro/verdict_door_service_unknown_lifetime.repro.json +++ b/tests/fixtures/repro/verdict_door_service_unknown_lifetime.repro.json @@ -1,20 +1,20 @@ { "repro_version": 3, "input": { - "ownir_version": 0, + "ownir_version": 1, "raw": { "algorithm": "sha256", - "digest": "264d8b7e5005c0fae9988871dc82e2c366dec9059c2e6532d9f15044684fd095", + "digest": "a354246b1cf569608b3741390343cca8b9fab03471af9a176ca026a6b8359b0e", "bytes": 759, - "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMCwKICAibW9kdWxlIjogIkRvb3IiLAogICJjb21wb25lbnRzIjogW10sCiAgIl9kb2MiOiBbCiAgICAiIzI5NCBPRC0xOiBhbiB1bmtub3duIERJIGxpZmV0aW1lIGlzIElHTk9SRUQgYnkgdGhlIHJlZmVyZW5jZSBmaW5kZXJzIG9uIHRoZSIsCiAgICAidG9sZXJhbnQgZG9vciAoTXlzdGVyeSBpcyBuZWl0aGVyIHNjb3BlZCBub3IgdHJhbnNpZW50LCBzbyBBcHAgLT4gRGIgaXMgdGhlIiwKICAgICJvbmx5IERJMDAxKTsgdGhlIHR5cGVkIFJ1c3QgZG9vciByZWZ1c2VzIHRoZSBkb2N1bWVudCBhdCB0aGUgbGlmZXRpbWUgZW51bS4iCiAgXSwKICAic2VydmljZXMiOiBbCiAgICB7CiAgICAgICJuYW1lIjogIkFwcCIsCiAgICAgICJsaWZldGltZSI6ICJzaW5nbGV0b24iLAogICAgICAiZmlsZSI6ICJyZWcuY3MiLAogICAgICAibGluZSI6IDUsCiAgICAgICJkZXBzIjogWwogICAgICAgICJNeXN0ZXJ5IiwKICAgICAgICAiRGIiCiAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICJuYW1lIjogIk15c3RlcnkiLAogICAgICAibGlmZXRpbWUiOiAicHJvdG90eXBlIiwKICAgICAgImZpbGUiOiAicmVnLmNzIiwKICAgICAgImxpbmUiOiA2LAogICAgICAiZGVwcyI6IFtdCiAgICB9LAogICAgewogICAgICAibmFtZSI6ICJEYiIsCiAgICAgICJsaWZldGltZSI6ICJzY29wZWQiLAogICAgICAiZmlsZSI6ICJyZWcuY3MiLAogICAgICAibGluZSI6IDcsCiAgICAgICJkZXBzIjogW10KICAgIH0KICBdCn0K" + "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMSwKICAibW9kdWxlIjogIkRvb3IiLAogICJjb21wb25lbnRzIjogW10sCiAgIl9kb2MiOiBbCiAgICAiIzI5NCBPRC0xOiBhbiB1bmtub3duIERJIGxpZmV0aW1lIGlzIElHTk9SRUQgYnkgdGhlIHJlZmVyZW5jZSBmaW5kZXJzIG9uIHRoZSIsCiAgICAidG9sZXJhbnQgZG9vciAoTXlzdGVyeSBpcyBuZWl0aGVyIHNjb3BlZCBub3IgdHJhbnNpZW50LCBzbyBBcHAgLT4gRGIgaXMgdGhlIiwKICAgICJvbmx5IERJMDAxKTsgdGhlIHR5cGVkIFJ1c3QgZG9vciByZWZ1c2VzIHRoZSBkb2N1bWVudCBhdCB0aGUgbGlmZXRpbWUgZW51bS4iCiAgXSwKICAic2VydmljZXMiOiBbCiAgICB7CiAgICAgICJuYW1lIjogIkFwcCIsCiAgICAgICJsaWZldGltZSI6ICJzaW5nbGV0b24iLAogICAgICAiZmlsZSI6ICJyZWcuY3MiLAogICAgICAibGluZSI6IDUsCiAgICAgICJkZXBzIjogWwogICAgICAgICJNeXN0ZXJ5IiwKICAgICAgICAiRGIiCiAgICAgIF0KICAgIH0sCiAgICB7CiAgICAgICJuYW1lIjogIk15c3RlcnkiLAogICAgICAibGlmZXRpbWUiOiAicHJvdG90eXBlIiwKICAgICAgImZpbGUiOiAicmVnLmNzIiwKICAgICAgImxpbmUiOiA2LAogICAgICAiZGVwcyI6IFtdCiAgICB9LAogICAgewogICAgICAibmFtZSI6ICJEYiIsCiAgICAgICJsaWZldGltZSI6ICJzY29wZWQiLAogICAgICAiZmlsZSI6ICJyZWcuY3MiLAogICAgICAibGluZSI6IDcsCiAgICAgICJkZXBzIjogW10KICAgIH0KICBdCn0K" }, "canonical": { "algorithm": "sha256", - "digest": "f812c4f014338788c67b3e3f29f035d074d84714f048b0ff8b696b57432a3752", + "digest": "e7820a76b22a9c562e7533d3f429ee16535c85bef592209d4466dcfa9d83f613", "bytes": 541 }, "document": { - "ownir_version": 0, + "ownir_version": 1, "module": "Door", "components": [], "_doc": [ @@ -55,19 +55,19 @@ "id": "python-ownlang", "consumed": { "algorithm": "sha256", - "digest": "264d8b7e5005c0fae9988871dc82e2c366dec9059c2e6532d9f15044684fd095", + "digest": "a354246b1cf569608b3741390343cca8b9fab03471af9a176ca026a6b8359b0e", "bytes": 759 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, "status": "produced", "document": { - "lowered_version": 1, + "lowered_version": 2, "module": "Door", "resources": [ { @@ -171,7 +171,7 @@ "document": { "degraded": null, "module": "Door", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } @@ -223,7 +223,7 @@ "status": "produced", "canonical": { "algorithm": "sha256", - "digest": "b129618f92150bfc7c3215303bb8506421fcebd05d43c309cde72b0c48ce9799", + "digest": "6a55b516f689e0269a5e32b5c418e91e9c365aaefd913769af9fc636fb92d600", "bytes": 1078 } } @@ -233,7 +233,7 @@ "id": "rust-own-bridge", "consumed": { "algorithm": "sha256", - "digest": "264d8b7e5005c0fae9988871dc82e2c366dec9059c2e6532d9f15044684fd095", + "digest": "a354246b1cf569608b3741390343cca8b9fab03471af9a176ca026a6b8359b0e", "bytes": 759 }, "layers": [ diff --git a/tests/fixtures/repro/verdict_door_service_unknown_lifetime.trace.json b/tests/fixtures/repro/verdict_door_service_unknown_lifetime.trace.json index 4b312ab6..444043f3 100644 --- a/tests/fixtures/repro/verdict_door_service_unknown_lifetime.trace.json +++ b/tests/fixtures/repro/verdict_door_service_unknown_lifetime.trace.json @@ -7,7 +7,7 @@ "engine": "python-ownlang", "input": { "algorithm": "sha256", - "digest": "f812c4f014338788c67b3e3f29f035d074d84714f048b0ff8b696b57432a3752", + "digest": "e7820a76b22a9c562e7533d3f429ee16535c85bef592209d4466dcfa9d83f613", "bytes": 541 }, "layers": [ @@ -21,7 +21,7 @@ "steps": [ { "id": "lowered_version", - "value": 1 + "value": 2 }, { "id": "module", @@ -147,7 +147,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", @@ -206,7 +206,7 @@ "engine": "rust-own-bridge", "input": { "algorithm": "sha256", - "digest": "f812c4f014338788c67b3e3f29f035d074d84714f048b0ff8b696b57432a3752", + "digest": "e7820a76b22a9c562e7533d3f429ee16535c85bef592209d4466dcfa9d83f613", "bytes": 541 }, "layers": [ diff --git a/tests/fixtures/repro/vocab_unknown_op.repro.json b/tests/fixtures/repro/vocab_unknown_op.repro.json index ad1aebc7..8cd2c045 100644 --- a/tests/fixtures/repro/vocab_unknown_op.repro.json +++ b/tests/fixtures/repro/vocab_unknown_op.repro.json @@ -1,20 +1,20 @@ { "repro_version": 3, "input": { - "ownir_version": 0, + "ownir_version": 1, "raw": { "algorithm": "sha256", - "digest": "cdf50bec31cb870daa324b5ee37db4ad504aa499eaa7bafbe8c3c35a5a48eede", + "digest": "91e2d42aad1ded1dc0ae052a2dd3b66ab098761709514dd7f7711408015f759d", "bytes": 208, - "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMCwKICAibW9kdWxlIjogIlZvY2FiIiwKICAiZnVuY3Rpb25zIjogWwogICAgewogICAgICAibmFtZSI6ICJNIiwKICAgICAgImZpbGUiOiAiRi5jcyIsCiAgICAgICJib2R5IjogWwogICAgICAgIHsKICAgICAgICAgICJvcCI6ICJ0cnkiLAogICAgICAgICAgImxpbmUiOiAyCiAgICAgICAgfQogICAgICBdCiAgICB9CiAgXQp9Cg==" + "base64": "ewogICJvd25pcl92ZXJzaW9uIjogMSwKICAibW9kdWxlIjogIlZvY2FiIiwKICAiZnVuY3Rpb25zIjogWwogICAgewogICAgICAibmFtZSI6ICJNIiwKICAgICAgImZpbGUiOiAiRi5jcyIsCiAgICAgICJib2R5IjogWwogICAgICAgIHsKICAgICAgICAgICJvcCI6ICJ0cnkiLAogICAgICAgICAgImxpbmUiOiAyCiAgICAgICAgfQogICAgICBdCiAgICB9CiAgXQp9Cg==" }, "canonical": { "algorithm": "sha256", - "digest": "c07494fb952154bcb0f026969754a20bf856c5c12b54a1c9b2aca0468315838d", + "digest": "866a9d0b4bf4898bbcb2a52b9522201efea52c0a0ff7a75ee2963ad4c88851a9", "bytes": 108 }, "document": { - "ownir_version": 0, + "ownir_version": 1, "module": "Vocab", "functions": [ { @@ -35,13 +35,13 @@ "id": "python-ownlang", "consumed": { "algorithm": "sha256", - "digest": "cdf50bec31cb870daa324b5ee37db4ad504aa499eaa7bafbe8c3c35a5a48eede", + "digest": "91e2d42aad1ded1dc0ae052a2dd3b66ab098761709514dd7f7711408015f759d", "bytes": 208 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, @@ -58,7 +58,7 @@ "document": { "degraded": null, "module": "Vocab", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", @@ -96,13 +96,13 @@ "id": "rust-own-bridge", "consumed": { "algorithm": "sha256", - "digest": "cdf50bec31cb870daa324b5ee37db4ad504aa499eaa7bafbe8c3c35a5a48eede", + "digest": "91e2d42aad1ded1dc0ae052a2dd3b66ab098761709514dd7f7711408015f759d", "bytes": 208 }, "layers": [ { "layer": "lowered", - "surface_version": 1, + "surface_version": 2, "projection": { "kind": "full" }, @@ -119,7 +119,7 @@ "document": { "degraded": null, "module": "Vocab", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/repro/vocab_unknown_op.trace.json b/tests/fixtures/repro/vocab_unknown_op.trace.json index d3fe88f1..105344a1 100644 --- a/tests/fixtures/repro/vocab_unknown_op.trace.json +++ b/tests/fixtures/repro/vocab_unknown_op.trace.json @@ -7,7 +7,7 @@ "engine": "python-ownlang", "input": { "algorithm": "sha256", - "digest": "c07494fb952154bcb0f026969754a20bf856c5c12b54a1c9b2aca0468315838d", + "digest": "866a9d0b4bf4898bbcb2a52b9522201efea52c0a0ff7a75ee2963ad4c88851a9", "bytes": 108 }, "layers": [ @@ -36,7 +36,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", @@ -75,7 +75,7 @@ "engine": "rust-own-bridge", "input": { "algorithm": "sha256", - "digest": "c07494fb952154bcb0f026969754a20bf856c5c12b54a1c9b2aca0468315838d", + "digest": "866a9d0b4bf4898bbcb2a52b9522201efea52c0a0ff7a75ee2963ad4c88851a9", "bytes": 108 }, "layers": [ @@ -104,7 +104,7 @@ }, { "id": "ownir_version", - "value": 0 + "value": 1 }, { "id": "degraded", diff --git a/tests/fixtures/summaries/alias_join_cases.summaries.json b/tests/fixtures/summaries/alias_join_cases.summaries.json index eda3733e..b7bd6861 100644 --- a/tests/fixtures/summaries/alias_join_cases.summaries.json +++ b/tests/fixtures/summaries/alias_join_cases.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Alias", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/flow_kill_on_rebind.summaries.json b/tests/fixtures/summaries/flow_kill_on_rebind.summaries.json index da03ea93..bd6304b4 100644 --- a/tests/fixtures/summaries/flow_kill_on_rebind.summaries.json +++ b/tests/fixtures/summaries/flow_kill_on_rebind.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Rebind", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/flow_unmapped_refs.summaries.json b/tests/fixtures/summaries/flow_unmapped_refs.summaries.json index 9f741fa7..6372f1c7 100644 --- a/tests/fixtures/summaries/flow_unmapped_refs.summaries.json +++ b/tests/fixtures/summaries/flow_unmapped_refs.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Unmapped", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/fn_params_ordering.summaries.json b/tests/fixtures/summaries/fn_params_ordering.summaries.json index 7aae7b6d..faea3751 100644 --- a/tests/fixtures/summaries/fn_params_ordering.summaries.json +++ b/tests/fixtures/summaries/fn_params_ordering.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Params", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/handles_global_counters.summaries.json b/tests/fixtures/summaries/handles_global_counters.summaries.json index 2b544d52..ddf15b9e 100644 --- a/tests/fixtures/summaries/handles_global_counters.summaries.json +++ b/tests/fixtures/summaries/handles_global_counters.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Counters", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } diff --git a/tests/fixtures/summaries/handles_null_metadata.summaries.json b/tests/fixtures/summaries/handles_null_metadata.summaries.json index 87650e56..d5f8e43d 100644 --- a/tests/fixtures/summaries/handles_null_metadata.summaries.json +++ b/tests/fixtures/summaries/handles_null_metadata.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "NullMeta", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } diff --git a/tests/fixtures/summaries/hoist_neg_early_return.summaries.json b/tests/fixtures/summaries/hoist_neg_early_return.summaries.json index 0317f80e..7f6d31ca 100644 --- a/tests/fixtures/summaries/hoist_neg_early_return.summaries.json +++ b/tests/fixtures/summaries/hoist_neg_early_return.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "HoistNeg3", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/hoist_neg_nested_depth.summaries.json b/tests/fixtures/summaries/hoist_neg_nested_depth.summaries.json index 451932a3..2516c762 100644 --- a/tests/fixtures/summaries/hoist_neg_nested_depth.summaries.json +++ b/tests/fixtures/summaries/hoist_neg_nested_depth.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "HoistNeg1", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/hoist_neg_while_body.summaries.json b/tests/fixtures/summaries/hoist_neg_while_body.summaries.json index 4c91de72..e797ab77 100644 --- a/tests/fixtures/summaries/hoist_neg_while_body.summaries.json +++ b/tests/fixtures/summaries/hoist_neg_while_body.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "HoistNeg2", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/hoist_pool_kind.summaries.json b/tests/fixtures/summaries/hoist_pool_kind.summaries.json index 20699714..5416327d 100644 --- a/tests/fixtures/summaries/hoist_pool_kind.summaries.json +++ b/tests/fixtures/summaries/hoist_pool_kind.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "HoistPool", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/hoist_positive_release.summaries.json b/tests/fixtures/summaries/hoist_positive_release.summaries.json index afb77def..b7dff134 100644 --- a/tests/fixtures/summaries/hoist_positive_release.summaries.json +++ b/tests/fixtures/summaries/hoist_positive_release.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Hoist", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/hoist_positive_use_only.summaries.json b/tests/fixtures/summaries/hoist_positive_use_only.summaries.json index 0a6f8c13..901d7d88 100644 --- a/tests/fixtures/summaries/hoist_positive_use_only.summaries.json +++ b/tests/fixtures/summaries/hoist_positive_use_only.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "HoistUse", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/lines_preserved.summaries.json b/tests/fixtures/summaries/lines_preserved.summaries.json index 43141d2a..010bf551 100644 --- a/tests/fixtures/summaries/lines_preserved.summaries.json +++ b/tests/fixtures/summaries/lines_preserved.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Lines", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/manifest.json b/tests/fixtures/summaries/manifest.json index b501515a..bcf13a4e 100644 --- a/tests/fixtures/summaries/manifest.json +++ b/tests/fixtures/summaries/manifest.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "excluded_lowered": [ { "name": "tolerant_unknown_kind", diff --git a/tests/fixtures/summaries/mos_call_channel_overload_sig.summaries.json b/tests/fixtures/summaries/mos_call_channel_overload_sig.summaries.json index 33999609..244d88e2 100644 --- a/tests/fixtures/summaries/mos_call_channel_overload_sig.summaries.json +++ b/tests/fixtures/summaries/mos_call_channel_overload_sig.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Overloads", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/mos_call_direct_consume.summaries.json b/tests/fixtures/summaries/mos_call_direct_consume.summaries.json index 70ccc5e7..5c8e83f6 100644 --- a/tests/fixtures/summaries/mos_call_direct_consume.summaries.json +++ b/tests/fixtures/summaries/mos_call_direct_consume.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Direct", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/mos_call_unknown_drop.summaries.json b/tests/fixtures/summaries/mos_call_unknown_drop.summaries.json index 7641318e..ad06c667 100644 --- a/tests/fixtures/summaries/mos_call_unknown_drop.summaries.json +++ b/tests/fixtures/summaries/mos_call_unknown_drop.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Drop", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/mos_fresh_mint.summaries.json b/tests/fixtures/summaries/mos_fresh_mint.summaries.json index 901bce6e..4c4022b5 100644 --- a/tests/fixtures/summaries/mos_fresh_mint.summaries.json +++ b/tests/fixtures/summaries/mos_fresh_mint.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Fresh", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/mos_killsite_toplevel.summaries.json b/tests/fixtures/summaries/mos_killsite_toplevel.summaries.json index 8fb5b39c..95e48b59 100644 --- a/tests/fixtures/summaries/mos_killsite_toplevel.summaries.json +++ b/tests/fixtures/summaries/mos_killsite_toplevel.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "KillSite", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/mos_untrack_inbranch.summaries.json b/tests/fixtures/summaries/mos_untrack_inbranch.summaries.json index b48ee3f9..5a470b55 100644 --- a/tests/fixtures/summaries/mos_untrack_inbranch.summaries.json +++ b/tests/fixtures/summaries/mos_untrack_inbranch.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Untrack", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/summaries/mosdump_degraded_duplicate_key.facts.json b/tests/fixtures/summaries/mosdump_degraded_duplicate_key.facts.json index 341995c0..ec928b44 100644 --- a/tests/fixtures/summaries/mosdump_degraded_duplicate_key.facts.json +++ b/tests/fixtures/summaries/mosdump_degraded_duplicate_key.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Degraded", "functions": [ { diff --git a/tests/fixtures/summaries/mosdump_degraded_duplicate_key.summaries.json b/tests/fixtures/summaries/mosdump_degraded_duplicate_key.summaries.json index 9e783bcc..338c50fa 100644 --- a/tests/fixtures/summaries/mosdump_degraded_duplicate_key.summaries.json +++ b/tests/fixtures/summaries/mosdump_degraded_duplicate_key.summaries.json @@ -1,7 +1,7 @@ { "degraded": "ValueError: duplicate MethodSkeleton key: Take(System.IO.Stream)", "module": "Degraded", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } diff --git a/tests/fixtures/summaries/mosdump_explicit_effects.facts.json b/tests/fixtures/summaries/mosdump_explicit_effects.facts.json index e0801598..19f8d8e0 100644 --- a/tests/fixtures/summaries/mosdump_explicit_effects.facts.json +++ b/tests/fixtures/summaries/mosdump_explicit_effects.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Effects", "functions": [ { diff --git a/tests/fixtures/summaries/mosdump_explicit_effects.summaries.json b/tests/fixtures/summaries/mosdump_explicit_effects.summaries.json index 159a7fe9..780acf19 100644 --- a/tests/fixtures/summaries/mosdump_explicit_effects.summaries.json +++ b/tests/fixtures/summaries/mosdump_explicit_effects.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Effects", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "ef.cs", diff --git a/tests/fixtures/summaries/mosdump_nonascii_escaping.facts.json b/tests/fixtures/summaries/mosdump_nonascii_escaping.facts.json index 848b9b08..d36243b5 100644 --- a/tests/fixtures/summaries/mosdump_nonascii_escaping.facts.json +++ b/tests/fixtures/summaries/mosdump_nonascii_escaping.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Юникод—М😀", "functions": [ { diff --git a/tests/fixtures/summaries/mosdump_nonascii_escaping.summaries.json b/tests/fixtures/summaries/mosdump_nonascii_escaping.summaries.json index 2e68de6a..5a21503b 100644 --- a/tests/fixtures/summaries/mosdump_nonascii_escaping.summaries.json +++ b/tests/fixtures/summaries/mosdump_nonascii_escaping.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "\u042e\u043d\u0438\u043a\u043e\u0434\u2014\u041c\ud83d\ude00", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "\u0444\u0430\u0439\u043b\ud83d\ude00.cs", diff --git a/tests/fixtures/summaries/mosdump_overload_merge_tiebreaks.facts.json b/tests/fixtures/summaries/mosdump_overload_merge_tiebreaks.facts.json index f76f3169..06ef382a 100644 --- a/tests/fixtures/summaries/mosdump_overload_merge_tiebreaks.facts.json +++ b/tests/fixtures/summaries/mosdump_overload_merge_tiebreaks.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "MergeTie", "functions": [ { diff --git a/tests/fixtures/summaries/mosdump_overload_merge_tiebreaks.summaries.json b/tests/fixtures/summaries/mosdump_overload_merge_tiebreaks.summaries.json index e540bba6..eb8c2f13 100644 --- a/tests/fixtures/summaries/mosdump_overload_merge_tiebreaks.summaries.json +++ b/tests/fixtures/summaries/mosdump_overload_merge_tiebreaks.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "MergeTie", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "a.cs", diff --git a/tests/fixtures/summaries/mosdump_partial_and_guarded.facts.json b/tests/fixtures/summaries/mosdump_partial_and_guarded.facts.json index ae488676..01f01310 100644 --- a/tests/fixtures/summaries/mosdump_partial_and_guarded.facts.json +++ b/tests/fixtures/summaries/mosdump_partial_and_guarded.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Guarded", "functions": [ { diff --git a/tests/fixtures/summaries/mosdump_partial_and_guarded.summaries.json b/tests/fixtures/summaries/mosdump_partial_and_guarded.summaries.json index ef87eff4..679a66c8 100644 --- a/tests/fixtures/summaries/mosdump_partial_and_guarded.summaries.json +++ b/tests/fixtures/summaries/mosdump_partial_and_guarded.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Guarded", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "pg.cs", diff --git a/tests/fixtures/summaries/mosdump_return_chains.facts.json b/tests/fixtures/summaries/mosdump_return_chains.facts.json index b9d4304a..44d7b143 100644 --- a/tests/fixtures/summaries/mosdump_return_chains.facts.json +++ b/tests/fixtures/summaries/mosdump_return_chains.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "ReturnChains", "functions": [ { diff --git a/tests/fixtures/summaries/mosdump_return_chains.summaries.json b/tests/fixtures/summaries/mosdump_return_chains.summaries.json index 9f026dfa..254f649d 100644 --- a/tests/fixtures/summaries/mosdump_return_chains.summaries.json +++ b/tests/fixtures/summaries/mosdump_return_chains.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "ReturnChains", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "cyc.cs", diff --git a/tests/fixtures/summaries/mosdump_scc_cycles.facts.json b/tests/fixtures/summaries/mosdump_scc_cycles.facts.json index b0ab94e2..65d4fa79 100644 --- a/tests/fixtures/summaries/mosdump_scc_cycles.facts.json +++ b/tests/fixtures/summaries/mosdump_scc_cycles.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "SccCycles", "functions": [ { diff --git a/tests/fixtures/summaries/mosdump_scc_cycles.summaries.json b/tests/fixtures/summaries/mosdump_scc_cycles.summaries.json index d314be74..56341b0c 100644 --- a/tests/fixtures/summaries/mosdump_scc_cycles.summaries.json +++ b/tests/fixtures/summaries/mosdump_scc_cycles.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "SccCycles", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "cy.cs", diff --git a/tests/fixtures/summaries/mosdump_sig_vocabulary.facts.json b/tests/fixtures/summaries/mosdump_sig_vocabulary.facts.json index b8213acf..6290f4af 100644 --- a/tests/fixtures/summaries/mosdump_sig_vocabulary.facts.json +++ b/tests/fixtures/summaries/mosdump_sig_vocabulary.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "SigVocab", "functions": [ { diff --git a/tests/fixtures/summaries/mosdump_sig_vocabulary.summaries.json b/tests/fixtures/summaries/mosdump_sig_vocabulary.summaries.json index 7e1db564..9d76cb7e 100644 --- a/tests/fixtures/summaries/mosdump_sig_vocabulary.summaries.json +++ b/tests/fixtures/summaries/mosdump_sig_vocabulary.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "SigVocab", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "f.cs", diff --git a/tests/fixtures/summaries/mosdump_sink_channels.facts.json b/tests/fixtures/summaries/mosdump_sink_channels.facts.json index cb5cebfe..dca63604 100644 --- a/tests/fixtures/summaries/mosdump_sink_channels.facts.json +++ b/tests/fixtures/summaries/mosdump_sink_channels.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Sinks", "functions": [ { diff --git a/tests/fixtures/summaries/mosdump_sink_channels.summaries.json b/tests/fixtures/summaries/mosdump_sink_channels.summaries.json index 144e0edc..00e2bc77 100644 --- a/tests/fixtures/summaries/mosdump_sink_channels.summaries.json +++ b/tests/fixtures/summaries/mosdump_sink_channels.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Sinks", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "sk.cs", diff --git a/tests/fixtures/summaries/routing_r1_unresolved.summaries.json b/tests/fixtures/summaries/routing_r1_unresolved.summaries.json index 0cd0417f..1fd45b51 100644 --- a/tests/fixtures/summaries/routing_r1_unresolved.summaries.json +++ b/tests/fixtures/summaries/routing_r1_unresolved.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "R1", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } diff --git a/tests/fixtures/summaries/routing_r2_subscribe_self.summaries.json b/tests/fixtures/summaries/routing_r2_subscribe_self.summaries.json index b9f992f0..3c80d2aa 100644 --- a/tests/fixtures/summaries/routing_r2_subscribe_self.summaries.json +++ b/tests/fixtures/summaries/routing_r2_subscribe_self.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "R2", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } diff --git a/tests/fixtures/summaries/routing_r3_capture_static.summaries.json b/tests/fixtures/summaries/routing_r3_capture_static.summaries.json index 0e379113..15436bba 100644 --- a/tests/fixtures/summaries/routing_r3_capture_static.summaries.json +++ b/tests/fixtures/summaries/routing_r3_capture_static.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "R3", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } diff --git a/tests/fixtures/summaries/routing_r4_returned_fresh.summaries.json b/tests/fixtures/summaries/routing_r4_returned_fresh.summaries.json index 25eed67b..a395834e 100644 --- a/tests/fixtures/summaries/routing_r4_returned_fresh.summaries.json +++ b/tests/fixtures/summaries/routing_r4_returned_fresh.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "R4", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } diff --git a/tests/fixtures/summaries/routing_r5_di_capture.summaries.json b/tests/fixtures/summaries/routing_r5_di_capture.summaries.json index f186c178..17194997 100644 --- a/tests/fixtures/summaries/routing_r5_di_capture.summaries.json +++ b/tests/fixtures/summaries/routing_r5_di_capture.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "R5", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } diff --git a/tests/fixtures/summaries/routing_r6_token_kinds.summaries.json b/tests/fixtures/summaries/routing_r6_token_kinds.summaries.json index 27e7f1de..74811789 100644 --- a/tests/fixtures/summaries/routing_r6_token_kinds.summaries.json +++ b/tests/fixtures/summaries/routing_r6_token_kinds.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "R6", - "ownir_version": 0, + "ownir_version": 1, "summaries": [], "unresolved": [] } diff --git a/tests/fixtures/summaries/typestate_cs_a1_alias_of_entity.summaries.json b/tests/fixtures/summaries/typestate_cs_a1_alias_of_entity.summaries.json new file mode 100644 index 00000000..66ecf19d --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_a1_alias_of_entity.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/A1_alias_of_entity.cs", + "line": 0, + "method": "Own.Protocols.Cases.A1AliasOfEntity.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_a2_entity_through_indexer.summaries.json b/tests/fixtures/summaries/typestate_cs_a2_entity_through_indexer.summaries.json new file mode 100644 index 00000000..1ad05239 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_a2_entity_through_indexer.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/A2_entity_through_indexer.cs", + "line": 0, + "method": "Own.Protocols.Cases.A2EntityThroughIndexer.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_g6_capability_not_spent.summaries.json b/tests/fixtures/summaries/typestate_cs_g6_capability_not_spent.summaries.json new file mode 100644 index 00000000..8f95b7e2 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_g6_capability_not_spent.summaries.json @@ -0,0 +1,18 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/G6_capability_not_spent.cs", + "line": 0, + "method": "Own.Protocols.Cases.G6CapabilityNotSpent.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l10_region_inside_try.summaries.json b/tests/fixtures/summaries/typestate_cs_l10_region_inside_try.summaries.json new file mode 100644 index 00000000..d51857e9 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l10_region_inside_try.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L10_region_inside_try.cs", + "line": 0, + "method": "Own.Protocols.Cases.L10RegionInsideTry.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l11_region_beside_disposable.summaries.json b/tests/fixtures/summaries/typestate_cs_l11_region_beside_disposable.summaries.json new file mode 100644 index 00000000..1f17c842 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l11_region_beside_disposable.summaries.json @@ -0,0 +1,51 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L11_region_beside_disposable.cs", + "line": 0, + "method": "Own.Protocols.Cases.L11RegionBesideDisposable.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/cases/L11_region_beside_disposable.cs", + "line": 0, + "method": "Own.Protocols.Cases.L11RegionBesideDisposable.Run$protocol", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l12_region_beside_leaked_disposable.summaries.json b/tests/fixtures/summaries/typestate_cs_l12_region_beside_leaked_disposable.summaries.json new file mode 100644 index 00000000..b609e4a5 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l12_region_beside_leaked_disposable.summaries.json @@ -0,0 +1,51 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs", + "line": 0, + "method": "Own.Protocols.Cases.L12RegionBesideLeakedDisposable.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs", + "line": 0, + "method": "Own.Protocols.Cases.L12RegionBesideLeakedDisposable.Run$protocol", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l13_values_captured_into_region.summaries.json b/tests/fixtures/summaries/typestate_cs_l13_values_captured_into_region.summaries.json new file mode 100644 index 00000000..a27019a2 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l13_values_captured_into_region.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L13_values_captured_into_region.cs", + "line": 0, + "method": "Own.Protocols.Cases.L13ValuesCapturedIntoRegion.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l1_stale_capability.summaries.json b/tests/fixtures/summaries/typestate_cs_l1_stale_capability.summaries.json new file mode 100644 index 00000000..0a18d7b4 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l1_stale_capability.summaries.json @@ -0,0 +1,87 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs", + "line": 0, + "method": "Own.Protocols.Cases.L1StaleCapability.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.DraftOrder.Cancel", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.DraftOrder.Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.SubmittedOrder.Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l2_copied_capability.summaries.json b/tests/fixtures/summaries/typestate_cs_l2_copied_capability.summaries.json new file mode 100644 index 00000000..9a093a97 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l2_copied_capability.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L2_copied_capability.cs", + "line": 0, + "method": "Own.Protocols.Cases.L2CopiedCapability.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.DraftOrder.Cancel", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l3_raw_mutation.summaries.json b/tests/fixtures/summaries/typestate_cs_l3_raw_mutation.summaries.json new file mode 100644 index 00000000..ee502f80 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l3_raw_mutation.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L3_raw_mutation.cs", + "line": 0, + "method": "Own.Protocols.Cases.L3RawMutation.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l4_raw_escape.summaries.json b/tests/fixtures/summaries/typestate_cs_l4_raw_escape.summaries.json new file mode 100644 index 00000000..cf1196e0 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l4_raw_escape.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L4_raw_escape.cs", + "line": 0, + "method": "Own.Protocols.Cases.L4RawEscape.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l5_normal_transition.summaries.json b/tests/fixtures/summaries/typestate_cs_l5_normal_transition.summaries.json new file mode 100644 index 00000000..7284583f --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l5_normal_transition.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L5_normal_transition.cs", + "line": 0, + "method": "Own.Protocols.Cases.L5NormalTransition.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l6_two_transitions.summaries.json b/tests/fixtures/summaries/typestate_cs_l6_two_transitions.summaries.json new file mode 100644 index 00000000..ebc9b1a0 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l6_two_transitions.summaries.json @@ -0,0 +1,64 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L6_two_transitions.cs", + "line": 0, + "method": "Own.Protocols.Cases.L6TwoTransitions.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.DraftOrder.Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.SubmittedOrder.Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l6b_chained_transitions.summaries.json b/tests/fixtures/summaries/typestate_cs_l6b_chained_transitions.summaries.json new file mode 100644 index 00000000..96c78b68 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l6b_chained_transitions.summaries.json @@ -0,0 +1,64 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L6b_chained_transitions.cs", + "line": 0, + "method": "Own.Protocols.Cases.L6bChainedTransitions.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.DraftOrder.Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.SubmittedOrder.Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l7_read_after_region.summaries.json b/tests/fixtures/summaries/typestate_cs_l7_read_after_region.summaries.json new file mode 100644 index 00000000..c30ede9b --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l7_read_after_region.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L7_read_after_region.cs", + "line": 0, + "method": "Own.Protocols.Cases.L7ReadAfterRegion.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l8_branch_inside_region.summaries.json b/tests/fixtures/summaries/typestate_cs_l8_branch_inside_region.summaries.json new file mode 100644 index 00000000..f96918e0 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l8_branch_inside_region.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L8_branch_inside_region.cs", + "line": 0, + "method": "Own.Protocols.Cases.L8BranchInsideRegion.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_l9_opaque_calls_around_region.summaries.json b/tests/fixtures/summaries/typestate_cs_l9_opaque_calls_around_region.summaries.json new file mode 100644 index 00000000..97cebfc4 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_l9_opaque_calls_around_region.summaries.json @@ -0,0 +1,41 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L9_opaque_calls_around_region.cs", + "line": 0, + "method": "Own.Protocols.Cases.L9OpaqueCallsAroundRegion.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_cs_x1_nested_region_same_entity.summaries.json b/tests/fixtures/summaries/typestate_cs_x1_nested_region_same_entity.summaries.json new file mode 100644 index 00000000..dccd8a12 --- /dev/null +++ b/tests/fixtures/summaries/typestate_cs_x1_nested_region_same_entity.summaries.json @@ -0,0 +1,64 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/cases/X1_nested_region_same_entity.cs", + "line": 0, + "method": "Own.Protocols.Cases.X1NestedRegionSameEntity.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/Api/ProtocolApi.cs", + "line": 0, + "method": "Own.Protocols.Sample.DraftOrder.Cancel", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_ef_orderbackend.summaries.json b/tests/fixtures/summaries/typestate_ef_orderbackend.summaries.json new file mode 100644 index 00000000..62c162bf --- /dev/null +++ b/tests/fixtures/summaries/typestate_ef_orderbackend.summaries.json @@ -0,0 +1,165 @@ +{ + "degraded": null, + "module": "Extracted", + "ownir_version": 1, + "summaries": [ + { + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "line": 0, + "method": "OrderBackend.Domain.ApprovedOrder.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "line": 0, + "method": "OrderBackend.Domain.DraftOrder.Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/Domain/OrderProtocol.cs", + "line": 0, + "method": "OrderBackend.Domain.SubmittedOrder.Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "token", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "entity", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 0, + "method": "OrderBackend.OrderHandlers.Create", + "params": [ + { + "disposable": true, + "index": 0, + "name": "db", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 0, + "method": "OrderBackend.OrderHandlers.Get", + "params": [ + { + "disposable": true, + "index": 0, + "name": "db", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 0, + "method": "OrderBackend.OrderHandlers.Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "db", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 0, + "method": "OrderBackend.OrderHandlers.Ship$protocol", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 0, + "method": "OrderBackend.OrderHandlers.SubmitAndApprove", + "params": [ + { + "disposable": true, + "index": 0, + "name": "db", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "frontend/roslyn/protocol-samples/efcore/OrderBackend/OrderHandlers.cs", + "line": 0, + "method": "OrderBackend.OrderHandlers.SubmitAndApprove$protocol", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_g6_capability_not_spent.summaries.json b/tests/fixtures/summaries/typestate_g6_capability_not_spent.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_g6_capability_not_spent.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l1_stale_capability.summaries.json b/tests/fixtures/summaries/typestate_l1_stale_capability.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l1_stale_capability.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l2_copied_capability.summaries.json b/tests/fixtures/summaries/typestate_l2_copied_capability.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l2_copied_capability.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l3_raw_entity_mutation.summaries.json b/tests/fixtures/summaries/typestate_l3_raw_entity_mutation.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l3_raw_entity_mutation.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l3b_second_region.summaries.json b/tests/fixtures/summaries/typestate_l3b_second_region.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l3b_second_region.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l4_raw_entity_unknown_call.summaries.json b/tests/fixtures/summaries/typestate_l4_raw_entity_unknown_call.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l4_raw_entity_unknown_call.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l4b_raw_entity_shared_call.summaries.json b/tests/fixtures/summaries/typestate_l4b_raw_entity_shared_call.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l4b_raw_entity_shared_call.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l4c_raw_entity_consumed.summaries.json b/tests/fixtures/summaries/typestate_l4c_raw_entity_consumed.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l4c_raw_entity_consumed.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l4d_token_unknown_call.summaries.json b/tests/fixtures/summaries/typestate_l4d_token_unknown_call.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l4d_token_unknown_call.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l5_normal_transition.summaries.json b/tests/fixtures/summaries/typestate_l5_normal_transition.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l5_normal_transition.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l5b_two_transitions.summaries.json b/tests/fixtures/summaries/typestate_l5b_two_transitions.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l5b_two_transitions.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_l5c_read_after_region.summaries.json b/tests/fixtures/summaries/typestate_l5c_read_after_region.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_l5c_read_after_region.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_n1_token_spent_on_other_entity.summaries.json b/tests/fixtures/summaries/typestate_n1_token_spent_on_other_entity.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_n1_token_spent_on_other_entity.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_n2_two_tokens_one_region.summaries.json b/tests/fixtures/summaries/typestate_n2_two_tokens_one_region.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_n2_two_tokens_one_region.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_n3_raw_mutation_inferred_effect.summaries.json b/tests/fixtures/summaries/typestate_n3_raw_mutation_inferred_effect.summaries.json new file mode 100644 index 00000000..2d29cfac --- /dev/null +++ b/tests/fixtures/summaries/typestate_n3_raw_mutation_inferred_effect.summaries.json @@ -0,0 +1,178 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Touch", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_n4_token_outlives_region.summaries.json b/tests/fixtures/summaries/typestate_n4_token_outlives_region.summaries.json new file mode 100644 index 00000000..08d2f970 --- /dev/null +++ b/tests/fixtures/summaries/typestate_n4_token_outlives_region.summaries.json @@ -0,0 +1,161 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Orders.cs", + "line": 0, + "method": "Approve", + "params": [ + { + "disposable": true, + "index": 0, + "name": "s", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelDraft", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "CancelOrder", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Handler.Run", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Ship", + "params": [ + { + "disposable": true, + "index": 0, + "name": "a", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "order", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Orders.cs", + "line": 0, + "method": "Submit", + "params": [ + { + "disposable": true, + "index": 0, + "name": "d", + "transfer": "must" + }, + { + "disposable": true, + "index": 1, + "name": "order", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_w1_loan_wordings.summaries.json b/tests/fixtures/summaries/typestate_w1_loan_wordings.summaries.json new file mode 100644 index 00000000..bc5f4df3 --- /dev/null +++ b/tests/fixtures/summaries/typestate_w1_loan_wordings.summaries.json @@ -0,0 +1,119 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Wordings.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "o", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "Reborrow", + "params": [ + { + "disposable": true, + "index": 0, + "name": "o", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "o", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Consumed", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Moved", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Reborrowed", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Released", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Shared", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Used", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/typestate_w2_loan_wordings_pooled.summaries.json b/tests/fixtures/summaries/typestate_w2_loan_wordings_pooled.summaries.json new file mode 100644 index 00000000..bc5f4df3 --- /dev/null +++ b/tests/fixtures/summaries/typestate_w2_loan_wordings_pooled.summaries.json @@ -0,0 +1,119 @@ +{ + "degraded": null, + "module": "TypestateGate", + "ownir_version": 1, + "summaries": [ + { + "file": "Wordings.cs", + "line": 0, + "method": "Peek", + "params": [ + { + "disposable": true, + "index": 0, + "name": "o", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "Reborrow", + "params": [ + { + "disposable": true, + "index": 0, + "name": "o", + "transfer": "no" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "Store", + "params": [ + { + "disposable": true, + "index": 0, + "name": "o", + "transfer": "must" + } + ], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Consumed", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Moved", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Reborrowed", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Released", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Shared", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + }, + { + "file": "Wordings.cs", + "line": 0, + "method": "W.Used", + "params": [], + "returns": { + "owned": "none" + }, + "source": "inferred" + } + ], + "unresolved": [] +} diff --git a/tests/fixtures/summaries/vocab_unknown_op.summaries.json b/tests/fixtures/summaries/vocab_unknown_op.summaries.json index 20400fcc..4394ccd5 100644 --- a/tests/fixtures/summaries/vocab_unknown_op.summaries.json +++ b/tests/fixtures/summaries/vocab_unknown_op.summaries.json @@ -1,7 +1,7 @@ { "degraded": null, "module": "Vocab", - "ownir_version": 0, + "ownir_version": 1, "summaries": [ { "file": "F.cs", diff --git a/tests/fixtures/verdict_renders/render_anchorless.facts.json b/tests/fixtures/verdict_renders/render_anchorless.facts.json index 8b0367ed..18d56b29 100644 --- a/tests/fixtures/verdict_renders/render_anchorless.facts.json +++ b/tests/fixtures/verdict_renders/render_anchorless.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Anchorless", "_doc": [ "OWN052 is anchorless by nature (file '?', line 0), so its SARIF location", diff --git a/tests/fixtures/verdict_renders/render_anchorless.renders.json b/tests/fixtures/verdict_renders/render_anchorless.renders.json index c5f938bf..107cd829 100644 --- a/tests/fixtures/verdict_renders/render_anchorless.renders.json +++ b/tests/fixtures/verdict_renders/render_anchorless.renders.json @@ -51,7 +51,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, @@ -98,7 +98,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, diff --git a/tests/fixtures/verdict_renders/render_columns.facts.json b/tests/fixtures/verdict_renders/render_columns.facts.json index 4e43e2ca..f2d8d920 100644 --- a/tests/fixtures/verdict_renders/render_columns.facts.json +++ b/tests/fixtures/verdict_renders/render_columns.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Columns", "_doc": [ "A reported column rides into SARIF as region.startColumn, and only ever", diff --git a/tests/fixtures/verdict_renders/render_columns.renders.json b/tests/fixtures/verdict_renders/render_columns.renders.json index 8dce3f63..2dbd8259 100644 --- a/tests/fixtures/verdict_renders/render_columns.renders.json +++ b/tests/fixtures/verdict_renders/render_columns.renders.json @@ -59,7 +59,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, @@ -137,7 +137,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, diff --git a/tests/fixtures/verdict_renders/render_empty.facts.json b/tests/fixtures/verdict_renders/render_empty.facts.json index 2f926557..d615097a 100644 --- a/tests/fixtures/verdict_renders/render_empty.facts.json +++ b/tests/fixtures/verdict_renders/render_empty.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Empty", "_doc": [ "A clean document: every line-per-finding surface is an empty list and the", diff --git a/tests/fixtures/verdict_renders/render_empty.renders.json b/tests/fixtures/verdict_renders/render_empty.renders.json index 7acbab5a..e188a4c9 100644 --- a/tests/fixtures/verdict_renders/render_empty.renders.json +++ b/tests/fixtures/verdict_renders/render_empty.renders.json @@ -28,7 +28,7 @@ "informationUri": "https://github.com/PhysShell/Own.NET", "rules": [], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, @@ -47,7 +47,7 @@ "informationUri": "https://github.com/PhysShell/Own.NET", "rules": [], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, diff --git a/tests/fixtures/verdict_renders/render_escaping.facts.json b/tests/fixtures/verdict_renders/render_escaping.facts.json index 98ac6d01..eeec9268 100644 --- a/tests/fixtures/verdict_renders/render_escaping.facts.json +++ b/tests/fixtures/verdict_renders/render_escaping.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Escaping", "_doc": [ "Every workflow-command escaping rule in one document. The component file", diff --git a/tests/fixtures/verdict_renders/render_escaping.renders.json b/tests/fixtures/verdict_renders/render_escaping.renders.json index 2c68acae..db52add2 100644 --- a/tests/fixtures/verdict_renders/render_escaping.renders.json +++ b/tests/fixtures/verdict_renders/render_escaping.renders.json @@ -51,7 +51,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, @@ -103,7 +103,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, diff --git a/tests/fixtures/verdict_renders/render_evidence_slices.facts.json b/tests/fixtures/verdict_renders/render_evidence_slices.facts.json index 60ff49ab..be179c81 100644 --- a/tests/fixtures/verdict_renders/render_evidence_slices.facts.json +++ b/tests/fixtures/verdict_renders/render_evidence_slices.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Evidence", "_doc": [ "The two evidence projections: `related` -> relatedLocations and the ordered", diff --git a/tests/fixtures/verdict_renders/render_evidence_slices.renders.json b/tests/fixtures/verdict_renders/render_evidence_slices.renders.json index 2f1b79c2..a246d37d 100644 --- a/tests/fixtures/verdict_renders/render_evidence_slices.renders.json +++ b/tests/fixtures/verdict_renders/render_evidence_slices.renders.json @@ -59,7 +59,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, @@ -244,7 +244,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, diff --git a/tests/fixtures/verdict_renders/render_protocol_family.facts.json b/tests/fixtures/verdict_renders/render_protocol_family.facts.json index e1ec9058..a5b24fb1 100644 --- a/tests/fixtures/verdict_renders/render_protocol_family.facts.json +++ b/tests/fixtures/verdict_renders/render_protocol_family.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Protocols", "_doc": [ "BR-V9 over the OBL family (#259 checkpoint 4b), two surfaces in one", diff --git a/tests/fixtures/verdict_renders/render_protocol_family.renders.json b/tests/fixtures/verdict_renders/render_protocol_family.renders.json index b8544fd0..ced801e2 100644 --- a/tests/fixtures/verdict_renders/render_protocol_family.renders.json +++ b/tests/fixtures/verdict_renders/render_protocol_family.renders.json @@ -87,7 +87,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, @@ -342,7 +342,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, diff --git a/tests/fixtures/verdict_renders/render_refusal.facts.json b/tests/fixtures/verdict_renders/render_refusal.facts.json index 0b3751c0..65d18472 100644 --- a/tests/fixtures/verdict_renders/render_refusal.facts.json +++ b/tests/fixtures/verdict_renders/render_refusal.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Refusal", "_doc": [ "A document the bridge refuses has no findings to render, so the rendered", diff --git a/tests/fixtures/verdict_renders/render_rule_catalogue.facts.json b/tests/fixtures/verdict_renders/render_rule_catalogue.facts.json index e7a64734..1b509668 100644 --- a/tests/fixtures/verdict_renders/render_rule_catalogue.facts.json +++ b/tests/fixtures/verdict_renders/render_rule_catalogue.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Catalogue", "_doc": [ "The SARIF log's TWO orderings, in a document where they disagree. The", diff --git a/tests/fixtures/verdict_renders/render_rule_catalogue.renders.json b/tests/fixtures/verdict_renders/render_rule_catalogue.renders.json index 584e1d69..aaaa1b79 100644 --- a/tests/fixtures/verdict_renders/render_rule_catalogue.renders.json +++ b/tests/fixtures/verdict_renders/render_rule_catalogue.renders.json @@ -73,7 +73,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, @@ -181,7 +181,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, diff --git a/tests/fixtures/verdict_renders/render_tiers_and_levels.facts.json b/tests/fixtures/verdict_renders/render_tiers_and_levels.facts.json index 31ef0c70..ea10fbf1 100644 --- a/tests/fixtures/verdict_renders/render_tiers_and_levels.facts.json +++ b/tests/fixtures/verdict_renders/render_tiers_and_levels.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Tiers", "_doc": [ "One document carrying all three SARIF levels and both suppression states:", diff --git a/tests/fixtures/verdict_renders/render_tiers_and_levels.renders.json b/tests/fixtures/verdict_renders/render_tiers_and_levels.renders.json index 24753c2f..61e5451c 100644 --- a/tests/fixtures/verdict_renders/render_tiers_and_levels.renders.json +++ b/tests/fixtures/verdict_renders/render_tiers_and_levels.renders.json @@ -81,7 +81,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, @@ -220,7 +220,7 @@ } ], "properties": { - "ownirSchemaVersion": 0 + "ownirSchemaVersion": 1 } } }, diff --git a/tests/fixtures/verdicts/typestate_cs_a1_alias_of_entity.verdicts.json b/tests/fixtures/verdicts/typestate_cs_a1_alias_of_entity.verdicts.json new file mode 100644 index 00000000..f200db6e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_a1_alias_of_entity.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "frontend/roslyn/protocol-samples/cases/A1_alias_of_entity.cs", + "line": 15, + "code": "OWN013", + "component": "Own.Protocols.Cases.A1AliasOfEntity.Run", + "event": "order", + "handler": "", + "message": "IDisposable local 'order' is used directly while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_cs_a2_entity_through_indexer.verdicts.json b/tests/fixtures/verdicts/typestate_cs_a2_entity_through_indexer.verdicts.json new file mode 100644 index 00000000..9d29c4d2 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_a2_entity_through_indexer.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "frontend/roslyn/protocol-samples/cases/A2_entity_through_indexer.cs", + "line": 15, + "code": "OWN013", + "component": "Own.Protocols.Cases.A2EntityThroughIndexer.Run", + "event": "order", + "handler": "", + "message": "IDisposable local 'order' is used directly while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_cs_g6_capability_not_spent.verdicts.json b/tests/fixtures/verdicts/typestate_cs_g6_capability_not_spent.verdicts.json new file mode 100644 index 00000000..4dfc0355 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_g6_capability_not_spent.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "frontend/roslyn/protocol-samples/cases/G6_capability_not_spent.cs", + "line": 13, + "code": "OWN001", + "component": "Own.Protocols.Cases.G6CapabilityNotSpent.Run", + "event": "approved", + "handler": "", + "message": "IDisposable local 'approved' is never disposed (leak)", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l10_region_inside_try.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l10_region_inside_try.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l10_region_inside_try.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l11_region_beside_disposable.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l11_region_beside_disposable.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l11_region_beside_disposable.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l12_region_beside_leaked_disposable.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l12_region_beside_leaked_disposable.verdicts.json new file mode 100644 index 00000000..9c24b643 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l12_region_beside_leaked_disposable.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L12_region_beside_leaked_disposable.cs", + "line": 14, + "code": "OWN001", + "component": "Own.Protocols.Cases.L12RegionBesideLeakedDisposable.Run", + "event": "log", + "handler": "", + "message": "IDisposable local 'log' is never disposed (leak)", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": 13 + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l13_values_captured_into_region.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l13_values_captured_into_region.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l13_values_captured_into_region.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l1_stale_capability.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l1_stale_capability.verdicts.json new file mode 100644 index 00000000..662c6cba --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l1_stale_capability.verdicts.json @@ -0,0 +1,32 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs", + "line": 13, + "code": "OWN002", + "component": "Own.Protocols.Cases.L1StaleCapability.Run", + "event": "draft", + "handler": "", + "message": "IDisposable local 'draft' is used after it is disposed", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [ + [ + "frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs", + 13, + "acquired 'draft' here" + ], + [ + "frontend/roslyn/protocol-samples/cases/L1_stale_capability.cs", + 16, + "used here after it was released/returned" + ] + ], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l2_copied_capability.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l2_copied_capability.verdicts.json new file mode 100644 index 00000000..278c2d18 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l2_copied_capability.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L2_copied_capability.cs", + "line": 13, + "code": "OWN005", + "component": "Own.Protocols.Cases.L2CopiedCapability.Run", + "event": "draft", + "handler": "", + "message": "IDisposable local 'draft' is used after its ownership was moved", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l3_raw_mutation.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l3_raw_mutation.verdicts.json new file mode 100644 index 00000000..03f13c69 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l3_raw_mutation.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L3_raw_mutation.cs", + "line": 13, + "code": "OWN013", + "component": "Own.Protocols.Cases.L3RawMutation.Run", + "event": "order", + "handler": "", + "message": "IDisposable local 'order' is used directly while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l4_raw_escape.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l4_raw_escape.verdicts.json new file mode 100644 index 00000000..ecaa04e6 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l4_raw_escape.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L4_raw_escape.cs", + "line": 13, + "code": "OWN013", + "component": "Own.Protocols.Cases.L4RawEscape.Run", + "event": "order", + "handler": "", + "message": "IDisposable local 'order' is used directly while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l5_normal_transition.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l5_normal_transition.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l5_normal_transition.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l6_two_transitions.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l6_two_transitions.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l6_two_transitions.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l6b_chained_transitions.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l6b_chained_transitions.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l6b_chained_transitions.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l7_read_after_region.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l7_read_after_region.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l7_read_after_region.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l8_branch_inside_region.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l8_branch_inside_region.verdicts.json new file mode 100644 index 00000000..4c7bfd16 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l8_branch_inside_region.verdicts.json @@ -0,0 +1,32 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "frontend/roslyn/protocol-samples/cases/L8_branch_inside_region.cs", + "line": 12, + "code": "OWN009", + "component": "Own.Protocols.Cases.L8BranchInsideRegion.Run", + "event": "approved", + "handler": "", + "message": "IDisposable local 'approved' may be used after disposal on some path", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [ + [ + "frontend/roslyn/protocol-samples/cases/L8_branch_inside_region.cs", + 12, + "acquired 'approved' here" + ], + [ + "frontend/roslyn/protocol-samples/cases/L8_branch_inside_region.cs", + 18, + "may be used here after release on some path" + ] + ], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_cs_l9_opaque_calls_around_region.verdicts.json b/tests/fixtures/verdicts/typestate_cs_l9_opaque_calls_around_region.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_l9_opaque_calls_around_region.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_cs_x1_nested_region_same_entity.verdicts.json b/tests/fixtures/verdicts/typestate_cs_x1_nested_region_same_entity.verdicts.json new file mode 100644 index 00000000..ead91307 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_cs_x1_nested_region_same_entity.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "frontend/roslyn/protocol-samples/cases/X1_nested_region_same_entity.cs", + "line": 13, + "code": "OWN011", + "component": "Own.Protocols.Cases.X1NestedRegionSameEntity.Run", + "event": "order", + "handler": "", + "message": "IDisposable local 'order' is exclusively borrowed while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_ef_orderbackend.verdicts.json b/tests/fixtures/verdicts/typestate_ef_orderbackend.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_ef_orderbackend.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_g6_capability_not_spent.verdicts.json b/tests/fixtures/verdicts/typestate_g6_capability_not_spent.verdicts.json new file mode 100644 index 00000000..51cabe9b --- /dev/null +++ b/tests/fixtures/verdicts/typestate_g6_capability_not_spent.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "Orders.cs", + "line": 12, + "code": "OWN001", + "component": "Handler.Run", + "event": "a", + "handler": "", + "message": "IDisposable local 'a' is never disposed (leak)", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_l1_stale_capability.verdicts.json b/tests/fixtures/verdicts/typestate_l1_stale_capability.verdicts.json new file mode 100644 index 00000000..40549b88 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l1_stale_capability.verdicts.json @@ -0,0 +1,32 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "Orders.cs", + "line": 12, + "code": "OWN002", + "component": "Handler.Run", + "event": "d", + "handler": "", + "message": "IDisposable local 'd' is used after it is disposed", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [ + [ + "Orders.cs", + 12, + "acquired 'd' here" + ], + [ + "Orders.cs", + 14, + "used here after it was released/returned" + ] + ], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_l2_copied_capability.verdicts.json b/tests/fixtures/verdicts/typestate_l2_copied_capability.verdicts.json new file mode 100644 index 00000000..5d6c8959 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l2_copied_capability.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "Orders.cs", + "line": 12, + "code": "OWN005", + "component": "Handler.Run", + "event": "d1", + "handler": "", + "message": "IDisposable local 'd1' is used after its ownership was moved", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_l3_raw_entity_mutation.verdicts.json b/tests/fixtures/verdicts/typestate_l3_raw_entity_mutation.verdicts.json new file mode 100644 index 00000000..a5ec0756 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l3_raw_entity_mutation.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "Orders.cs", + "line": 10, + "code": "OWN011", + "component": "Handler.Run", + "event": "order", + "handler": "", + "message": "IDisposable local 'order' is exclusively borrowed while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_l3b_second_region.verdicts.json b/tests/fixtures/verdicts/typestate_l3b_second_region.verdicts.json new file mode 100644 index 00000000..a5ec0756 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l3b_second_region.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "Orders.cs", + "line": 10, + "code": "OWN011", + "component": "Handler.Run", + "event": "order", + "handler": "", + "message": "IDisposable local 'order' is exclusively borrowed while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_l4_raw_entity_unknown_call.verdicts.json b/tests/fixtures/verdicts/typestate_l4_raw_entity_unknown_call.verdicts.json new file mode 100644 index 00000000..1ca7a132 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l4_raw_entity_unknown_call.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "error": "OwnIR call to 'Unknown' inside a borrow_mut region passes tracked local 'order', but the callee has no ownership contract (Orders.cs:13) — refused: an exclusive region must not hand its entity or tokens to unanalysed code" +} diff --git a/tests/fixtures/verdicts/typestate_l4b_raw_entity_shared_call.verdicts.json b/tests/fixtures/verdicts/typestate_l4b_raw_entity_shared_call.verdicts.json new file mode 100644 index 00000000..2f02421e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l4b_raw_entity_shared_call.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "Orders.cs", + "line": 10, + "code": "OWN012", + "component": "Handler.Run", + "event": "order", + "handler": "", + "message": "IDisposable local 'order' is borrowed while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_l4c_raw_entity_consumed.verdicts.json b/tests/fixtures/verdicts/typestate_l4c_raw_entity_consumed.verdicts.json new file mode 100644 index 00000000..3de030bd --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l4c_raw_entity_consumed.verdicts.json @@ -0,0 +1,21 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "Orders.cs", + "line": 10, + "code": "OWN007", + "component": "Handler.Run", + "event": "order", + "handler": "", + "message": "IDisposable local 'order' is consumed or returned while it is borrowed", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_l4d_token_unknown_call.verdicts.json b/tests/fixtures/verdicts/typestate_l4d_token_unknown_call.verdicts.json new file mode 100644 index 00000000..25d4e12f --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l4d_token_unknown_call.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "error": "OwnIR call to 'Unknown' inside a borrow_mut region passes tracked local 'a', but the callee has no ownership contract (Orders.cs:13) — refused: an exclusive region must not hand its entity or tokens to unanalysed code" +} diff --git a/tests/fixtures/verdicts/typestate_l5_normal_transition.verdicts.json b/tests/fixtures/verdicts/typestate_l5_normal_transition.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l5_normal_transition.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_l5b_two_transitions.verdicts.json b/tests/fixtures/verdicts/typestate_l5b_two_transitions.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l5b_two_transitions.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_l5c_read_after_region.verdicts.json b/tests/fixtures/verdicts/typestate_l5c_read_after_region.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_l5c_read_after_region.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_n1_token_spent_on_other_entity.verdicts.json b/tests/fixtures/verdicts/typestate_n1_token_spent_on_other_entity.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_n1_token_spent_on_other_entity.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_n2_two_tokens_one_region.verdicts.json b/tests/fixtures/verdicts/typestate_n2_two_tokens_one_region.verdicts.json new file mode 100644 index 00000000..9454b37e --- /dev/null +++ b/tests/fixtures/verdicts/typestate_n2_two_tokens_one_region.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "findings": [] +} diff --git a/tests/fixtures/verdicts/typestate_n3_raw_mutation_inferred_effect.verdicts.json b/tests/fixtures/verdicts/typestate_n3_raw_mutation_inferred_effect.verdicts.json new file mode 100644 index 00000000..a327e8d5 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_n3_raw_mutation_inferred_effect.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "error": "OwnIR call to 'Touch' inside a borrow_mut region passes tracked local 'order' at position 0, which carries no ownership effect (Orders.cs:13) — refused: inside an exclusive region every position that receives the entity or a token must state what it does with it" +} diff --git a/tests/fixtures/verdicts/typestate_n4_token_outlives_region.verdicts.json b/tests/fixtures/verdicts/typestate_n4_token_outlives_region.verdicts.json new file mode 100644 index 00000000..1c289081 --- /dev/null +++ b/tests/fixtures/verdicts/typestate_n4_token_outlives_region.verdicts.json @@ -0,0 +1,4 @@ +{ + "verdicts_version": 1, + "error": "internal: the core reported [OWN030] on the lowered facts that the bridge cannot map back to a C# subscription (subject=None, message=\"undefined name 'loc_13'\"). The OwnIR lowering has drifted from the core; teach the bridge this diagnostic rather than dropping the finding." +} diff --git a/tests/fixtures/verdicts/typestate_w1_loan_wordings.verdicts.json b/tests/fixtures/verdicts/typestate_w1_loan_wordings.verdicts.json new file mode 100644 index 00000000..84bbcccd --- /dev/null +++ b/tests/fixtures/verdicts/typestate_w1_loan_wordings.verdicts.json @@ -0,0 +1,101 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "Wordings.cs", + "line": 1, + "code": "OWN005", + "component": "W.Moved", + "event": "b", + "handler": "", + "message": "IDisposable local 'b' is used after its ownership was moved", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + }, + { + "file": "Wordings.cs", + "line": 11, + "code": "OWN007", + "component": "W.Consumed", + "event": "o", + "handler": "", + "message": "IDisposable local 'o' is consumed or returned while it is borrowed", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + }, + { + "file": "Wordings.cs", + "line": 21, + "code": "OWN008", + "component": "W.Released", + "event": "o", + "handler": "", + "message": "IDisposable local 'o' is released while it is borrowed", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + }, + { + "file": "Wordings.cs", + "line": 31, + "code": "OWN011", + "component": "W.Reborrowed", + "event": "o", + "handler": "", + "message": "IDisposable local 'o' is exclusively borrowed while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + }, + { + "file": "Wordings.cs", + "line": 41, + "code": "OWN012", + "component": "W.Shared", + "event": "o", + "handler": "", + "message": "IDisposable local 'o' is borrowed while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + }, + { + "file": "Wordings.cs", + "line": 51, + "code": "OWN013", + "component": "W.Used", + "event": "o", + "handler": "", + "message": "IDisposable local 'o' is used directly while an exclusive borrow of it is live", + "kind": "disposable", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/typestate_w2_loan_wordings_pooled.verdicts.json b/tests/fixtures/verdicts/typestate_w2_loan_wordings_pooled.verdicts.json new file mode 100644 index 00000000..0502e3ea --- /dev/null +++ b/tests/fixtures/verdicts/typestate_w2_loan_wordings_pooled.verdicts.json @@ -0,0 +1,101 @@ +{ + "verdicts_version": 1, + "findings": [ + { + "file": "Wordings.cs", + "line": 1, + "code": "OWN005", + "component": "W.Moved", + "event": "b", + "handler": "", + "message": "pooled buffer 'b' is used after its ownership was moved", + "kind": "pooled buffer", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + }, + { + "file": "Wordings.cs", + "line": 11, + "code": "OWN007", + "component": "W.Consumed", + "event": "o", + "handler": "", + "message": "pooled buffer 'o' is consumed or returned while it is borrowed", + "kind": "pooled buffer", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + }, + { + "file": "Wordings.cs", + "line": 21, + "code": "OWN008", + "component": "W.Released", + "event": "o", + "handler": "", + "message": "pooled buffer 'o' is released while it is borrowed", + "kind": "pooled buffer", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + }, + { + "file": "Wordings.cs", + "line": 31, + "code": "OWN011", + "component": "W.Reborrowed", + "event": "o", + "handler": "", + "message": "pooled buffer 'o' is exclusively borrowed while an exclusive borrow of it is live", + "kind": "pooled buffer", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + }, + { + "file": "Wordings.cs", + "line": 41, + "code": "OWN012", + "component": "W.Shared", + "event": "o", + "handler": "", + "message": "pooled buffer 'o' is borrowed while an exclusive borrow of it is live", + "kind": "pooled buffer", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + }, + { + "file": "Wordings.cs", + "line": 51, + "code": "OWN013", + "component": "W.Used", + "event": "o", + "handler": "", + "message": "pooled buffer 'o' is used directly while an exclusive borrow of it is live", + "kind": "pooled buffer", + "advisory": false, + "severity": null, + "related": [], + "flow": [], + "ignore_reason": null, + "column": null + } + ] +} diff --git a/tests/fixtures/verdicts/verdict_boundary_effect_line_negative.facts.json b/tests/fixtures/verdicts/verdict_boundary_effect_line_negative.facts.json index 3737429c..7db44663 100644 --- a/tests/fixtures/verdicts/verdict_boundary_effect_line_negative.facts.json +++ b/tests/fixtures/verdicts/verdict_boundary_effect_line_negative.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Bound", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_boundary_line_above_u32.facts.json b/tests/fixtures/verdicts/verdict_boundary_line_above_u32.facts.json index 21795e6c..000653c1 100644 --- a/tests/fixtures/verdicts/verdict_boundary_line_above_u32.facts.json +++ b/tests/fixtures/verdicts/verdict_boundary_line_above_u32.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Bound", "_doc": [ "The upper edge of the same promoted control: an acquire at 2^32 is outside", diff --git a/tests/fixtures/verdicts/verdict_boundary_line_negative.facts.json b/tests/fixtures/verdicts/verdict_boundary_line_negative.facts.json index 98d68d2d..fabde6a7 100644 --- a/tests/fixtures/verdicts/verdict_boundary_line_negative.facts.json +++ b/tests/fixtures/verdicts/verdict_boundary_line_negative.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Bound", "_doc": [ "A promoted #259 coordinate-domain control: a negative param line. Before", diff --git a/tests/fixtures/verdicts/verdict_boundary_service_line_negative.facts.json b/tests/fixtures/verdicts/verdict_boundary_service_line_negative.facts.json index 89253f3b..5861b2a7 100644 --- a/tests/fixtures/verdicts/verdict_boundary_service_line_negative.facts.json +++ b/tests/fixtures/verdicts/verdict_boundary_service_line_negative.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Bound", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_column_sort_order.facts.json b/tests/fixtures/verdicts/verdict_column_sort_order.facts.json index 53caa314..daf8a879 100644 --- a/tests/fixtures/verdicts/verdict_column_sort_order.facts.json +++ b/tests/fixtures/verdicts/verdict_column_sort_order.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Cols", "_doc": [ "BR-V8's column member: two leaks on the SAME line are minted in the order b", diff --git a/tests/fixtures/verdicts/verdict_dedup_key_members.facts.json b/tests/fixtures/verdicts/verdict_dedup_key_members.facts.json index cf625c8e..c836f39c 100644 --- a/tests/fixtures/verdicts/verdict_dedup_key_members.facts.json +++ b/tests/fixtures/verdicts/verdict_dedup_key_members.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DedupKeyMembers", "_doc": [ "BR-V7 key members that survive only because they are IN the key, now that", diff --git a/tests/fixtures/verdicts/verdict_dedup_needs_the_message.facts.json b/tests/fixtures/verdicts/verdict_dedup_needs_the_message.facts.json index 6247bfa0..3ceb93d3 100644 --- a/tests/fixtures/verdicts/verdict_dedup_needs_the_message.facts.json +++ b/tests/fixtures/verdicts/verdict_dedup_needs_the_message.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DedupNeedsTheMessage", "_doc": [ "BR-V7's `message` member, which cp4 could not carry and argued was", diff --git a/tests/fixtures/verdicts/verdict_degenerate_metadata.facts.json b/tests/fixtures/verdicts/verdict_degenerate_metadata.facts.json index aa0bacff..c9fb182f 100644 --- a/tests/fixtures/verdicts/verdict_degenerate_metadata.facts.json +++ b/tests/fixtures/verdicts/verdict_degenerate_metadata.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DegenerateMetadata", "_doc": [ "Metadata that is PRESENT and degenerate, which is not the same as absent.", diff --git a/tests/fixtures/verdicts/verdict_di004_call_site_anchor.facts.json b/tests/fixtures/verdicts/verdict_di004_call_site_anchor.facts.json index 903a5bd9..3d275348 100644 --- a/tests/fixtures/verdicts/verdict_di004_call_site_anchor.facts.json +++ b/tests/fixtures/verdicts/verdict_di004_call_site_anchor.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Di004", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_di005_cache_site_anchor.facts.json b/tests/fixtures/verdicts/verdict_di005_cache_site_anchor.facts.json index 7d612df5..54e94aff 100644 --- a/tests/fixtures/verdicts/verdict_di005_cache_site_anchor.facts.json +++ b/tests/fixtures/verdicts/verdict_di005_cache_site_anchor.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Di005", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_di_duplicate_sites_last_wins.facts.json b/tests/fixtures/verdicts/verdict_di_duplicate_sites_last_wins.facts.json index e10b8921..5246092b 100644 --- a/tests/fixtures/verdicts/verdict_di_duplicate_sites_last_wins.facts.json +++ b/tests/fixtures/verdicts/verdict_di_duplicate_sites_last_wins.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DiDup", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_di_evidence_degradations.facts.json b/tests/fixtures/verdicts/verdict_di_evidence_degradations.facts.json index 745e2373..dd351b50 100644 --- a/tests/fixtures/verdicts/verdict_di_evidence_degradations.facts.json +++ b/tests/fixtures/verdicts/verdict_di_evidence_degradations.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DiEvidenceDegradations", "_doc": [ "Two BR-V5 degradations on the DI families. `App` records a consuming ctor", diff --git a/tests/fixtures/verdicts/verdict_di_graph_families.facts.json b/tests/fixtures/verdicts/verdict_di_graph_families.facts.json index 50121f85..5a60b17c 100644 --- a/tests/fixtures/verdicts/verdict_di_graph_families.facts.json +++ b/tests/fixtures/verdicts/verdict_di_graph_families.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DiGraph", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_di_tolerant_typed_coercions.facts.json b/tests/fixtures/verdicts/verdict_di_tolerant_typed_coercions.facts.json index 9cfa7340..a835a566 100644 --- a/tests/fixtures/verdicts/verdict_di_tolerant_typed_coercions.facts.json +++ b/tests/fixtures/verdicts/verdict_di_tolerant_typed_coercions.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "DiTolerant", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_domain_tolerant_readers.facts.json b/tests/fixtures/verdicts/verdict_domain_tolerant_readers.facts.json index b946ab0a..3b92f3a5 100644 --- a/tests/fixtures/verdicts/verdict_domain_tolerant_readers.facts.json +++ b/tests/fixtures/verdicts/verdict_domain_tolerant_readers.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Dom", "_doc": [ "The tolerant coordinate readers, where nothing else reaches them. The four", diff --git a/tests/fixtures/verdicts/verdict_door_effect_deps_not_strings.facts.json b/tests/fixtures/verdicts/verdict_door_effect_deps_not_strings.facts.json index e3510dc1..9a10a556 100644 --- a/tests/fixtures/verdicts/verdict_door_effect_deps_not_strings.facts.json +++ b/tests/fixtures/verdicts/verdict_door_effect_deps_not_strings.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Door", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_door_service_unknown_lifetime.facts.json b/tests/fixtures/verdicts/verdict_door_service_unknown_lifetime.facts.json index 4ecfd778..6e429306 100644 --- a/tests/fixtures/verdicts/verdict_door_service_unknown_lifetime.facts.json +++ b/tests/fixtures/verdicts/verdict_door_service_unknown_lifetime.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Door", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_eff001_slice_dropped.facts.json b/tests/fixtures/verdicts/verdict_eff001_slice_dropped.facts.json index ee73b2f8..42a64a6a 100644 --- a/tests/fixtures/verdicts/verdict_eff001_slice_dropped.facts.json +++ b/tests/fixtures/verdicts/verdict_eff001_slice_dropped.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Eff001NoSlice", "_doc": [ "BR-V5's line-guard on the effect slice: the storm is a verdict either way,", diff --git a/tests/fixtures/verdicts/verdict_eff001_storm_and_memo.facts.json b/tests/fixtures/verdicts/verdict_eff001_storm_and_memo.facts.json index ff9889b9..020b0c07 100644 --- a/tests/fixtures/verdicts/verdict_eff001_storm_and_memo.facts.json +++ b/tests/fixtures/verdicts/verdict_eff001_storm_and_memo.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Fx", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_flow_local_wordings.facts.json b/tests/fixtures/verdicts/verdict_flow_local_wordings.facts.json index e983201b..3ddb770b 100644 --- a/tests/fixtures/verdicts/verdict_flow_local_wordings.facts.json +++ b/tests/fixtures/verdicts/verdict_flow_local_wordings.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "FlowLocalWordings", "_doc": [ "BR-V4's flow-local wordings the swept corpora never mint, one function each", diff --git a/tests/fixtures/verdicts/verdict_multi_file_ordering.facts.json b/tests/fixtures/verdicts/verdict_multi_file_ordering.facts.json index d61e0c4a..3639865d 100644 --- a/tests/fixtures/verdicts/verdict_multi_file_ordering.facts.json +++ b/tests/fixtures/verdicts/verdict_multi_file_ordering.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Order", "_doc": [ "BR-V8 across families and files: five findings on line 7 in five files sort", diff --git a/tests/fixtures/verdicts/verdict_own014_escape_slice_dropped.facts.json b/tests/fixtures/verdicts/verdict_own014_escape_slice_dropped.facts.json index 5377c85b..94630572 100644 --- a/tests/fixtures/verdicts/verdict_own014_escape_slice_dropped.facts.json +++ b/tests/fixtures/verdicts/verdict_own014_escape_slice_dropped.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Own014NoSlice", "_doc": [ "BR-V5's 'a slice shorter than two steps is dropped', on the OWN014 escape", diff --git a/tests/fixtures/verdicts/verdict_own014_wordings.facts.json b/tests/fixtures/verdicts/verdict_own014_wordings.facts.json index fba21931..52f38c4b 100644 --- a/tests/fixtures/verdicts/verdict_own014_wordings.facts.json +++ b/tests/fixtures/verdicts/verdict_own014_wordings.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Own014Wordings", "_doc": [ "The OWN014 wordings the swept corpora never mint. `Cache` is a DI SCOPED", diff --git a/tests/fixtures/verdicts/verdict_own051_gates.facts.json b/tests/fixtures/verdicts/verdict_own051_gates.facts.json index a9ee0a1e..d0c8b018 100644 --- a/tests/fixtures/verdicts/verdict_own051_gates.facts.json +++ b/tests/fixtures/verdicts/verdict_own051_gates.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Gates", "_doc": [ "BR-L8 / INF-A5 advisories: an owned local dropped after a may-call is silent", diff --git a/tests/fixtures/verdicts/verdict_own053_orphaned_awaitable.facts.json b/tests/fixtures/verdicts/verdict_own053_orphaned_awaitable.facts.json index d177b023..4296069f 100644 --- a/tests/fixtures/verdicts/verdict_own053_orphaned_awaitable.facts.json +++ b/tests/fixtures/verdicts/verdict_own053_orphaned_awaitable.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Orphans", "_doc": [ "BR-V1 / BR-V4 / BR-V8: the OWN053 orphaned-awaitable advisory, promoted from", diff --git a/tests/fixtures/verdicts/verdict_pool_view_anchor.facts.json b/tests/fixtures/verdicts/verdict_pool_view_anchor.facts.json index f5cd45f4..eb7874a1 100644 --- a/tests/fixtures/verdicts/verdict_pool_view_anchor.facts.json +++ b/tests/fixtures/verdicts/verdict_pool_view_anchor.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "PoolView", "_doc": [ "OWN025 anchors at the VIEW site (the core's line) with column null ON", diff --git a/tests/fixtures/verdicts/verdict_protocol_absent_rules_are_silent.facts.json b/tests/fixtures/verdicts/verdict_protocol_absent_rules_are_silent.facts.json index b2df7e99..a17e3ffd 100644 --- a/tests/fixtures/verdicts/verdict_protocol_absent_rules_are_silent.facts.json +++ b/tests/fixtures/verdicts/verdict_protocol_absent_rules_are_silent.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Silent", "components": [ { diff --git a/tests/fixtures/verdicts/verdict_protocol_barrier_maybe_two_step_slice.facts.json b/tests/fixtures/verdicts/verdict_protocol_barrier_maybe_two_step_slice.facts.json index cef39096..ca356c42 100644 --- a/tests/fixtures/verdicts/verdict_protocol_barrier_maybe_two_step_slice.facts.json +++ b/tests/fixtures/verdicts/verdict_protocol_barrier_maybe_two_step_slice.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Docs", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_protocol_beside_other_families.facts.json b/tests/fixtures/verdicts/verdict_protocol_beside_other_families.facts.json index ce94f4ef..f281b134 100644 --- a/tests/fixtures/verdicts/verdict_protocol_beside_other_families.facts.json +++ b/tests/fixtures/verdicts/verdict_protocol_beside_other_families.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Mixed", "components": [ { diff --git a/tests/fixtures/verdicts/verdict_protocol_exit_codes_and_wordings.facts.json b/tests/fixtures/verdicts/verdict_protocol_exit_codes_and_wordings.facts.json index 27f2c254..e693c343 100644 --- a/tests/fixtures/verdicts/verdict_protocol_exit_codes_and_wordings.facts.json +++ b/tests/fixtures/verdicts/verdict_protocol_exit_codes_and_wordings.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Batch", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_protocol_identity_and_line_guards.facts.json b/tests/fixtures/verdicts/verdict_protocol_identity_and_line_guards.facts.json index 4848b8ae..d43aafe8 100644 --- a/tests/fixtures/verdicts/verdict_protocol_identity_and_line_guards.facts.json +++ b/tests/fixtures/verdicts/verdict_protocol_identity_and_line_guards.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Names", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_protocol_obl005_dead_rule.facts.json b/tests/fixtures/verdicts/verdict_protocol_obl005_dead_rule.facts.json index 19387b25..29baa75e 100644 --- a/tests/fixtures/verdicts/verdict_protocol_obl005_dead_rule.facts.json +++ b/tests/fixtures/verdicts/verdict_protocol_obl005_dead_rule.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Ghosts", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_protocol_tolerant_door_rules.facts.json b/tests/fixtures/verdicts/verdict_protocol_tolerant_door_rules.facts.json index 0e9a0039..2d53b212 100644 --- a/tests/fixtures/verdicts/verdict_protocol_tolerant_door_rules.facts.json +++ b/tests/fixtures/verdicts/verdict_protocol_tolerant_door_rules.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Tolerant", "components": [], "_doc": [ diff --git a/tests/fixtures/verdicts/verdict_same_site_distinct_events.facts.json b/tests/fixtures/verdicts/verdict_same_site_distinct_events.facts.json index a6a741ad..a9045b0c 100644 --- a/tests/fixtures/verdicts/verdict_same_site_distinct_events.facts.json +++ b/tests/fixtures/verdicts/verdict_same_site_distinct_events.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "SameSite", "_doc": [ "BR-V7's key, one pair per member: records on the same line that differ in", diff --git a/tests/fixtures/verdicts/verdict_severity_tiers_and_suppression.facts.json b/tests/fixtures/verdicts/verdict_severity_tiers_and_suppression.facts.json index 1264ecd0..2ba04fde 100644 --- a/tests/fixtures/verdicts/verdict_severity_tiers_and_suppression.facts.json +++ b/tests/fixtures/verdicts/verdict_severity_tiers_and_suppression.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Tiers", "_doc": [ "BR-V6: an injected-source `+=` or ignored `.Subscribe()` is the warning tier;", diff --git a/tests/fixtures/verdicts/verdict_skip_list_artifacts.facts.json b/tests/fixtures/verdicts/verdict_skip_list_artifacts.facts.json index 9d532fd5..2dc4b0cb 100644 --- a/tests/fixtures/verdicts/verdict_skip_list_artifacts.facts.json +++ b/tests/fixtures/verdicts/verdict_skip_list_artifacts.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Skip", "_doc": [ "BR-V2, the CLOSED skip list, one control per member the tree can reach:", diff --git a/tests/fixtures/verdicts/verdict_subscription_lambda_note.facts.json b/tests/fixtures/verdicts/verdict_subscription_lambda_note.facts.json index e1caee3c..f6f9e6ca 100644 --- a/tests/fixtures/verdicts/verdict_subscription_lambda_note.facts.json +++ b/tests/fixtures/verdicts/verdict_subscription_lambda_note.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "SubscriptionLambdaNote", "_doc": [ "The inline-lambda note on the INJECTED plain-subscription wording. The", diff --git a/tests/fixtures/verdicts/verdict_unknown_line_guards.facts.json b/tests/fixtures/verdicts/verdict_unknown_line_guards.facts.json index 51faa6de..d0412497 100644 --- a/tests/fixtures/verdicts/verdict_unknown_line_guards.facts.json +++ b/tests/fixtures/verdicts/verdict_unknown_line_guards.facts.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "UnknownLineGuards", "_doc": [ "BR-V5's line guards, one per slice builder, each on a record that IS a", diff --git a/tests/goldens/README.md b/tests/goldens/README.md index 43595b1f..e68c4045 100644 --- a/tests/goldens/README.md +++ b/tests/goldens/README.md @@ -31,6 +31,19 @@ The remaining 11 followed the same derivation, and run 30443181114 (job values are what the extractor actually emits, not just the dozen that had been read off a log. The file is a measured artifact again. +**Amended a second time, by OwnIR v1.** The flow vocabulary gained `move` and +`borrow_mut`, `OWNIR_VERSION` moved 0 → 1, and every producer stamps it. One line +of this file changed — `"ownir_version": 0` became `"ownir_version": 1` — and +nothing else: no record, no key, no order. That is again the "intentional +alteration by an unrelated extractor change" case, and again the file is the +`ff21d4a` output plus documented deltas rather than a re-recording. + +The same bump found a control that had confused the two things this gate keeps +apart. `tests/check_fix_candidates_facts.py` asserted `ownir_version == 0` under +the message "must stay 0", meaning "the flag does not move the version" but +checking a literal. It now checks what it meant: the flag-on facts carry the +core's current `OWNIR_VERSION`, and the same one as the flag-off facts. + ### Regenerating (only when an unrelated extractor change intentionally alters this sample's facts) ```bash diff --git a/tests/goldens/fix_candidates_off.golden.json b/tests/goldens/fix_candidates_off.golden.json index 9110c56c..c60de9bc 100644 --- a/tests/goldens/fix_candidates_off.golden.json +++ b/tests/goldens/fix_candidates_off.golden.json @@ -1,5 +1,5 @@ { - "ownir_version": 0, + "ownir_version": 1, "module": "Extracted", "components": [ { diff --git a/tests/test_effects.py b/tests/test_effects.py index ed13aff7..885072d4 100644 --- a/tests/test_effects.py +++ b/tests/test_effects.py @@ -99,7 +99,7 @@ def check(cond: bool, msg: str) -> None: # ---- the OwnIR bridge ---- facts = { - "ownir_version": 0, "module": "D", "components": [], + "ownir_version": 1, "module": "D", "components": [], "effects": [ {"component": "Dashboard", "file": "Dashboard.tsx", "line": 33, "io": True, "deps": ["filters"], @@ -123,11 +123,11 @@ def check(cond: bool, msg: str) -> None: check("EFF001" in rules and "storm" in rules["EFF001"], "EFF001 must appear in the SARIF rules") # malformed effects degrade gracefully (additive/optional, never a crash). - check(check_facts({"ownir_version": 0, "components": [], "effects": "nope"}) == [], + check(check_facts({"ownir_version": 1, "components": [], "effects": "nope"}) == [], "a malformed effects block must not crash check_facts") # a per-entry malformed effect is SKIPPED, not coerced: `deps: "a"` must NOT # become `("a",)` and emit a spurious EFF001 on the direct check_facts() path. - coerce = check_facts({"ownir_version": 0, "components": [], "effects": [ + coerce = check_facts({"ownir_version": 1, "components": [], "effects": [ {"component": "X", "file": "X.tsx", "line": 1, "io": True, "deps": "a", "bindings": [{"name": "a", "init": "object", "refs": [], "line": 1}]}]}) check(coerce == [], f"a malformed deps='a' entry must be skipped, got {coerce}") diff --git a/tests/test_fix_candidates.py b/tests/test_fix_candidates.py index c5b905a3..a724cf29 100644 --- a/tests/test_fix_candidates.py +++ b/tests/test_fix_candidates.py @@ -63,7 +63,7 @@ def _facts(subs: list[dict], qn: str = "N.C", file: str = "N/C.cs", comp = {"name": qn.rsplit(".", 1)[-1], "qualified_name": qn, "is_partial": is_partial, "is_nested": is_nested, "declaration_count": 1, "is_generated": is_generated, "file": file, "subscriptions": subs} - facts: dict = {"ownir_version": 0, "components": [comp, *(extra or [])]} + facts: dict = {"ownir_version": 1, "components": [comp, *(extra or [])]} if version is not _OMIT: facts["fix_candidates_version"] = version return facts diff --git a/tests/test_obligations.py b/tests/test_obligations.py index 0bf069cf..05b50054 100644 --- a/tests/test_obligations.py +++ b/tests/test_obligations.py @@ -355,7 +355,7 @@ def rejects(fn: object, raw: object, why: str) -> None: # exit leak through the bridge: OBL003 anchored at the open site, and the # SARIF rules catalogue knows the code. leak = check_facts({ - "ownir_version": 0, "module": "S", + "ownir_version": 1, "module": "S", "protocols": [{ "name": "Suppress", "opens": {"kind": "assign", "target": "_suppress", "value": True}, @@ -377,7 +377,7 @@ def rejects(fn: object, raw: object, why: str) -> None: # OBL005: a scoped protocol matching no reported method is an advisory. dead = check_facts({ - "ownir_version": 0, "module": "S", + "ownir_version": 1, "module": "S", "protocols": [{ "name": "Ghost", "opens": {"kind": "assign", "target": "x", "value": False}, @@ -391,10 +391,10 @@ def rejects(fn: object, raw: object, why: str) -> None: # malformed blocks degrade gracefully on the direct check_facts path # (load() fail-louds; embedders/tests may skip it). - check(check_facts({"ownir_version": 0, "components": [], + check(check_facts({"ownir_version": 1, "components": [], "protocols": "nope"}) == [], "a malformed protocols block must not crash check_facts") - check(check_facts({"ownir_version": 0, "components": [], + check(check_facts({"ownir_version": 1, "components": [], "protocols": [{"name": "P"}], "protocol_functions": [{"name": "m"}]}) == [], "a malformed protocol entry is skipped on the direct path") @@ -403,7 +403,7 @@ def rejects(fn: object, raw: object, why: str) -> None: # On the direct path the first wins deterministically (the second is # skipped — never a mixed message or a dedup-collapsed pair of findings)... dup = check_facts({ - "ownir_version": 0, "module": "S", + "ownir_version": 1, "module": "S", "protocols": [ {"name": "Dup", "opens": {"kind": "assign", "target": "A", "value": False}, @@ -441,14 +441,14 @@ def load_rejects(doc: dict[str, object], why: str) -> None: finally: os.unlink(tmp) - load_rejects({"ownir_version": 0, "module": "S", + load_rejects({"ownir_version": 1, "module": "S", "protocol_functions": [{"name": "m", "events": [{"ev": "goto", "line": 1}]}]}, "an unknown protocol event") _p = {"name": "Dup", "opens": {"kind": "assign", "target": "A", "value": False}, "closes": {"kind": "assign", "target": "A", "value": True}} - load_rejects({"ownir_version": 0, "module": "S", "protocols": [_p, dict(_p)]}, + load_rejects({"ownir_version": 1, "module": "S", "protocols": [_p, dict(_p)]}, "a duplicate protocol name") # both fixtures pass the real load() gate (shape-valid on disk). diff --git a/tests/test_ownir.py b/tests/test_ownir.py index 2a2b4cd9..e3d9c2d0 100644 --- a/tests/test_ownir.py +++ b/tests/test_ownir.py @@ -478,15 +478,21 @@ def _sub(source: str | None) -> list[Finding]: checks += 1 try: with open(_path, encoding="utf-8") as _f: - _m = _ver.search(_f.read()) + _stamps = [int(_m.group(1)) for _m in _ver.finditer(_f.read())] except OSError as _e: fails.append(f"{_label}: cannot read producer ({_e})") continue - if _m is None: + # EVERY stamp, not the first one. A producer may build its envelope in more + # than one place (the extractor has a branch per additive top-level section), + # and a check that reads only the first literal lets a second one stay behind: + # merging the OWN053 branch (written against v0) into the v1 tree left exactly + # that — one envelope of three still stamped 0, and this check green. + if not _stamps: fails.append(f"{_label}: no `ownir_version` literal found (moved? update this check)") - elif int(_m.group(1)) != OWNIR_VERSION: - fails.append(f"{_label}: ownir_version {_m.group(1)} != core OWNIR_VERSION " - f"{OWNIR_VERSION} — bump every producer together") + elif set(_stamps) != {OWNIR_VERSION}: + fails.append(f"{_label}: ownir_version stamps {_stamps} != core OWNIR_VERSION " + f"{OWNIR_VERSION} — bump every producer, and every envelope in it, " + f"together") # --- Schema <-> code binding (spec/ownir.schema.json). The JSON Schema is the # single source the Python core and the Rust `own-ir` crate (P-022) are both @@ -568,10 +574,15 @@ def _sub(source: str | None) -> list[Finding]: # lower (unknown-op OR the declared-but-unhandled internal raise) is a # phantom authority entry — the set claims an op the lowerer cannot handle. _node = {"op": _op, "line": 1} - if _op in ("acquire", "release", "use", "overspan", "alias_join"): + if _op in ("acquire", "release", "use", "overspan", "alias_join", "move"): _node["var"] = "x" - if _op == "alias_join": + if _op in ("alias_join", "move"): _node["src"] = "x" + if _op == "borrow_mut": + # a well-formed region needs a tracked owner; the smoke body + # here has none, so the lowerer refuses it — which is a + # handled op refusing its input, not an unknown one. + _node.update({"owner": "x", "binding": "r", "body": []}) if _op == "call": _node["callee"] = "f" _facts = {"ownir_version": OWNIR_VERSION, "module": "S", @@ -924,7 +935,7 @@ def _sub(source: str | None) -> list[Finding]: fails.append(f"DI003 message missing consuming-constructor anchor: " f"{cache3.message if cache3 else None!r}") # bridge: DI003 surfaces as a WARNING-severity finding; `disposable` is parsed. - di3facts = {"ownir_version": 0, "module": "X", "components": [], "functions": [], + di3facts = {"ownir_version": 1, "module": "X", "components": [], "functions": [], "services": [ {"name": "Cache", "lifetime": "singleton", "deps": ["Conn"], "file": "S.cs", "line": 7}, @@ -975,7 +986,7 @@ def _sub(source: str | None) -> list[Finding]: if not di2 or "WeakReference" not in di2[0].message: fails.append("DI002 message missing 'WeakReference'") # bridge: DI002 surfaces as a WARNING; `weak_deps` is parsed and kept off DI001. - di2facts = {"ownir_version": 0, "module": "X", "components": [], "functions": [], + di2facts = {"ownir_version": 1, "module": "X", "components": [], "functions": [], "services": [ {"name": "WeakCache", "lifetime": "singleton", "deps": [], "weak_deps": ["Db"], "file": "S.cs", "line": 9}, @@ -1047,7 +1058,7 @@ def _sub(source: str | None) -> list[Finding]: # bridge: DI004 surfaces as a WARNING, anchored at the CALL SITE (R.cs:42) — its real # consumer (Codex) — with the REGISTRATION (S.cs:5) as the Finding.related secondary and # named in the message tail. (registration site S.cs:5 differs from the call site R.cs:42.) - di4facts = {"ownir_version": 0, "module": "X", "components": [], "functions": [], + di4facts = {"ownir_version": 1, "module": "X", "components": [], "functions": [], "services": [ {"name": "Resolver", "lifetime": "singleton", "deps": [], "root_resolves": ["Conn"], "file": "S.cs", "line": 5, @@ -1132,7 +1143,7 @@ def _sub(source: str | None) -> list[Finding]: f"{(trans5.cached_file, trans5.cached_line) if trans5 else None}") # bridge: DI005 surfaces as a WARNING anchored at the STORE site (C.cs:21), with the # REGISTRATION (S.cs:7) as the related secondary and named in the message tail. - di5facts = {"ownir_version": 0, "module": "X", "components": [], "functions": [], + di5facts = {"ownir_version": 1, "module": "X", "components": [], "functions": [], "services": [ {"name": "Cacher", "lifetime": "singleton", "deps": [], "scope_cached": ["Db"], "file": "S.cs", "line": 7, @@ -1232,7 +1243,7 @@ def _sub(source: str | None) -> list[Finding]: fails.append(f"DI001 ReportService transitive flow wrong: {rs.flow if rs else None!r}") checks += 1 # a DI001 whose ctor location is UNKNOWN degrades cleanly — no suffix, no related. - nolocf = check_facts({"ownir_version": 0, "module": "X", "components": [], "functions": [], + nolocf = check_facts({"ownir_version": 1, "module": "X", "components": [], "functions": [], "services": [ {"name": "Cap", "lifetime": "singleton", "deps": ["Sc"], "file": "S.cs", "line": 3}, @@ -1246,7 +1257,7 @@ def _sub(source: str | None) -> list[Finding]: # an INTERFACE registration (AddSingleton): the singleton is 'IBilling' # (no ctor) but the consuming ctor is 'Billing's, so the finding must name the IMPL Billing, # never the interface (Codex). ctor_type carries the impl through the fact. - ifacef = check_facts({"ownir_version": 0, "module": "X", "components": [], "functions": [], + ifacef = check_facts({"ownir_version": 1, "module": "X", "components": [], "functions": [], "services": [ {"name": "IBilling", "lifetime": "singleton", "deps": ["Db"], "file": "Startup.cs", "line": 8, "ctor_file": "Billing.cs", @@ -1486,7 +1497,7 @@ def _sub(source: str | None) -> list[Finding]: # subscribe site -> where the longer-lived source service was registered (its lifetime # is *why* the subscriber escapes). The source hop comes from the services graph. checks += 1 - esc = check_facts({"ownir_version": 0, "module": "M", "functions": [], + esc = check_facts({"ownir_version": 1, "module": "M", "functions": [], "components": [{"name": "Vm", "file": "VM.cs", "subscriptions": [ {"event": "bus.Tick", "handler": "OnTick", "line": 11, "released": False, "resource": "subscription", "source": "injected", "source_type": "IBus"}]}], diff --git a/tests/test_ownir_column.py b/tests/test_ownir_column.py index b9857f45..a9c16d26 100644 --- a/tests/test_ownir_column.py +++ b/tests/test_ownir_column.py @@ -105,7 +105,7 @@ def _subscription_facts(column: int | None = None) -> dict: "line": 12, "released": False} if column is not None: sub["column"] = column - return {"ownir_version": 0, "module": "WpfApp", + return {"ownir_version": 1, "module": "WpfApp", "components": [{"name": "CustomerViewModel", "file": "CustomerViewModel.cs", "subscriptions": [sub]}]} @@ -120,7 +120,7 @@ def _flow_acquire_facts(column: int | None = None) -> dict: acquire: dict = {"op": "acquire", "var": "tfLeak", "line": 105} if column is not None: acquire["column"] = column - return {"ownir_version": 0, "module": "Extracted", "components": [], + return {"ownir_version": 1, "module": "Extracted", "components": [], "functions": [{"name": "FlowLocalsSample.TryNeverDisposed", "file": "FlowLocalsSample.cs", "body": [acquire, @@ -223,11 +223,11 @@ def run() -> int: # the direct `acquire` would leave whole categories line-only, so each path # is exercised here rather than assumed from the code reading. def _fn(body): - return {"ownir_version": 0, "module": "M", "components": [], + return {"ownir_version": 1, "module": "M", "components": [], "functions": [{"name": "F.G", "file": "F.cs", "body": body}]} # a contract param that became an owned obligation (`_lower_fn_params`) - prm = check_facts({"ownir_version": 0, "module": "M", "components": [], + prm = check_facts({"ownir_version": 1, "module": "M", "components": [], "functions": [{"name": "F.G", "file": "F.cs", "params": [{"name": "owned", "line": 30, "column": 26, "effect": "consume"}], @@ -307,8 +307,9 @@ def _fn(body): "a re-indented construct must carry ITS column, not a remembered one") # ---- 8. THINGS THAT MUST NOT MOVE -------------------------------------- - check(OWNIR_VERSION == 0, - f"OWNIR_VERSION must stay 0 - an optional field with a safe default is " + check(OWNIR_VERSION == 1, + f"OWNIR_VERSION must stay 1 (the move/borrow_mut vocabulary) - an " + f"optional field with a safe default is " f"additive (spec/OwnIR.md §2), got {OWNIR_VERSION}") if old and new: for fmt in ("human", "github", "msbuild"): diff --git a/tests/test_ownir_defensive_limits.py b/tests/test_ownir_defensive_limits.py index 1dc028db..ab92a14f 100644 --- a/tests/test_ownir_defensive_limits.py +++ b/tests/test_ownir_defensive_limits.py @@ -90,7 +90,7 @@ def _body(depth: int, key: str = "then") -> dict[str, Any]: node: dict[str, Any] = {"op": "acquire", "column": 1} for _ in range(depth): node = {"op": "if" if key != "body" else "while", key: [node]} - return {"ownir_version": 0, "functions": [{"body": [node]}]} + return {"ownir_version": 1, "functions": [{"body": [node]}]} def _events(depth: int, key: str = "then") -> dict[str, Any]: @@ -98,7 +98,7 @@ def _events(depth: int, key: str = "then") -> dict[str, Any]: node: dict[str, Any] = {"ev": "return", "line": 1} for _ in range(depth): node = {"ev": "if" if key != "body" else "while", "line": 1, key: [node]} - return {"ownir_version": 0, + return {"ownir_version": 1, "protocol_functions": [{"name": "M", "events": [node]}]} @@ -465,12 +465,12 @@ def _subschemas(node: Any, key: str, out: list[Any]) -> None: # Bounding depth is the kind of change that quietly turns that into a # rejection, so it is asserted rather than assumed. for label, document in ( - ("non-list body", {"ownir_version": 0, "functions": [{"body": 7}]}), + ("non-list body", {"ownir_version": 1, "functions": [{"body": 7}]}), ("body of scalars", - {"ownir_version": 0, "functions": [{"body": [1, "x", None]}]}), - ("absent sections", {"ownir_version": 0}), + {"ownir_version": 1, "functions": [{"body": [1, "x", None]}]}), + ("absent sections", {"ownir_version": 1}), ("null column", - {"ownir_version": 0, + {"ownir_version": 1, "components": [{"subscriptions": [{"column": None}]}]}), ): err = _load(document) @@ -486,18 +486,18 @@ def _subschemas(node: Any, key: str, out: list[Any]) -> None: # must not become `2^31 - 1` and `-1` must not become `1`, because a # clamped anchor points at a REAL line the producer did not mean. def _sub(line: Any) -> dict[str, Any]: - return {"ownir_version": 0, "module": "X", + return {"ownir_version": 1, "module": "X", "components": [{"name": "C", "file": "C.cs", "subscriptions": [ {"event": "e", "handler": "h", "line": line, "source": "static"}]}]} def _acquire(line: Any) -> dict[str, Any]: - return {"ownir_version": 0, "module": "X", "functions": [ + return {"ownir_version": 1, "module": "X", "functions": [ {"name": "F", "file": "F.cs", "body": [{"op": "acquire", "var": "x", "line": line}]}]} def _event(line: Any) -> dict[str, Any]: - return {"ownir_version": 0, "module": "X", + return {"ownir_version": 1, "module": "X", "protocols": [{"name": "P", "opens": {"kind": "assign", "target": "f", "value": True}, @@ -549,7 +549,7 @@ def _event(line: Any) -> dict[str, Any]: # only thing that pins the tolerant column bound is right here and the one # synthetic Layer 3 case written for it. def _sub_col(column: Any) -> dict[str, Any]: - return {"ownir_version": 0, "module": "X", + return {"ownir_version": 1, "module": "X", "components": [{"name": "C", "file": "C.cs", "subscriptions": [ {"event": "e", "handler": "h", "line": 7, "column": column, "source": "static"}]}]} diff --git a/tests/test_ownir_input_boundary.py b/tests/test_ownir_input_boundary.py index e333359b..0aecba16 100644 --- a/tests/test_ownir_input_boundary.py +++ b/tests/test_ownir_input_boundary.py @@ -140,7 +140,7 @@ def run() -> int: # its offset — rather than in the decoder's voice, which is what lets the # port report it identically. Both halves are asserted, because an offset # that silently became a character index would still "contain 0xff". - invalid_utf8 = b'{"ownir_version": 0, "components": [{"name": "\xff\xfe"}]}' + invalid_utf8 = b'{"ownir_version": 1, "components": [{"name": "\xff\xfe"}]}' assert invalid_utf8.index(b"\xff") == 46 failures += _refusal_case( invalid_utf8, check="invalid-utf8", @@ -151,7 +151,7 @@ def run() -> int: # This is the case an implementation that indexed past the valid prefix # would crash on. failures += _refusal_case( - b'{"ownir_version": 0}\xc3', check="invalid-utf8", + b'{"ownir_version": 1}\xc3', check="invalid-utf8", must_contain="is not valid UTF-8: byte 0xc3 at offset 20") # SCOPE: valid UTF-8 that is invalid JSON must still reach the JSON door, @@ -188,7 +188,7 @@ def run() -> int: # V1 anywhere else in the document is the same refusal: the constants are # refused by the PARSER, so the position cannot matter. failures += _refusal_case( - b'{"ownir_version": 0, "components": [{"line": NaN}]}', + b'{"ownir_version": 1, "components": [{"line": NaN}]}', check="v1-non-standard-constant", must_contain="is not valid JSON: NaN is not a JSON value") @@ -209,7 +209,7 @@ def run() -> int: # SCOPE 2 — a `-0` on any other field is not V2 at all and must not even # be refused: it is an ordinary zero, and the document still analyses. - ok_doc = (b'{"ownir_version": 0, "components": [{"name": "C", ' + ok_doc = (b'{"ownir_version": 1, "components": [{"name": "C", ' b'"file": "a.cs", "line": -0}]}') outcome, _ = _load_bytes(ok_doc) if outcome != "ok": @@ -239,7 +239,7 @@ def run() -> int: big = f"{sign}99999999999999999999999999" outcome, detail = _load_bytes( b'{"ownir_version": ' + big.encode() + b"}") - want = f"OwnIR facts are schema v{big}, but this core understands v0" + want = f"OwnIR facts are schema v{big}, but this core understands v1" if outcome != "refused" or not str(detail).startswith(want): failures += _fail( f"an oversized integral version must keep taking the Version " @@ -253,7 +253,7 @@ def run() -> int: # with ordinary integers is checked to still load and still carry them as # plain values. outcome, doc = _load_bytes( - b'{"ownir_version": 0, "components": [{"name": "C", "file": "a.cs", ' + b'{"ownir_version": 1, "components": [{"name": "C", "file": "a.cs", ' b'"line": 12, "column": 3}]}') if outcome != "ok": failures += _fail(f"an ordinary document must load, got {outcome}: " diff --git a/tests/test_perf_instrument.py b/tests/test_perf_instrument.py index 7679fd54..bb4d15f2 100644 --- a/tests/test_perf_instrument.py +++ b/tests/test_perf_instrument.py @@ -7,6 +7,7 @@ perf-firewall-decisive a decisive workload cannot reach a clock pre-D7 perf-firewall-calibration a calibration workload can (or the instrument is inert) + perf-calibration-facts-current the reference analyses what the generator writes perf-reference-boundary the Python reference reads nothing its identity misses perf-d7-phase-universe D7's metrics are not the attribution taxonomy perf-gate-dormant the C1/C2 gate exists, is unarmed, and fails closed @@ -1498,8 +1499,58 @@ def control_digest_platform_stable() -> None: "binary is still hashed byte for byte") +def control_calibration_facts_current() -> None: + """A generated facts workload is a document the reference ANALYSES. + + The generator stamps `ownir_version`, and the reference refuses any other + version at its door (spec/OwnIR.md §2). A stamp left behind by a vocabulary + bump turns every `facts` rung into the refusal path: the cells would still + be produced, on both engines, and would time the version gate. The + instrument has a workload for that path on purpose (`refused`), so the two + generators must land on OPPOSITE sides of the door. + + Observed by running the reference on what the generator wrote, not by + comparing two integers: the first OwnIR vocabulary bump (v0 -> v1) left the + generator on v0 with every other control in this suite green. + """ + import subprocess + problems = [] + seen = {"facts": 0, "refused": 0} + with tempfile.TemporaryDirectory(prefix="perf-facts-") as td: + tmp = Path(td) + workloads, _ = pb.load_manifest() + env = dict(os.environ) + env["PYTHONPATH"] = str(ROOT) + for w in workloads: + gen = str(w.spec.get("generator")) + if w.decisive or gen not in seen: + continue + seen[gen] += 1 + target = pb.materialize_calibration(w, tmp) + r = subprocess.run([sys.executable, "-m", "ownlang", "ownir", str(target)], + capture_output=True, env=env, cwd=str(ROOT), check=False) + said = r.stderr.decode("utf-8", "replace").strip()[:160] + if gen == "facts" and r.returncode != 0: + problems.append(f"{w.id}: the reference does not analyse the generated facts " + f"(exit {r.returncode}: {said}) — the rung would time a refusal") + if gen == "refused" and r.returncode != 2: + problems.append(f"{w.id}: the refusal workload is not refused (exit " + f"{r.returncode}), so nothing measures the refusal path") + missing = [g for g, n in seen.items() if n == 0] + if missing: + problems.append(f"the manifest has no {missing} calibration workload; this control " + "exercised nothing for it") + if problems: + fail("perf-calibration-facts-current", "; ".join(problems)) + else: + ok("perf-calibration-facts-current", + f"the reference analyses all {seen['facts']} generated facts workload(s) and " + f"refuses the {seen['refused']} built to be refused") + + def run() -> int: control_firewall() + control_calibration_facts_current() control_reference_boundary() control_d7_phase_universe() control_gate_dormant() diff --git a/tests/test_repro_fixtures.py b/tests/test_repro_fixtures.py index f3900895..04859c8e 100644 --- a/tests/test_repro_fixtures.py +++ b/tests/test_repro_fixtures.py @@ -486,7 +486,7 @@ def raw_of_another_document(a: dict[str, Any]) -> None: # The link that makes `input.document` an observation: bytes that are # perfectly self-consistent (their own digest and length hold) and parse # to a DIFFERENT document than the artifact claims. - other = b'{"ownir_version": 0, "module": "SomethingElse"}' + other = b'{"ownir_version": 1, "module": "SomethingElse"}' a["input"]["raw"] = encode_raw(other) def drop_consumed(a: dict[str, Any]) -> None: diff --git a/tests/test_stage3_cancellation.py b/tests/test_stage3_cancellation.py index afd3b6f3..85640c76 100644 --- a/tests/test_stage3_cancellation.py +++ b/tests/test_stage3_cancellation.py @@ -101,7 +101,7 @@ def _write_workload(path: str, components: int) -> None: """A large but entirely ORDINARY document. Nothing hostile: the point is a run long enough to interrupt, not a parser stress case.""" with open(path, "w", encoding="utf-8") as f: - f.write('{"ownir_version": 0, "components": [') + f.write('{"ownir_version": 1, "components": [') for i in range(components): if i: f.write(",") diff --git a/tests/test_unreachable_branch_probe.py b/tests/test_unreachable_branch_probe.py index 1ce308c7..e942850c 100644 --- a/tests/test_unreachable_branch_probe.py +++ b/tests/test_unreachable_branch_probe.py @@ -84,7 +84,7 @@ def probe_all() -> dict[str, str]: "loc_1": _record(resource="flow-local", event="s", line=4, pool=True, ever_released=False), } - diags = [Diagnostic("OWN005", "moved 's' at A.cs:9", 9, subject=f"{h}#4") + diags = [Diagnostic("OWN015", "moved 's' at A.cs:9", 9, subject=f"{h}#4") for h in ("loc_0", "loc_1")] plain, pooled = _probe(handles, diags) out["flow_local_fallback_plain"] = plain diff --git a/tests/test_verify_delta.py b/tests/test_verify_delta.py index 0e40a8c2..27f1aea9 100644 --- a/tests/test_verify_delta.py +++ b/tests/test_verify_delta.py @@ -159,7 +159,7 @@ def _cfacts(subs: list) -> dict: comp = {"name": _CTYPE.rsplit(".", 1)[-1], "qualified_name": _CTYPE, "is_partial": False, "is_nested": False, "declaration_count": 1, "is_generated": False, "file": _CREL, "subscriptions": subs} - return {"ownir_version": 0, "fix_candidates_version": 1, "components": [comp]} + return {"ownir_version": 1, "fix_candidates_version": 1, "components": [comp]} def _mk_root(work: str) -> str: diff --git a/tests/verdict_surface_inventory.py b/tests/verdict_surface_inventory.py index 6718fd66..a163eff3 100644 --- a/tests/verdict_surface_inventory.py +++ b/tests/verdict_surface_inventory.py @@ -132,7 +132,7 @@ def matches(self, f: dict[str, object]) -> bool: ) #: The disposition of the two fallback rows: see `Branch.note`. UNIT_PINNED = ( - "unreachable from any facts document (the nine-op flow vocabulary raises only codes " + "unreachable from any facts document (the eleven-op flow vocabulary raises only codes " "that HAVE a wording); pinned by a `verdict::tests` control driven through " "`map_core`, whose expected text is read from the recorded probe " "`tests/fixtures/unreachable_branches.json`. The core message it " @@ -173,6 +173,23 @@ def _flow_local(bid: str, code: str, kind: str, what: str, tail: str, _flow_local("flowlocal_own009_pool", "OWN009", "pooled buffer", "flow-local maybe-use-after-return", r" may be used after being returned on some path"), + # the move / loan codes, reachable since the flow vocabulary carries `move` + # and `borrow_mut`; one wording per code, per pool split. + *(_flow_local(f"flowlocal_{code.lower()}{suffix}", code, kind, + f"flow-local {what}{label}", tail) + for kind, suffix, label in (("disposable", "", ""), + ("pooled buffer", "_pool", " on a pooled buffer")) + for code, what, tail in ( + ("OWN005", "use after move", r" is used after its ownership was moved"), + ("OWN007", "consume/return while borrowed", + r" is consumed or returned while it is borrowed"), + ("OWN008", "release while borrowed", r" is released while it is borrowed"), + ("OWN011", "exclusive re-borrow", + r" is exclusively borrowed while an exclusive borrow of it is live"), + ("OWN012", "shared borrow under an exclusive one", + r" is borrowed while an exclusive borrow of it is live"), + ("OWN013", "direct use under an exclusive borrow", + r" is used directly while an exclusive borrow of it is live"))), # the two fallbacks: a flow-local code with no wording of its own keeps the # CORE diagnostic's message verbatim after a colon. _flow_local("flowlocal_fallback", "", "disposable",