Skip to content

Track drop points by MIR Place, splitting partially-moved locals (fix #121, #122)#155

Draft
coord-e wants to merge 2 commits into
mainfrom
claude/pr-154-mergeable-vt1l0f
Draft

Track drop points by MIR Place, splitting partially-moved locals (fix #121, #122)#155
coord-e wants to merge 2 commits into
mainfrom
claude/pr-154-mergeable-vt1l0f

Conversation

@coord-e

@coord-e coord-e commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Supersedes #154 and #124. Fixes #121 and #122.

Motivation

Description

  • DropPoints is generic over the MIR lifetime and stores mir::Place<'tcx> in before_statements, after_statements, after_terminator, and after_terminator_extra. Liveness-derived Local sets are converted to Places in the builder, and the basic-block Analyzer routes all implicit-drop handling through drop_place/drop_after_terminator working on mir::Place<'tcx>.
  • The fix lives in the drop-point production, not the env drop-walk. partial_moves collects the sub-places moved out of each local somewhere in the body; expand_owned_places then splits a to-be-dropped local along its type into the maximal still-owned sub-places, carving out moved-out subtrees while still dropping their owned siblings. A wholly-moved place expands to nothing; a place with no moved-out descendant is emitted whole (preserving prior behavior). Reference-typed moves are left in place, since ReborrowVisitor/RustCallVisitor turn them into reborrows and the source keeps owning its prophecy.
  • Drop-point places are collected into HashSet instead of Vec, removing the manual dedup bookkeeping.

Testing

🤖 Generated with Claude Code


Generated by Claude Code

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).

Produce correct drop points instead of patching the env drop-walk:

- `DropPoints` stores a `PlaceSet { locals, places }` per position, so
  whole-local drops -- the common case -- stay as bare `Local`s and only
  genuinely place-granular drops (closure environments) are tracked as
  `Place`s. The analyzer drops through a single `drop_place_set` helper.

- `Moves::collect` gathers all non-reference `move`d operands in one body
  traversal: whole-local moves (keyed by location, where the local also dies,
  for the per-statement drop-set subtraction) and the set of locals with a
  partial field move. A partially-moved local stays live until its remaining
  parts die later, so dropping it wholesale at that point would re-resolve the
  moved-out sub-place's prophecy; it is excluded from dropping entirely.
  Reference-typed moves are skipped: reborrows keep the source owning its
  prophecy.

Adds regression tests for both shapes (partial move into a local, and a
`&mut`-bearing field moved into a call).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NU1g7aHMxcSEZgeKProDr1
@coord-e coord-e force-pushed the claude/pr-154-mergeable-vt1l0f branch from e2f735e to 440988e Compare June 29, 2026 01:44
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.

Unsoundness: partially-moved locals are still implicitly dropped, resolving prophecies of moved-out &mut borrows

2 participants