Skip to content

traits: Use a placeholder self type for escaping dyn principals in WF#157280

Open
Dnreikronos wants to merge 2 commits into
rust-lang:mainfrom
Dnreikronos:existential_trait_ref_escaping_bound_vars_assert
Open

traits: Use a placeholder self type for escaping dyn principals in WF#157280
Dnreikronos wants to merge 2 commits into
rust-lang:mainfrom
Dnreikronos:existential_trait_ref_escaping_bound_vars_assert

Conversation

@Dnreikronos
Copy link
Copy Markdown
Contributor

@Dnreikronos Dnreikronos commented Jun 2, 2026

Fixes #157122

WF-checking walks through higher-ranked binders without instantiating them, so a dyn Trait nested in a for<'a> bound reaches the ty::Dynamic arm of WfPredicates::visit_ty while it still carries escaping bound vars. That type got handed to ExistentialTraitRef::with_self_ty, and its debug_assert!(!self_ty.has_escaping_bound_vars()) fired while building the standard library. The assert was turned back on recently after sitting commented out since a 2018 refactor.

The trait ref built there only exists to read off ConstArgHasType clauses, which constrain the trait's own const arguments and never mention Self. So when the real self type escapes, swap in a fresh placeholder. The assert holds and the const-argument check still runs.

Skipping the block when t escapes was my first attempt, since it mirrors the guard on the projection bounds right below it. It's wrong. Skipping drops the ConstArgHasType obligation, so an ill-typed const argument on a dyn nested in an HRTB compiles clean when it should error. The sibling check in check.rs only runs for type aliases, not fn params, so nothing else catches it. The second regression test pins that down.

A binder-based fix doesn't work here either. You'd want to instantiate the escaping vars with placeholders or rebind the obligation under t's binder, but t is a bare Ty, not a Binder. Its escaping vars are bound by an ancestor the visitor already walked past, since WfPredicates overrides visit_ty and visit_const but not visit_binder. There's no binder in hand to instantiate. The placeholder gets around that: the clauses we keep don't care about the self type, so a stand-in is enough.

The placeholder-self-type trick is the same one the pretty-printer uses for existential principals.

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 2, 2026

changes to the core type system

cc @lcnr

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 2, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 2, 2026

r? @mejrs

rustbot has assigned @mejrs.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 73 candidates
  • Random selection from 17 candidates

WF-checking walks through higher-ranked binders without instantiating
them, so a `dyn Trait` nested inside a `for<'a>` bound reaches the
`ty::Dynamic` arm of `WfPredicates::visit_ty` while still carrying
escaping bound vars. Feeding that type into
`ExistentialTraitRef::with_self_ty` violated its no-escaping-self
precondition and tripped the assertion that guards it.

The trait ref built there is only used to read off `ConstArgHasType`
clauses, which constrain the trait's own const arguments and never
mention the `Self` type. Substitute a fresh placeholder self type when
the real one escapes: the assertion holds and the const-argument check
is still performed. Re-enable the `with_self_ty` debug assertion now
that its precondition is upheld.
One test covers the original ICE (a `dyn Trait` nested in a `for<'a>`
bound, distilled from itertools). The other locks in that a const
argument on such a nested `dyn` is still type-checked, so the
placeholder-self-type fix cannot silently regress into dropping the
`ConstArgHasType` check.
@Dnreikronos Dnreikronos force-pushed the existential_trait_ref_escaping_bound_vars_assert branch from 87f6783 to 0676d4a Compare June 2, 2026 02:49
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 2, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@mejrs
Copy link
Copy Markdown
Contributor

mejrs commented Jun 2, 2026

I'm not confident reviewing this.

r? @fmease perhaps?

@rustbot rustbot assigned fmease and unassigned mejrs Jun 2, 2026
@Dnreikronos
Copy link
Copy Markdown
Contributor Author

I'm not confident reviewing this.

r? @fmease perhaps?

Hi, @mejrs!
I'm not 100% confident that this implementation that I did it's the best approach as possible to solve the problem. So I'm totally open/available to discuss about it

@mejrs
Copy link
Copy Markdown
Contributor

mejrs commented Jun 2, 2026

Oh it's not about what and how you implemented this, I'm very unfamiliar with this part of the compiler so I'm ill-suited to review PRs touching it.

@oli-obk oli-obk added T-types Relevant to the types team, which will review and decide on the PR/issue. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-types Relevant to the types team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ExistentialTraitRef::with_self_ty gets called with escaping bound vars since a few months ago

5 participants