Skip to content

fix: Off-by-one in lifetime binders when lowering dyn Trait<'a> - #23107

Merged
ChayimFriedman2 merged 1 commit into
rust-lang:masterfrom
Wilfred:fix-empty-bound-vars-binder
Aug 11, 2026
Merged

fix: Off-by-one in lifetime binders when lowering dyn Trait<'a>#23107
ChayimFriedman2 merged 1 commit into
rust-lang:masterfrom
Wilfred:fix-empty-bound-vars-binder

Conversation

@Wilfred

@Wilfred Wilfred commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

dyn Trait<'a> does not have an explicit for<'a>, but it still has a binder. If we don't call with_shifted_in(), we end up with lifetimes whose de Bruijn index points to the wrong level.

This could cause r-a to refer to the wrong lifetime variable, or even panic when the enclosing binder doesn't declare a lifetime variable. See the new unit test.

This bug meant r-a would previously crash when generating a SCIP file for the dachshund crate.

AI disclosure: Code partly written by GPT-5, all comments, commit messages and mistakes are mine.

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 10, 2026
@Wilfred

Wilfred commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

I'm hesitant to merge this since I fear this will collide with the lifetime elision work. CC @dfireBird.

let db = self.db;
self.lower_type_bound(b, dummy_self_ty, false).for_each(|(b, _)| {
let clauses: Vec<_> = match b {
TypeBound::Path(_, TraitBoundModifier::None) => {

@Wilfred Wilfred Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm understanding #22927 correctly, I think this can change to TypeBound::Path(None, _, TraitBoundModifier::None) => if that PR merges first. I think the PRs are strictly complementary.

View changes since the review

@dfireBird

Copy link
Copy Markdown
Member

I think this would be fine to merge. Thanks for catching this.

Comment thread crates/hir-ty/src/lower.rs Outdated
TypeBound::Path(_, TraitBoundModifier::None) => {
// `dyn Trait<'a>` is an existential predicate that introduces a binder.
self.with_shifted_in(&[], |ctx| {
ctx.lower_type_bound(b, dummy_self_ty, false).collect()

@ChayimFriedman2 ChayimFriedman2 Aug 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the extra collect(). You can avoid it by extracting the for_each into a named closure and doing it in both arms,

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored to a match that returns an iterator.

`dyn Trait<'a>` does not have an explicit `for<'a>`, but it still has
a binder. If we don't call with_shifted_in(), we end up with lifetimes
whose de Bruijn index points to the wrong level.

This could cause r-a to refer to the wrong lifetime variable, or even
panic when the enclosing binder doesn't declare a lifetime
variable. See the new unit test.

This bug meant r-a would previously crash when generating a SCIP file
for the dachshund crate.

AI disclosure: Code partly written by GPT-5, all comments, commit
messages and mistakes are mine.
@Wilfred
Wilfred force-pushed the fix-empty-bound-vars-binder branch from a59cd0b to 5c18792 Compare August 11, 2026 10:41
@ChayimFriedman2
ChayimFriedman2 added this pull request to the merge queue Aug 11, 2026
Merged via the queue into rust-lang:master with commit f571919 Aug 11, 2026
18 checks passed
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 11, 2026
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.

4 participants