Skip to content

Rebase mined getter invariants onto the receiver's field path - #5087

Open
wodex1nhaoIeng wants to merge 1 commit into
model-checking:mainfrom
wodex1nhaoIeng:codex/fix-5011-nested-getter
Open

wodex1nhaoIeng wants to merge 1 commit into
model-checking:mainfrom
wodex1nhaoIeng:codex/fix-5011-nested-getter

Conversation

@wodex1nhaoIeng

@wodex1nhaoIeng wodex1nhaoIeng commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

--check-invariants checked the wrong field when an invariant was mined through a getter called on a field of self. In #5011, Outer::first asserts self.inner.valid(), and Inner::valid checks self.count > 0. The miner accepted &self.inner as if it were &self, then read the callee's self.count (field 0 of Inner) as field 0 of Outer, which is decoy. The mined invariant became decoy > 0, so make_valid failed and make_invalid passed: the opposite of the correct verdicts.

The getter's receiver can now be self or any field path under it. The miner records the field path from the caller's self to the receiver and prepends it to the expression mined from the callee, so Inner::valid turns into self.inner.count > 0 on Outer. Nested getters compose, since each level rebases onto its own caller. Receivers this AST can't express (a deref below a field, or a downcast under the prefix) make the miner skip the conjunct instead of guessing.

One shape that isn't explicitly guarded against: a receiver field that is itself a reference or Box, where the prefix would end at a pointer-typed field. On the current toolchain it can't reach the miner. rustc passes self.r through a reborrowed temp, which isn't rooted at self, and a Box deref lowers to BoxDerefTransmute, which the extractor rejects. I left it at that rather than adding a guard for MIR that isn't produced today.

Resolves #5011

The regression test script-based-pre/autoharness_nested_getter is the reproducer from the issue plus a two-level receiver (Deep.outer.inner). It fails on main and passes with this change. All 43 autoharness tests in script-based-pre pass, and rustfmt --check is clean on the changed file.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

Mining a getter call such as `self.inner.valid()` treated `&self.inner` as
`&self`, so the callee's field reads (e.g. `self.count`, field 0 of `Inner`)
were interpreted as fields of the outer type. Compute the field path from the
caller's `self` to the getter receiver and prepend it to the callee's mined
expression; bail out on projections the expression AST cannot represent.

Resolves model-checking#5011

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wodex1nhaoIeng
wodex1nhaoIeng requested review from a team as code owners October 28, 2026 05:16
@github-actions github-actions Bot added Z-EndToEndBenchCI Tag a PR to run benchmark CI Z-CompilerBenchCI Tag a PR to run benchmark CI labels Oct 28, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Z-CompilerBenchCI Tag a PR to run benchmark CI Z-EndToEndBenchCI Tag a PR to run benchmark CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Invariant mining checks the wrong field when calling a getter on a nested struct

1 participant