Skip to content

borrowck: Normalize non-rigid aliases in NLL type relating - #161012

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
Dnreikronos:borrowck/normalize_nll_aliases
Aug 27, 2026
Merged

borrowck: Normalize non-rigid aliases in NLL type relating#161012
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
Dnreikronos:borrowck/normalize_nll_aliases

Conversation

@Dnreikronos

@Dnreikronos Dnreikronos commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

View all comments

Fixes #160652

With -Znext-solver=globally, yielding from an impl Iterator without an explicit Item bound ICEs in borrowck. The coroutine defining type returned by type_of is unnormalized, so its yield type remains <impl Iterator as Iterator>::Item. Skipping normalization propagates that non-rigid alias into both MIR's CoroutineInfo and borrowck's UniversalRegions; NLL type relating then hits its invariant that non-rigid aliases must already have been normalized.

Deeply normalize the instantiated defining type when MIR construction creates CoroutineInfo and when borrowck reconstructs DefiningTy. That makes the coroutine yield and resume types rigid before NLL compares them.

This is intentionally gated to the next solver. The old solver keeps the existing skip-normalization path because deeply normalizing defining types there causes regressions.

@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. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels Aug 13, 2026
@rustbot

rustbot commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

r? @camelid

rustbot has assigned @camelid.
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: borrowck, compiler
  • borrowck, compiler expanded to 75 candidates
  • Random selection from 17 candidates

@adwinwhite

Copy link
Copy Markdown
Contributor

r? me

We really shouldn't have non-rigid aliases here. I would guess that we lack a normalization call earlier, likely yield_ty in construct_fn.

@rustbot rustbot assigned adwinwhite and unassigned camelid Aug 13, 2026
@Dnreikronos

Dnreikronos commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Imo we really shouldn't have non-rigid aliases in NLL relating. You were right, copying that into relate_tys was tempting and it's the wrong move. Dropping it.

construct_fn was the right guess for body.yield_ty. Writeback leaves <impl Iterator as Iterator>::Item on it sometimes. Normalizing makes the alias rigid, which is what stops the span-bug. Fyi dumps can still print the projection.

That still doesn't cover the ICE though. It's sub_types(value.ty(), yield_ty) and value.ty() is the local i, still a non-rigid alias. universal_regions.yield_ty comes off defining_ty unnormalized, same as unnormalized_output_ty.

So I'm also normalizing the operand at the Yield terminator and the defining_ty yield in equate_inputs_and_outputs. Next-solver only. Btw not touching resume_ty, this bug is yield.

Idk if this is the long-term answer once next-solver is default irl. Maybe NLL just grows real lazy norm later. Pushing asap, ltm if you'd rather I skip the operand/defining_ty bits.

@oli-obk

This comment was marked as resolved.

@oli-obk oli-obk closed this Aug 13, 2026
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 13, 2026
@oli-obk oli-obk reopened this Aug 13, 2026
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 13, 2026
Comment thread compiler/rustc_mir_build/src/builder/mod.rs Outdated
Comment thread compiler/rustc_borrowck/src/universal_regions.rs Outdated
Comment thread compiler/rustc_mir_build/src/builder/mod.rs Outdated
Comment thread compiler/rustc_mir_build/src/builder/mod.rs
Comment thread compiler/rustc_mir_build/src/builder/mod.rs Outdated
@adwinwhite

Copy link
Copy Markdown
Contributor

Sorry for the delay :>

@adwinwhite adwinwhite added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 24, 2026
@Dnreikronos

Copy link
Copy Markdown
Contributor Author

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 24, 2026
@Dnreikronos

Copy link
Copy Markdown
Contributor Author

Sup, @adwinwhite!
I've made the adjustments. Can you re-validate, please?

@adwinwhite adwinwhite left a comment

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.

Comment thread compiler/rustc_borrowck/src/universal_regions.rs Outdated
Comment thread compiler/rustc_mir_build/src/builder/mod.rs Outdated
Comment thread compiler/rustc_mir_build/src/builder/mod.rs Outdated
Comment thread compiler/rustc_borrowck/src/universal_regions.rs Outdated
@Dnreikronos

Copy link
Copy Markdown
Contributor Author

Ha, good nits. All four applied, answered each one inline.

@adwinwhite

Copy link
Copy Markdown
Contributor

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Aug 26, 2026
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Aug 26, 2026
…=<try>

borrowck: Normalize non-rigid aliases in NLL type relating
@Dnreikronos
Dnreikronos force-pushed the borrowck/normalize_nll_aliases branch from 1e47fcc to f8dd6a8 Compare August 26, 2026 12:57
@Dnreikronos

Dnreikronos commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Unfortunately the old solver does have some regressions. Let's add the old solver early skip back. Sorry for the back and forth. And please update the PR description and squash the commits. Thanks! @rustbot author

Sup, @adwinwhite :)

I think I addressed what you want. can you re-validate, please?

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 26, 2026
@rust-log-analyzer

This comment has been minimized.

@Dnreikronos
Dnreikronos force-pushed the borrowck/normalize_nll_aliases branch from f8dd6a8 to 2701241 Compare August 26, 2026 14:04
@adwinwhite

Copy link
Copy Markdown
Contributor

@bors r+ rollup

@rust-bors

rust-bors Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 2701241 has been approved by adwinwhite

It is now in the queue for this repository.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 27, 2026
jhpratt added a commit to jhpratt/rust that referenced this pull request Aug 27, 2026
…_aliases, r=adwinwhite

borrowck: Normalize non-rigid aliases in NLL type relating

Fixes rust-lang#160652

With `-Znext-solver=globally`, yielding from an `impl Iterator` without an explicit `Item` bound ICEs in borrowck. The coroutine defining type returned by `type_of` is unnormalized, so its yield type remains `<impl Iterator as Iterator>::Item`. Skipping normalization propagates that non-rigid alias into both MIR's `CoroutineInfo` and borrowck's `UniversalRegions`; NLL type relating then hits its invariant that non-rigid aliases must already have been normalized.

Deeply normalize the instantiated defining type when MIR construction creates `CoroutineInfo` and when borrowck reconstructs `DefiningTy`. That makes the coroutine yield and resume types rigid before NLL compares them.

This is intentionally gated to the next solver. The old solver keeps the existing skip-normalization path because deeply normalizing defining types there causes regressions.
rust-bors Bot pushed a commit that referenced this pull request Aug 27, 2026
Rollup of 7 pull requests

Successful merges:

 - #150075 (Implement clamp_to)
 - #161034 (Add SVE-accelerated Vec::retain_mut for aarch64)
 - #161628 (interpret: ensure that calls via no-unwind ABIs do not unwind)
 - #161012 (borrowck: Normalize non-rigid aliases in NLL type relating)
 - #161702 (Use `drop_guard` in some places in {core,alloc,std})
 - #161813 (Change `is_eligible_for_coverage` from a hook to a query)
 - #161842 (chore: fix cargo lints)
jhpratt added a commit to jhpratt/rust that referenced this pull request Aug 27, 2026
…_aliases, r=adwinwhite

borrowck: Normalize non-rigid aliases in NLL type relating

Fixes rust-lang#160652

With `-Znext-solver=globally`, yielding from an `impl Iterator` without an explicit `Item` bound ICEs in borrowck. The coroutine defining type returned by `type_of` is unnormalized, so its yield type remains `<impl Iterator as Iterator>::Item`. Skipping normalization propagates that non-rigid alias into both MIR's `CoroutineInfo` and borrowck's `UniversalRegions`; NLL type relating then hits its invariant that non-rigid aliases must already have been normalized.

Deeply normalize the instantiated defining type when MIR construction creates `CoroutineInfo` and when borrowck reconstructs `DefiningTy`. That makes the coroutine yield and resume types rigid before NLL compares them.

This is intentionally gated to the next solver. The old solver keeps the existing skip-normalization path because deeply normalizing defining types there causes regressions.
rust-bors Bot pushed a commit that referenced this pull request Aug 27, 2026
Rollup of 6 pull requests

Successful merges:

 - #161034 (Add SVE-accelerated Vec::retain_mut for aarch64)
 - #161628 (interpret: ensure that calls via no-unwind ABIs do not unwind)
 - #161012 (borrowck: Normalize non-rigid aliases in NLL type relating)
 - #161702 (Use `drop_guard` in some places in {core,alloc,std})
 - #161813 (Change `is_eligible_for_coverage` from a hook to a query)
 - #161842 (chore: fix cargo lints)
rust-bors Bot pushed a commit that referenced this pull request Aug 27, 2026
Rollup of 7 pull requests

Successful merges:

 - #161034 (Add SVE-accelerated Vec::retain_mut for aarch64)
 - #161628 (interpret: ensure that calls via no-unwind ABIs do not unwind)
 - #161012 (borrowck: Normalize non-rigid aliases in NLL type relating)
 - #161691 (Assorted bootstrap config refactors (part 1/N))
 - #161813 (Change `is_eligible_for_coverage` from a hook to a query)
 - #161842 (chore: fix cargo lints)
 - #161843 (rustdoc: fix lint `cargo::non_kebab_case_bins`)
@rust-bors
rust-bors Bot merged commit 04eae11 into rust-lang:main Aug 27, 2026
13 checks passed
rust-bors Bot pushed a commit that referenced this pull request Aug 27, 2026
Rollup merge of #161012 - Dnreikronos:borrowck/normalize_nll_aliases, r=adwinwhite

borrowck: Normalize non-rigid aliases in NLL type relating

Fixes #160652

With `-Znext-solver=globally`, yielding from an `impl Iterator` without an explicit `Item` bound ICEs in borrowck. The coroutine defining type returned by `type_of` is unnormalized, so its yield type remains `<impl Iterator as Iterator>::Item`. Skipping normalization propagates that non-rigid alias into both MIR's `CoroutineInfo` and borrowck's `UniversalRegions`; NLL type relating then hits its invariant that non-rigid aliases must already have been normalized.

Deeply normalize the instantiated defining type when MIR construction creates `CoroutineInfo` and when borrowck reconstructs `DefiningTy`. That makes the coroutine yield and resume types rigid before NLL compares them.

This is intentionally gated to the next solver. The old solver keeps the existing skip-normalization path because deeply normalizing defining types there causes regressions.
@rustbot rustbot added this to the 1.100.0 milestone Aug 27, 2026
let ocx = ObligationCtxt::new(&infcx);
let span = tcx.def_span(def_id);
let cause = ObligationCause::misc(span, def_id);
ocx.deeply_normalize(&cause, tcx.param_env(def_id), ty).unwrap()

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.

that drops region constraints from normalization 🤔

I assume that's fine because the yield type has already been normalized in HIR typeck, so this should just replace the non-rigid aliases with rigid ones in the closure? Could we do that explicitly with a comment explaining what's going on?

Using a local ocx during borrowck feels brittle to me

@Dnreikronos Dnreikronos Aug 27, 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.

sup o/

Yeah, I think you're right about the local ocx. Basically when I wrote this I was mostly following the failure backwards from borrowck..it was getting a non-rigid alias where it expected a rigid one, so normalizing the type there fixed the ICE. It worked, but I don't think it's a great place to do it. Any region constraints created by that normalization live in a temporary inference context and disappear right after.

The part I missed is that HIR typeck had already normalized the closure type. type_of then puts it into an EarlyBinder, which marks the aliases as non-rigid again. So when borrowck gets the type, it looks like it needs normalization even though only the marker changed.

My feeling is that set_aliases_to_rigid says what we actually mean here and avoids running the solver again for no real reason. A comment would help too, because this path is pretty easy to misunderstand. I definitely misunderstood it the first time.

As this PR has already merged, what do you think makes sense as a follow-up? I could open another PR that changes this in borrowck and the MIR builder, since both read the same closure type, but I'm not sure if you'd prefer to keep it smaller.

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 assume that's fine because the yield type has already been normalized in HIR typeck, so this should just replace the non-rigid aliases with rigid ones in the closure?

Oh, I missed that rigidness can be shared between typeck and borrowck.

@Dnreikronos a follow-up would be good, thank you!

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.

@Dnreikronos can you add that fact as a comment on IsRigid I think? Unsure where we currently document the way rigidness works

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.

sup o/

ofc, i will work on this today!

RalfJung pushed a commit to RalfJung/miri that referenced this pull request Aug 28, 2026
Rollup of 7 pull requests

Successful merges:

 - rust-lang/rust#161034 (Add SVE-accelerated Vec::retain_mut for aarch64)
 - rust-lang/rust#161628 (interpret: ensure that calls via no-unwind ABIs do not unwind)
 - rust-lang/rust#161012 (borrowck: Normalize non-rigid aliases in NLL type relating)
 - rust-lang/rust#161691 (Assorted bootstrap config refactors (part 1/N))
 - rust-lang/rust#161813 (Change `is_eligible_for_coverage` from a hook to a query)
 - rust-lang/rust#161842 (chore: fix cargo lints)
 - rust-lang/rust#161843 (rustdoc: fix lint `cargo::non_kebab_case_bins`)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 31, 2026
…_rigidity, r=adwinwhite

borrowck: Restore alias rigidity from HIR typeck

Follow-up to rust-lang#161012. This came out of the review thread here:
rust-lang#161012 (comment)

Borrowck was normalizing the closure type again in a fresh inference context. HIR writeback had already done that work. EarlyBinder only marked the aliases as non-rigid again because it has to be conservative. If the second normalization creates region constraints, they disappear with the temporary context.

I first thought normalizing again here was fine. After tracing the type back through writeback, I think it makes more sense to trust the result from HIR typeck. Borrowck now restores the rigid flag, and the IsRigid docs explain that this state can carry into borrowck and when it needs to be reset.

Tested with the coroutine regression and tidy.

cc @adwinwhite @lcnr
jhpratt added a commit to jhpratt/rust that referenced this pull request Aug 31, 2026
…_rigidity, r=adwinwhite

borrowck: Restore alias rigidity from HIR typeck

Follow-up to rust-lang#161012. This came out of the review thread here:
rust-lang#161012 (comment)

Borrowck was normalizing the closure type again in a fresh inference context. HIR writeback had already done that work. EarlyBinder only marked the aliases as non-rigid again because it has to be conservative. If the second normalization creates region constraints, they disappear with the temporary context.

I first thought normalizing again here was fine. After tracing the type back through writeback, I think it makes more sense to trust the result from HIR typeck. Borrowck now restores the rigid flag, and the IsRigid docs explain that this state can carry into borrowck and when it needs to be reset.

Tested with the coroutine regression and tidy.

cc @adwinwhite @lcnr
rust-bors Bot pushed a commit that referenced this pull request Aug 31, 2026
Rollup merge of #161926 - Dnreikronos:borrowck/restore_alias_rigidity, r=adwinwhite

borrowck: Restore alias rigidity from HIR typeck

Follow-up to #161012. This came out of the review thread here:
#161012 (comment)

Borrowck was normalizing the closure type again in a fresh inference context. HIR writeback had already done that work. EarlyBinder only marked the aliases as non-rigid again because it has to be conservative. If the second normalization creates region constraints, they disappear with the temporary context.

I first thought normalizing again here was fine. After tracing the type back through writeback, I think it makes more sense to trust the result from HIR typeck. Borrowck now restores the rigid flag, and the IsRigid docs explain that this state can carry into borrowck and when it needs to be reset.

Tested with the coroutine regression and tidy.

cc @adwinwhite @lcnr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

perf-regression Performance regression. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ICE]: it should not be possible to encounter unnormalized aliases in borrowck

8 participants