Skip to content

mgca: Register ConstArgHasType when normalizing projection consts#154853

Open
lapla-cogito wants to merge 7 commits into
rust-lang:mainfrom
lapla-cogito:normlize_projecttion_const
Open

mgca: Register ConstArgHasType when normalizing projection consts#154853
lapla-cogito wants to merge 7 commits into
rust-lang:mainfrom
lapla-cogito:normlize_projecttion_const

Conversation

@lapla-cogito
Copy link
Copy Markdown
Contributor

@lapla-cogito lapla-cogito commented Apr 5, 2026

View all comments

fixes #152962

When running CTFE on a MIR body, normalizing a type const within that body can change the type of the resulting value, causing the MIR to become ill-formed. Since no prior error has been reported at that point, MIR validation fires a span_bug!. The existing ConstArgHasType check in wfcheck::check_type_const does catch this at the definition site, but due to query evaluation ordering, the normalization path can reach MIR validation before that check has run.

Fix this by registering a ConstArgHasType(ct, expected_ty) obligation/goal when normalizing projection consts (both trait and inherent), in both the old and new trait solvers. This ensures the type mismatch is reported as an error during normalization itself, which taints the MIR before validation runs.

The first commit fixes the original case reported in the issue. The second commit fixes a different ICE pattern reported within the issue (see #152962 (comment)).

r? BoxyUwU

@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 Apr 5, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 5, 2026

BoxyUwU is currently at their maximum review capacity.
They may take a while to respond.

@rustbot

This comment has been minimized.

@lapla-cogito lapla-cogito force-pushed the normlize_projecttion_const branch from b93677c to 672dfb8 Compare April 5, 2026 14:54
@rustbot

This comment has been minimized.

assoc_term_own_obligations(selcx, obligation, &mut nested);
Progress { term: term.instantiate(tcx, args), obligations: nested }
let instantiated_term: Term<'tcx> = term.instantiate(tcx, args);
if let Some(ct) = instantiated_term.as_const() {
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.

Boxy and I discussed the fix approach and settled on registering a nested goal when normalizing type consts to verify that the normalized term has the type of the type const item. However, this implementation applies the same nested goal to all associated consts, not just type consts. This better expresses the invariant that the normalized result of a const should match its declared type (I think only type consts currently go through this path, but this also guards against future changes).

@rust-log-analyzer

This comment has been minimized.

@lapla-cogito lapla-cogito force-pushed the normlize_projecttion_const branch from 672dfb8 to 90e8301 Compare April 5, 2026 15:41
@BoxyUwU
Copy link
Copy Markdown
Member

BoxyUwU commented Apr 7, 2026

can you add an equivalent test for free type consts, e.g:

type const N: usize = "this isn't a usize";
fn f() -> [u8; const { N }] {}

actuall;y it seems like this doesn't even ICE on nightly rn 🤔 can you look into why this doesn't ICE but the other stuff does. would like to properly understand why we need this for projections but not free type consts.

When a type const has a value whose type doesn't match the declared type, normalizing a reference to it can trigger CTFE, which in turn runs MIR validation on the const body

the type const has no associated const body. so i think what's happening here is that we normalize everything in a MIR body and then do MIR validation on it afterwards, rather than normalization causing validation to happen 🤔

@lapla-cogito lapla-cogito force-pushed the normlize_projecttion_const branch from 4af1458 to 7dc2ef4 Compare April 7, 2026 13:54
@rustbot

This comment has been minimized.

@lapla-cogito
Copy link
Copy Markdown
Contributor Author

can you add an equivalent test for free type consts

actuall;y it seems like this doesn't even ICE on nightly rn 🤔

Ah, I didn't consider that. Indeed, in such cases, it seems ICE doesn't occur.

IIUC, the key is the ordering of check_type_wf(). For free type consts, check_type_const() runs during par_items(), which catches the type mismatch and emits an error. CTFE of inline consts like const { N } happens later (during MIR_borrow_checking phase, after check_crate completes), so has_errors() is already Some by then and MIR validation suppresses the span_bug!.

For trait/inherent impl type consts, the impl block's check_well_formed() runs during par_items() and can trigger CTFE via compare_impl_item (trait) or signature normalization (inherent). But check_type_const() for the associated item doesn't run until par_impl_items(), which hasn't started yet. So no error has been reported when MIR validation fires. Therefore, I added a test to verify that ICE doesn't occur for free type consts cases as well, thanks.

@rust-log-analyzer

This comment has been minimized.

@lapla-cogito lapla-cogito force-pushed the normlize_projecttion_const branch from 7dc2ef4 to c89665d Compare April 7, 2026 15:29
@rust-log-analyzer

This comment has been minimized.

@lapla-cogito lapla-cogito force-pushed the normlize_projecttion_const branch from c89665d to 3d241ce Compare April 7, 2026 17:01
@BoxyUwU
Copy link
Copy Markdown
Member

BoxyUwU commented Apr 14, 2026

IIUC, the key is the ordering of check_type_wf().

oooh okay I think I get it. this test case relies on evaluating the anon const during wfcheck of free items and results in an ICE. does this PR fix this variant: ?

//@ compile-flags: -Zvalidate-mir
#![feature(min_generic_const_args)]

type const X: usize = const { N };
type const N: usize = "this isn't a usize";

@BoxyUwU
Copy link
Copy Markdown
Member

BoxyUwU commented Apr 14, 2026

wrt your PR description it's a bit wrong right now:

When a type const has a value whose type doesn't match the declared type, normalizing a reference to it can trigger CTFE, which in turn runs MIR validation on the const body. The MIR body contains a type mismatch, and since no prior error has been reported at that point, MIR validation fires a span_bug!.

it's not that normalizing a usage of the type const triggers CTFE. rather that when running CTFE on a MIR body we may wind up normalizing a type const in the body, which can change the type of the value causing the MIR to become illformed.

can you update the description

Comment thread compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs Outdated
tcx.const_of_item(alias_term.def_id).instantiate(tcx, args).into()
};

if let Some(ct) = term.as_const() {
Copy link
Copy Markdown
Member

@BoxyUwU BoxyUwU Apr 14, 2026

Choose a reason for hiding this comment

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

View changes since the review

same for the old solver's normalization routine

@BoxyUwU
Copy link
Copy Markdown
Member

BoxyUwU commented Apr 14, 2026

thanks for working on this ✨

@BoxyUwU
Copy link
Copy Markdown
Member

BoxyUwU commented Apr 14, 2026

@rustbot author

@rustbot rustbot 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 Apr 14, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 14, 2026

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@lapla-cogito
Copy link
Copy Markdown
Contributor Author

lapla-cogito commented Apr 16, 2026

IIUC, the key is the ordering of check_type_wf().

oooh okay I think I get it. this test case relies on evaluating the anon const during wfcheck of free items and results in an ICE. does this PR fix this variant: ?

//@ compile-flags: -Zvalidate-mir
#![feature(min_generic_const_args)]

type const X: usize = const { N };
type const N: usize = "this isn't a usize";

I tested this variant and adding ConstArgHasType to normalize_free_alias does not fix it. The obligation is registered in the outer wfcheck context, but the ICE happens inside the AnonConst's CTFE -> MIR validation, where has_errors() hasn't been updated yet. This would need a different approach to fix, so I think it's out of scope for this PR 🤔

edit: Of course, even if this PR doesn't address such cases, it would be possible for me to handle them later.

@lapla-cogito
Copy link
Copy Markdown
Contributor Author

@rustbot ready

@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Apr 16, 2026
@lapla-cogito lapla-cogito force-pushed the normlize_projecttion_const branch from 4e17133 to 00b1870 Compare May 9, 2026 05:48
@rustbot

This comment has been minimized.

Copy link
Copy Markdown
Contributor Author

@lapla-cogito lapla-cogito left a comment

Choose a reason for hiding this comment

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

Ah, I didn't realize about the QueryNormalizer. Thanks!

View changes since this review

Comment thread tests/ui/const-generics/mgca/type_const-mismatched-types.rs
@lapla-cogito lapla-cogito force-pushed the normlize_projecttion_const branch from 00b1870 to cb7ca45 Compare May 9, 2026 09:51
@rust-bors

This comment has been minimized.

@lapla-cogito lapla-cogito force-pushed the normlize_projecttion_const branch from cb7ca45 to ff1972a Compare June 2, 2026 00:27
@rustbot

This comment has been minimized.

@rust-bors

This comment has been minimized.

@lapla-cogito lapla-cogito force-pushed the normlize_projecttion_const branch from ff1972a to 1240be2 Compare June 4, 2026 03:58
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 4, 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.

Comment thread compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs Outdated
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => false,
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => false,
Copy link
Copy Markdown
Member

@BoxyUwU BoxyUwU Jun 5, 2026

Choose a reason for hiding this comment

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

oh this is slightly scuffed actually 🤔 we probably don't to change this but then I guess try_normalize_erasing_regions ICEs due to dropping ConstArgHasType goals on the floor...

can you revert this and then instead of registering the ConstArgHasType goals in try_fold_free_or_assoc for query_normalize instead handle it in the normalize_canonicalized_x queries:

tcx.normalize_canonicalized_projection(c_term)
tcx.normalize_canonicalized_free_alias(c_term)
tcx.normalize_canonicalized_inherent_projection(c_term)

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.

This change results in a more sensible error message being emitted in the type-const-free-value-type-mismatch.rs test.

@lapla-cogito lapla-cogito force-pushed the normlize_projecttion_const branch from c0f7e12 to e8390d8 Compare June 5, 2026 15:08
///
/// Additionally, when `term` is a const, this registers a `ConstArgHasType`
/// goal to ensure that the const value's type matches the type of the
/// alias it was normalized from, preventing ICEs from type mismatches.
Copy link
Copy Markdown
Contributor

@khyperia khyperia Jun 5, 2026

Choose a reason for hiding this comment

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

sorry for butting in kinda late - some optional feedback here:

The way that I would expect this to work is that things are wfchecked at definition site before they're attempted to be evaluated (and so would be tainted, and this usage would never even get to this point of attempting to normalize it). You write in the PR description:

The existing ConstArgHasType check in wfcheck::check_type_const does catch this at the definition site, but due to query evaluation ordering, the normalization path can reach MIR validation before that check has run.

I presume there is some cursed arcane reason why we cannot easily fix the "due to query evaluation ordering" part of that sentence, and why this approach of slapping on ConstArgHasType obligations to the normalization result is needed.

Would you mind writing that cursed arcane reason into a comment here? I find comments of the style "hey reader, you're not insane, this is indeed wonky and not what you would expect, because [...]" to be extremely helpful ❤️

View changes since the review

@BoxyUwU
Copy link
Copy Markdown
Member

BoxyUwU commented Jun 5, 2026

@bors try @rust-timer queue

we should check perf incase it matters :3

@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 Jun 5, 2026
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jun 5, 2026
mgca: Register `ConstArgHasType` when normalizing projection consts
@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented Jun 5, 2026

☀️ Try build successful (CI)
Build commit: 4787dc1 (4787dc1e2f7a57927f9f19345cf1b82e3ea48da7, parent: ac6f3a3e778a586854bdbf8f15202e11e2348d9f)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (4787dc1): comparison URL.

Overall result: ❌ regressions - no action needed

Benchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up.

@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
0.3% [0.2%, 0.3%] 7
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results (secondary 3.2%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
8.5% [8.5%, 8.5%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-2.1% [-2.1%, -2.1%] 1
All ❌✅ (primary) - - 0

Cycles

Results (primary 2.2%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
2.2% [2.2%, 2.2%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.2% [2.2%, 2.2%] 1

Binary size

This perf run didn't have relevant results for this metric.

Bootstrap: 514.264s -> 515.211s (0.18%)
Artifact size: 400.77 MiB -> 400.77 MiB (-0.00%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jun 5, 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-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]: mgca: broken mir Failed subtyping u8 and usize

6 participants