Skip to content

majit: fail the slice-index block-alias resolver closed on a non-variable incoming argument - #1133

Merged
youknowone merged 1 commit into
mainfrom
residual
Aug 10, 2026
Merged

majit: fail the slice-index block-alias resolver closed on a non-variable incoming argument#1133
youknowone merged 1 commit into
mainfrom
residual

Conversation

@youknowone

@youknowone youknowone commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Follow-up to #1124, acting on its Codex parity review. §2 is fixed here; §1 is answered with a test
rather than a code change; §3 is out of scope.

Fixed (§2): resolve_block_alias discarded non-variable incoming arguments

.filter_map(|link| link.args.get(arg_index).and_then(LinkArg::as_variable).cloned())

filter_map drops an incoming argument that is not a variable instead of treating it as a
disagreement. A block input fed [Variable(v), Constant(7)] collapsed to [v], the "all incoming
agree" check passed, and the phi resolved to v's root — so the resolver could equate two values
that are not equal on all paths. The static-length proof relies on this resolver for the
receiver/ArrayLen base identity, and the runtime helper ll_listslice_startstop clamps rather than
panicking, so a false alias is a silent wrong-length slice, not a crash. resolve_block_alias did
not exist before #1124.

The fix collects into Option<Vec<Variable>>, so the first non-variable argument short-circuits the
collection and incoming? returns None.

Links out of blocks not reachable from startblock cannot execute, so they are excluded from the
walk rather than allowed to veto a resolution. reachable_from_start is lifted out of
array_len_base_is_stable and shared; the set is computed once and threaded through the recursion.

Not fixed (§1): the end field write keeps requiring the "end" spelling

The review notes that range_feeds_only_index matches the end field write as
field.name == "end", while the aggregate lowering names that write __pos_<i> when the resolver
cannot project a schema entry — so a RangeTo, whose single operand is at index 0, is spelled
__pos_0 and the end_writes == 1 gate declines it.

The code reading is right; the conclusion that #1124 narrowed a rewrite the older code performed does
not follow. is_construction_write has never keyed on the field name and still does not — the
end_writes gate only requires the write to be unique and named. #1124 also added
resolve_block_alias, which widened which sites are recognised at all. So widening the gate to
__pos_0 would not restore an earlier rewrite; it would admit sites that only the new alias
resolution makes visible. It was implemented and measured, and cleared no additional prepass subject,
so it is not included. A test pins the decline with that reasoning in its doc comment.

Verification

  • front::slice_index 34 passed / 0 failed; full lib 3170 passed / 0 failed / 33 ignored; the
    --ignored anchor 2 passed / 0 failed; cargo fmt --check clean.
  • All three new tests verified by mutation: reverting the behaviour under test makes each fail.
  • Three-stream prepass census (phaseA annotate / phaseB rtype / PYRE_RTYPER skip), working tree vs.
    this base: NEWLY BAD 0 / 0 / 0, NEWLY GOOD 0 / 0 / 0.

A measurement caveat worth recording

While validating the above I found that the census is not stable for one row,
pyre_interpreter::display::<Impl>::push_onto: on a byte-identical tree it scored phaseB 15 once
and phaseB 14 eight times across independent runs (fresh --force LLBC extraction, fresh build,
and a full re-run of the A/B harness). A single-observation 1-subject delta on that row is therefore
not evidence either way, and any earlier claim in this fold's history that rests on it — in either
direction — should be re-measured with at least two independent arm runs before being relied on.

Summary by CodeRabbit

  • Bug Fixes

    • Improved block alias resolution by ignoring inputs from unreachable predecessors.
    • Prevented incorrect aliasing when reachable inputs are mixed or non-variable.
    • Improved handling of positional range-end writes and unreachable predecessor constants.
  • Tests

    • Added coverage for mixed variable and constant inputs, positional range-end writes, and unreachable paths.

…able incoming argument

`resolve_block_alias` collected the incoming link arguments of a block input
with `filter_map` and `LinkArg::as_variable`, discarding an argument that is not
a variable instead of treating it as a disagreement. A block input fed
`[Variable(v), Constant(7)]` collapsed to `[v]`, the "all incoming agree" check
passed, and the phi resolved to v's root, so the resolver could equate two
values that are not equal on all paths. Collect into `Option<Vec<Variable>>`
instead: the first non-variable argument short-circuits the collection and
`incoming?` returns None.

Links out of blocks not reachable from `startblock` cannot execute, so they are
excluded from the walk rather than allowed to veto a resolution.
`reachable_from_start` is lifted out of `array_len_base_is_stable` and shared,
and the set is computed once and threaded through the recursion.

The positional `__pos_0` spelling of the `RangeTo.end` field write stays
rejected, recorded by a test: `is_construction_write` does not key on the field
name, so widening the `end_writes` gate to `__pos_0` admits sites that only
`resolve_block_alias` makes visible rather than restoring an earlier rewrite.

Assisted-by: Claude
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9c69e5f1-7490-432b-8d1e-5dd921be2a5d

📥 Commits

Reviewing files that changed from the base of the PR and between 8e3ed93 and a92ee7c.

📒 Files selected for processing (1)
  • majit/majit-translate/src/front/slice_index.rs

Walkthrough

The translator now resolves block aliases using only reachable predecessors. It rejects mixed or conflicting reachable inputs, reuses reachability analysis for stability checks, and adds RangeTo tests for positional fields and unreachable constants.

Changes

Reachability-aware slice alias resolution

Layer / File(s) Summary
Reachability-aware alias and stability analysis
majit/majit-translate/src/front/slice_index.rs
A shared helper computes reachable blocks. Alias resolution ignores unreachable predecessors and rejects non-variable or conflicting reachable inputs. Stability analysis reuses the helper.
RangeTo test coverage
majit/majit-translate/src/front/slice_index.rs
Test builders accept configurable RangeTo field names. Tests cover positional end writes, mixed reachable inputs, and constants from unreachable predecessors.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Poem

A rabbit checks each path with care,
And skips the blocks that lead nowhere.
Mixed inputs make the rewrite wait,
While reachable clues decide its fate.
RangeTo tests hop through the code—
Clean aliases lighten every load.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: making the slice-index block-alias resolver fail closed for non-variable incoming arguments.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch residual

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit a92ee7c).
Updated: 2026-08-10T00:06:00.355Z

Files in the reviewed diff
majit/majit-translate/src/front/slice_index.rs

1. Regressions to PyPy parity introduced by this patch

None.

2. Other mismatches introduced by this patch

None.

3. Pre-existing mismatches (already present before this patch)

None.

4. Structural adaptations

  • majit/majit-translate/src/front/slice_index.rs:376-387 ↔ rpython/flowspace/model.py:78-88 — Rust must explicitly compute reachability while iterating its flat graph.blocks; upstream FunctionGraph.iterlinks() inherently traverses only from startblock. The new reachable_from_start filter restores that upstream traversal scope.

  • majit/majit-translate/src/front/slice_index.rs:414-426 ↔ rpython/flowspace/model.py:114-117, 694-697Link.args may contain either a variable or constant. The new Option<Vec<_>> rejects a reachable constant incoming value rather than silently dropping it and proving a false variable-only alias. This is a conservative Rust-side CFG/SSA adaptation; it does not change PyPy slice semantics.

@youknowone
youknowone merged commit eba1223 into main Aug 10, 2026
13 of 17 checks passed
@youknowone
youknowone deleted the residual branch August 10, 2026 01:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant