Skip to content

Make const eval return normalized ty - #160526

Open
bit-aloo wants to merge 4 commits into
rust-lang:mainfrom
bit-aloo:2026-08-04-const-eval-normalized-ty-return
Open

Make const eval return normalized ty#160526
bit-aloo wants to merge 4 commits into
rust-lang:mainfrom
bit-aloo:2026-08-04-const-eval-normalized-ty-return

Conversation

@bit-aloo

@bit-aloo bit-aloo commented Aug 4, 2026

Copy link
Copy Markdown
Member

@rustbot

rustbot commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in const_evaluatable.rs

cc @BoxyUwU

Some changes occurred to the core trait solver

cc @rust-lang/initiative-trait-system-refactor

@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 4, 2026
@bit-aloo

bit-aloo commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

I am very dicy around the old solver changes: 0d49779

@rust-bors

This comment has been minimized.

@khyperia

khyperia commented Aug 11, 2026

Copy link
Copy Markdown
Member

neat, looks good to me!

one mostly style comment I had is that the evaluate machinery is getting really annoyingly tangly and layered and messy, and this is just more layers of wonkiness on top, haha. I wonder if instead of having a double-wrapped Result like you do with this change, instead:

  • remove the _with_fallible_normalization methods
  • EvaluateConstErr gets a new variant, "type normalization error", whose value is a generic parameter
  • try_evaluate_const has an <E> generic arg, takes a normalize: fn(..) -> Result<Ty, E> and returns Result<Const, EvaluateConstErr<E>>
  • evaluate_const returns either Result<Option<Const>, E> or Result<Const, SomeNewEnum<E>> that's either... you know what, hm, evaluate_const maybe should just get nuked, maybe everything should use try_evaluate_const, since there's multiple complex failure modes of regular evaluate_const, and the complexity reduction of evaluate_const over try_evaluate_const isn't that useful anymore. idk. shrug.
  • infallable normalization returns Result<Ty, Infallible> so try_evaluate_const returns EvaluateConstErr<Infallible>. (or actual ! never, I forget if we're allowed to use it here)
  • fallable normalization returns with E=NoSolutionOrRerunNonErased or whatever
  • try_evaluate_const_inner doesn't need to exist, nor does the weird new enum EvaluatedConst

anyway, just kind of spitballing here, totally up to you on whether you try to clean this up, it's also fine as-is (I'll probably try to clean it up post-merge though if you leave it as-is)

@bit-aloo

bit-aloo commented Aug 11, 2026

Copy link
Copy Markdown
Member Author

neat, looks good to me!

one mostly style comment I had is that the evaluate machinery is getting really annoyingly tangly and layered and messy, and this is just more layers of wonkiness on top, haha. I wonder if instead of having a double-wrapped Result like you do with this change, instead:

  • remove the _with_fallible_normalization methods
  • EvaluateConstErr gets a new variant, "type normalization error", whose value is a generic parameter
  • try_evaluate_const has an <E> generic arg, takes a normalize: fn(..) -> Result<Ty, E> and returns Result<Const, EvaluateConstErr<E>>
  • evaluate_const returns either Result<Option<Const>, E> or Result<Const, SomeNewEnum<E>> that's either... you know what, hm, evaluate_const maybe should just get nuked, maybe everything should use try_evaluate_const, since there's multiple complex failure modes of regular evaluate_const, and the complexity reduction of evaluate_const over try_evaluate_const isn't that useful anymore. idk. shrug.
  • infallable normalization returns Result<Ty, Infallible> so try_evaluate_const returns EvaluateConstErr<Infallible>. (or actual ! never, I forget if we're allowed to use it here)
  • fallable normalization returns with E=NoSolutionOrRerunNonErased or whatever
  • try_evaluate_const_inner doesn't need to exist, nor does the weird new enum EvaluatedConst

anyway, just kind of spitballing here, totally up to you on whether you try to clean this up, it's also fine as-is (I'll probably try to clean it up post-merge though if you leave it as-is)

I will do the clean up and let you know. Thanks for the review 😄

@BoxyUwU

BoxyUwU commented Aug 11, 2026

Copy link
Copy Markdown
Member

I would also try not being generic over normalization routine. I don't think it's important to have old solver support here

@rust-cloud-vms
rust-cloud-vms Bot force-pushed the 2026-08-04-const-eval-normalized-ty-return branch from 54cfaab to 3f3b1cf Compare August 13, 2026 06:33
@bit-aloo

Copy link
Copy Markdown
Member Author

Ripped out all old solver patches, changes should be eye pleasing now 😄

@bit-aloo

Copy link
Copy Markdown
Member Author

r? @khyperia

@rustbot rustbot assigned khyperia and unassigned lcnr Aug 13, 2026

@khyperia khyperia left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

changes should be eye pleasing now

heck yea love me some nevers 🔥

two nits, and one thing I'm squinting at, otherwise looks fantastic!

View changes since this review

|v| Ok::<_, !>(v.skip_norm_wip()),
) {
Ok(val) => Ok(val),
Err(e) => Err(e),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this isn't your PR, but lmao, what are we doing with this match statement 💀 can just remove the match and use try_evaluate_const directly I think, but also ok to leave it

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

😆 This is so funny. Collapsed it.

Self::FailedNormalization(_) => f.write_str("FailedNormalization(..)"),
}
}
}

@khyperia khyperia Aug 13, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I have a vague preference to keep #[derive(Debug)] and add E: Debug to evaluate_const<E: Debug> and try_evaluate_const<E: Debug> (i.e. add E: Debug wherever the compiler errors at you)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I had this before, but then changed it to explicit debug. I have reverted it back now.

self.normalize(GoalSource::Misc, param_env, ty)
}) {
Ok(ct) => Ok(ct),
Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Ok(None),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm vaguely sus of this. Should this really return Ok(None) instead of Err?

Admittedly I need more coffee and time to think through this. Some potential wonky interactions with feature(checked_type_aliases) and whatnot that's too big-brained for me right now. If you're confident this should be Ok(None), great, if not, maybe we could chat on zulip a bit about this and figure it out together? At the very least, I think a comment explaining why it should/shouldn't return Ok(None) vs Err would be good here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Now that you mention it, I think what I did here is wrong, or atleast incomplete. Originally, this method's Err was just the rerun signal (RerunNonErased) from the erased-mode guard, while Ok(None) meant "too generic, treat as ambiguity". Normalizing the value's type adds another possible failure (NoSolutionOrRerunNonErased from self.normalize). I don't think those should be conflated. Ambiguity during normalization is already deferred as a nested goal inside normalize, so a NoSolution here should be considered as a failure?. normalize_free_alias also propagates normalization failures with ?, so treating it as ambiguity here seems inconsistent. So I am leaning towards returning Result<Option<Const>, NoSolutionOrRerunNonErased> and letting callers ? it. The main thing I am unsure about is whether we can even hit NoSolution here. The const is fully concrete by the time we evaluate it, so its type's projections should also resolve?

@bit-aloo
bit-aloo requested a review from khyperia August 13, 2026 14:48
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.

feature(adt_const_params) ICEs under next solver: symbol_names: unsupported constant of type [ICE]: symbol_names: unsupported constant of type

5 participants