fix(printer): recover non-builtin static/vtable alloc typing#131
fix(printer): recover non-builtin static/vtable alloc typing#131
Conversation
|
Hey @Stevengre , the split, made this easy to review. So I went digging into this a bit, and here's what I found: the assert! calls that used to live in the Static and VTable arms (the ones that would panic on non-builtin-deref types) were actually already removed in #126 as part of the broader provenance resolution rework. That means the panic this was originally guarding against is already gone on master. What this PR is doing now is something subtly different: it's a correctness improvement. On master, those arms just unconditionally record the outer ty, which could be a container type rather than the actual pointee when builtin_deref returns None. This PR recovers the real pointee via That said: I wasn't able to actually trigger the non-builtin-deref path. I tried the existing integration suite (none of the 28 programs exercise A natural question: do you have a concrete example (or know of a UI test) where this path actually gets hit? I'd feel a lot better landing this with a test that validates the fix. Right now we're adding recovery logic for a case we can't reproduce, which makes it hard to verify it's doing the right thing. Thanks in advance! |
#129) ### Summary - In `TyCollector::visit_ty` (`src/printer.rs`), after successful closure instance traversal, record closure `Ty` metadata in `types`. - Update integration golden files (`tests/integration/programs/*.smir.json.expected`) to match emitted closure `FunType` metadata. - Keep `Makefile` integration path as `TESTDIR=tests/integration/programs` to keep closure fixture output paths stable. ### Context In the closure arm of `TyCollector::visit_ty`, the code resolved and visited the closure instance but returned without inserting the closure `Ty` into `types`. Other type families were inserted; closures were the exception. This made downstream closure type lookup incomplete (notably for kmir proof paths that consume exported type metadata). Recording closure `Ty` closes that gap. Related split: static/vtable alloc fallback changes were moved out to [stable-mir-json#131](#131) so this PR stays focused on closure metadata. Dependency context: this PR is depended on by [mir-semantics#957](runtimeverification/mir-semantics#957).
|
Additional note using the same input case What this change does in this example (diff-based)Comparing the --- nofix
+++ fix
@@
- "ty_def": {
- "ArrayType": {
- "elem_type": 33,
- "layout": { "abi": { "Aggregate": { "sized": true } }, ... }
- }
- },
- "ty_id": 34
+ "ty_def": {
+ "DynType": {
+ "name": "dyn std::fmt::Debug",
+ "layout": { "abi": { "Aggregate": { "sized": false } }, ... }
+ }
+ },
+ "ty_id": 46So:
This is exactly the Why this is not directly visible in expected snapshotsThe integration normalizer removes alloc type fields: # tests/integration/normalise-filter.jq
.allocs = ( .allocs | map(del(.alloc_id)) | map(del(.ty)) )So expected files only assert alloc kind presence ( |
|
@cds-amal Thanks for asking for an example! Above gives the example! |
|
Hey @Stevengre, it's taking me some time to review this, and I think the merge commits are a big part of why: they make it hard to tell which changes are yours versus what came in from upstream. I wanted to share a quick workflow note while my notes are fresh; I'll follow up with a code review shortly. Looking at the original history on Here's the original branch graph: ⌽ a85eb0e fix(printer): avoid panic on non-builtin static/vtable alloc pointers
⌽ 7282617 docs(printer): clarify static/vtable fallback typing policy
⌽ 8d73970 test(integration): cover static and vtable fallback behavior
⌽ 7621532 fix(tests): reuse SMIR command in fallback check
⌽ 93b40f1 docs(comments): shorten fallback annotations
⌽ 23cb8fb test(integration): use golden case for static/vtable fallback
⌽ f57e1f5 chore(printer): revert unrelated function comment edit
⌽ f1b95e4 docs(test): annotate expected impact for fallback case
⌽ 11180ce docs(test): inline concise comments and remove extra notes file
⌽ 7c8aa5c (merge commit) merge(printer): resolve #131 against latest master
⌽ f54e442 (merge commit) Merge remote-tracking branch 'origin/master' into codex/...
⌽ codex/static-vtable-alloc-fallback test(integration): refresh static-vtable expected after master mergeThat's 12 commits (including 2 merge commits and a post-merge fixup) for a change that touches 4 files. When I open this for review, After rebasing onto master and squashing the iterative work: ⌽ master fix(printer): record closure Ty in type table after instance traversal (#129)
⌽ cacf4d4 fix(printer): avoid panic on non-builtin static/vtable alloc pointers
⌽ rebase/codex/svta-fb test(integration): cover static and vtable fallback behaviorTwo commits, linear, each doing one thing. The fix is to rebase instead of merge when you need to pick up upstream changes: git fetch origin
git rebase origin/masterThis replays your commits on top of the latest master, so your branch stays a clean, linear sequence of just your work. If there are conflicts, you resolve them inline during the rebase (same conflict resolution, just applied differently), and the result is a branch where every commit is yours. One thing that makes rebasing less painful: enable The first setting tells git to record every conflict resolution you make. The second automatically stages the re-applied resolution (without it, One caveat: rebasing rewrites commit hashes, so if you've already pushed the branch remotely, you'll need |
|
Hi @cds-amal ! Thank you for sharing these things. I'll use rebase to make it easy to review. |
9d8015c to
2d83f3f
Compare
2d83f3f to
f2a751e
Compare
dkcumming
left a comment
There was a problem hiding this comment.
Nice! Love the teamwork @Stevengre @cds-amal - I think we can do a bit of a common functionality refactor by the look of things but let's get this in so it unblocks that aspect of your SPL proofs Jianhong
- [stable-mir-json PR 122](https://github.com/runtimeverification/stable-mir-json/pull/122/changes#diff-f3fb88e143d9d90b06c9086e1c660a3e28674c1c1cebf1870de06d73156e3d54R413-R416) Added `Dyn` which needed corresponding K and python productions added to AST - [stable-mir-json PR 129](runtimeverification/stable-mir-json#129) or [131](runtimeverification/stable-mir-json#131) changes closures which do not have corresponding K updates in this PR, proofs `and_then_closure` and `closure_acces_struct` are regressed to failing for now with semantics for correct usage expected to come after merging --------- Co-authored-by: devops <devops@runtimeverification.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Daniel Cumming <124537596+dkcumming@users.noreply.github.com> Co-authored-by: dkcumming <daniel.cumming@runtimeverification.com>
This is a follow-up to #131. That PR fixed a real panic (non-builtin-deref Static/VTable allocations), but the fix landed as three nearly identical match arms: Static, VTable, and Function, each repeating the same "try `get_prov_ty`, fall back to opaque placeholder" logic. The only meaningful difference between them was a single predicate ("is this type usable directly?") and the debug log string. This PR collapses them back into one arm, makes the predicate explicit, and documents a previously unexplained jq filter. ## What changed **`src/printer/mir_visitor.rs`** The three arms now share a single code path. The predicate that actually differs between them is captured in a `needs_recovery` variable: - Static/VTable: `builtin_deref(true).is_none()` (not a reference, raw pointer, or Box) - Function: `!kind.is_fn_ptr()` (outer type isn't already a function pointer) Worth noting: these two predicates are *not* equivalent (a function pointer passes `builtin_deref` but fails `is_fn_ptr`), which is why a naive "just combine the arms" without the inner match would have changed behavior for Function allocs. The inner match on `global_alloc` makes this asymmetry visible rather than hiding it across separate arms. The rest of the logic (try `get_prov_ty`, fall back to opaque placeholder) is written once. Also dropped an unnecessary `.clone()` on the `builtin_deref` call; it takes `&self`. **`tests/integration/normalise-filter.jq`** The `def_id` filter had a terse comment ("unrelated to this regression") that didn't explain *why* it exists or why it's safe to strip globally. Replaced it with a proper explanation: `def_id` values are interned compiler indices (same class as `alloc_id` and `adt_def`) that are consistent within a single rustc invocation but non-deterministic across runs. Downstream consumers need them as cross-reference keys to join `AggregateKind::Adt` in MIR bodies with type metadata entries, so they can't be dropped from the output itself; we only strip them here for golden-file comparison. (See #125 for the full picture on interned-index non-determinism.) ## Test plan - [ ] `cargo build` compiles cleanly - [ ] `make integration-test` passes (no behavioral change; this is a pure refactor)
Summary
src/printer.rs,collect_allocno longer panics on non-builtin_derefGlobalAlloc::Static/GlobalAlloc::VTablepaths.get_prov_ty(ty, offset)first, and falls back to opaqueTy::to_val(0)when recovery is not possible.builtin_derefpointer/reference paths is unchanged.tests/integration/programs/static-vtable-nonbuiltin-deref.rstests/integration/programs/static-vtable-nonbuiltin-deref.smir.json.expectedtests/integration/normalise-filter.jq(strip unstabledef_id).Context
This PR was split from stable-mir-json#129 so
#129can stay focused on closure type-table metadata.The failure mode here was assert-based panic in pre-fix code when a provenance edge reached
Static/VTablethrough a non-builtin_derefcontainer type.Testing
Automated (local):
origin/master):make integration-test TESTS=tests/integration/programs/static-vtable-nonbuiltin-deref.rsAllocated pointer is not a built-in pointer typepanic atsrc/printer.rs:789.make integration-test TESTS=tests/integration/programs/static-vtable-nonbuiltin-deref.rs✅make integration-test TESTS=tests/integration/programs/assert_eq.rs✅cargo +nightly-2024-11-29 fmt --check✅cargo +nightly-2024-11-29 clippy -- -Dwarnings✅GitHub checks:
11180ceis in progress.