Repository navigation
Conversation
This was referenced Jun 28, 2026
coord-e
force-pushed
the
claude/pr-154-mergeable-vt1l0f
branch
5 times, most recently
from
July 2, 2026 04:54
12b6c5f to
43aaebb
Compare
coord-e
force-pushed
the
claude/pr-154-mergeable-vt1l0f
branch
2 times, most recently
from
July 8, 2026 10:55
e5b8321 to
4c88826
Compare
coord-e
force-pushed
the
claude/pr-154-mergeable-vt1l0f
branch
2 times, most recently
from
August 9, 2026 02:34
cd98f92 to
a87b28e
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes prophecy double-resolution when partially moved locals are dropped.
Changes:
- Tracks moved sub-places as drop exceptions.
- Skips excepted paths during drop-formula generation.
- Adds pass/fail regression coverage for local, call, and sibling cases.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/analyze/basic_block/drop_point.rs |
Collects moves and builds exception-aware drop sets. |
src/analyze/basic_block.rs |
Applies drop sets during block analysis. |
src/analyze/local_def.rs |
Propagates lifetime-aware drop-point types. |
src/refine/env.rs |
Skips moved paths while generating drop formulas. |
tests/ui/pass/partial_move_drop.rs |
Tests a valid local partial move. |
tests/ui/fail/partial_move_drop.rs |
Rejects the unsound local variant. |
tests/ui/pass/partial_move_field_call.rs |
Tests a valid field move into a call. |
tests/ui/fail/partial_move_field_call.rs |
Rejects the unsound call variant. |
tests/ui/pass/partial_move_sibling.rs |
Tests correct sibling prophecy resolution. |
tests/ui/fail/partial_move_sibling.rs |
Guards against double-resolution with a sibling. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This was referenced Aug 29, 2026
A local with a partial field move (e.g. `move (_2.0)`) was still dropped wholesale, so dropping it walked into the moved-out sub-place and resolved the `&mut` prophecy it owns a second time. The two resolutions contradict, making the clause body unsatisfiable, after which any assertion -- including false ones -- "verifies" (#121, #122). `Moves::collect` gathers all non-reference `move`d operands in one body traversal: whole-local moves (keyed by location, where the local also dies) and, keyed by parent local, the partial field moves. `DropSet { drops, except }` carries, per drop point, the whole locals to drop plus the moved-out sub-places to skip. A dying local is dropped whole, but its partial-move sub-places are passed to the drop as `except`: the drop walk resolves the still-owned siblings and skips the moved-out subtrees (resolved at the move destination), so the fix is both sound and complete. Drop targets stay whole locals; the closure environment restored by `RustCallVisitor` reaches its drop through a projection-less temporary. `Env::dropping_formula_for_term` threads the drop-walk `path` and `except` alongside the type/term walk and returns early on any subtree matching an excepted path. The moved-out places are elaborated to the walk's form via `Env::elaborated_path`, which inserts the `own`-box `Deref`s the type elaboration introduces (mut/reborrowed locals, and every tuple field) so the comparison lines up exactly -- without this a partially-moved local that gets box-elaborated (e.g. when a sibling is mutated through) would not be skipped, and the false assertion would verify vacuously. Adds regression tests: the two original shapes (#121, #122), plus a partially-moved local with a still-owned sibling (completeness) and a soundness guard where the moved part is used and the sibling is reborrowed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A3zd4nCdz5atbgNuqXEJTc
coord-e
force-pushed
the
claude/pr-154-mergeable-vt1l0f
branch
from
September 28, 2026 10:51
a87b28e to
45a0927
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #121 and #122. Supersedes #124.
Dropping an aggregate after moving out a field can resolve that field's mutable-borrow prophecy twice. Contradictory resolutions can make false assertions verify. The drop must resolve only the parts still owned at that point on that execution path: a field moved in one branch remains owned in the other, and assigning a value back restores its drop obligation.
Implementation
DropSet { drops, except }: drop targets are whole locals, and exclusions are moved-out MIR places. Include a parent local in the drop candidates after a direct field assignment. Whole-local move suppression remains keyed by the move's location.Boxdereferences and inserting only the synthetic ownership dereferences. Match those paths against the refined type's drop traversal, including enum downcasts, to skip moved-out subtrees while resolving still-owned siblings.Validation
thrust-fptprove-wrapper. They cover moves into locals and calls, siblings, conditional moves, field/parent/local reinitialization, enum payloads, loops with invariants, call-return initialization, sequential conditionals, and moves throughBoxvalues and boxed fields. Pass/fail pairs check both successful verification and rejection of false assertions.thrust-fptprove-wrapperand a 180-second default solver limit, 409 UI tests pass; the two known timeout cases are excluded. The pass and fail variants ofslice_split_first_mut_loop.rspreviously timed out even with a 180-second limit. Their generated SMT constraints remain byte-for-byte identical before the ownership-tracking changes, after those changes, and after theBoxfix. These two cases remain unverified; the entire 411-test suite is not reported as green.cargo fmt --all -- --check,cargo clippy -- -D warnings, andgit diff --checkpass.Boxdereferences. No additional findings remained in their final reviews.Existing limitation
Writing through a field after reinitialization, for example
let t = s.0; s.0 = t; *s.0.0 = 10;, can still panic withderef unbound var. This reproduces both before and after these changes and is separate from restoring the drop obligation.