Traverse types once when relating them invariantly - #254
Merged
Conversation
Relating two types invariantly was expressed as subtyping in both directions, which walks the whole type structure twice. Each owning or mutable pointer nested inside relates its referent invariantly again, so the number of clauses emitted for a refinement doubled per pointer layer above it: the eight identical clauses per basic block edge in a `&mut self` method over `Option<i32>` come from three such layers. The two directions do not derive different constraints. Relating types invariantly is symmetric, and every position below an owning or mutable pointer is related invariantly again, so the second direction re-derives the constraints of the first. Relate types in a single traversal carrying the relation to derive, emitting both implications where the refinements must agree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PEtrgExrszb8aBUEGASPeE
coord-e
force-pushed
the
claude/reduce-duplicate-clauses-br7c8m
branch
from
September 2, 2026 12:39
7d49aaf to
4415027
Compare
coord-e
marked this pull request as ready for review
September 2, 2026 12:41
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The refactor preserves relation semantics while eliminating redundant recursive traversals.
Pull request overview
Optimizes invariant type relations by traversing type structures once while preserving bidirectional refinement constraints.
Changes:
- Introduces explicit
SubandEqualrelation modes. - Propagates invariance through owning and mutable pointers.
- Removes the unused equality method from
Subtyping.
File summaries
| File | Description |
|---|---|
src/rty/subtyping.rs |
Consolidates subtype and equality traversal to prevent duplicated clauses. |
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 0
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
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.
Relating two types invariantly was expressed as subtyping in both directions:
relate_sub_refined_typewalks the whole type structure, so this traverses it twice, and every owning or mutable pointer found inside relates its referent invariantly again. The number of clauses emitted for a refinement therefore doubles per pointer layer above it.The two directions do not derive different constraints. Writing
Sforrelate_sub_refined_type,Eforrelate_equal_refined_typeandRforrelate_sub_type:Eis symmetric by its definition, soE(own X, own Y)containsE(X,Y)andE(Y,X)— the same multiset twice. The direction only distinguishes anything at a covariant position, and every position below an owning or mutable pointer is invariant again, so the second direction just re-derives the constraints of the first.This walks the type once, carrying the relation to derive, and emits both implications at the positions where the refinements must agree.
Effect
Measured on a
&mut selftrait method overOption<i32>(own (&mut (own Option<{int | p3}>, )), three such pointer layers), and on the same program with one more struct nesting:Both had 12 distinct clauses throughout. The count no longer grows with nesting depth. No change on the existing UI tests' output, which do not nest pointers above a refinement.
Two duplicates remain in that example, of the form
p3 v <= ... /\ p3 v: both sides of an invariant position happen to carry the same predicate variable, so the two implications coincide. That is inherent to relating a position invariantly and is bounded by 2 regardless of depth. Dropping those would mean treating a clause whose head occurs in its own body as a nop, which needsPartialEqonAtom/Term/Formula; left out of this change.Other changes
relate_equal_refined_typehad no callers outside this module once the recursion stopped going through it, so it is dropped from theSubtypingtrait.Testing
cargo test(334 UI tests + unit and doc tests),cargo clippy -- -D warnings,cargo fmt --check.🤖 Generated with Claude Code
https://claude.ai/code/session_01PEtrgExrszb8aBUEGASPeE
Generated by Claude Code