Skip to content

type system const items via direct rhs - #162179

Open
khyperia wants to merge 1 commit into
rust-lang:mainfrom
khyperia:direct-rhs-const
Open

type system const items via direct rhs#162179
khyperia wants to merge 1 commit into
rust-lang:mainfrom
khyperia:direct-rhs-const

Conversation

@khyperia

@khyperia khyperia commented Sep 2, 2026

Copy link
Copy Markdown
Member

View all comments

fixes #161264

see also zulip thread: #project-const-generics > implementing assoc consts as direct args

a const item with a direct! rhs is now a type system transparent direct const, similar to a type const:

const C: T = core::direct_const_arg!(V);

if the macroless feature is enabled, the macroless heuristic also applies here

this PR puts us in an awkward middle ground, between the present world with type const, and the future of GCA as discussed in this zulip thread: #project-const-generics > talkies at last

tl;dr we're yeeting type const and replacing it with const C: T = gca!(V);, and with this PR, both syntaxes are supported at the same time, which is weird and awkward. But, incremental improvement is good, doing the whole thing at once is too much!

some notes on the change:

  • the is_type_const boolean on the DefKind now corresponds to whether the type const syntax is used, not whether it is a type system transparent const
  • the const_of_item query now returns Option, and is Some when it is a type system transparent direct const.
    • it is a little spicy that const_of_item returns None if there is no RHS rather than panicing - if it panics, it's vaguely annoying to guard against this in callsites, returning None is a bit more convenient. API design is hard, idk.
  • the TyCtxt method is_direct_const is true if it's either a type const, or if it's a direct const
    • this logic will eventually change to: is true if it either has the #[always_gca] attribute, or if it has a gca! rhs.
  • should we serialize the const_of_item query for anon consts, or just guard against the DefKind in some helper that returns the actually serialized query impl? Behavior is the same, idk perf jank or whatever.

r? @BoxyUwU

@rustbot

rustbot commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

clippy is developed in its own repository. If possible, consider making this change to rust-lang/rust-clippy instead.

cc @rust-lang/clippy

Some changes occurred in match checking

cc @Nadrieril

HIR ty lowering was modified

cc @fmease

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-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. labels Sep 2, 2026
@rustbot rustbot added the WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) label Sep 2, 2026
@rustbot

rustbot commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

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

@BoxyUwU BoxyUwU 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.

very sick and cool :3

View changes since this review

@@ -2683,19 +2683,41 @@ impl<'hir> LoweringContext<'_, 'hir> {
) -> hir::ConstItemRhs<'hir> {
match (body, kind) {
(body, ConstItemKind::Body) => {

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.

In the long tail of history I suppose we wont have a ConstItemKind to match on because they'll all be the same kind?

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.

correct, ConstItemKind gets nuked, and this method, lower_const_item_rhs, will only be this arm of this match statement.

def_id: LocalDefId,
item_ty: Ty<'tcx>,
has_value: bool,
) -> Result<(), ErrorGuaranteed> {

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.

why yeet the Result?

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.

no reason, there was no ? or return Err or anything in this method, we were always returning Ok(()), so why not yeet Result

Ty::new_error_with_message(
tcx,
ty_span,
"constant with `type const` requires an explicit type",

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 assume this isn't necessarily always a type const nowadays?

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.

yeahh. bunch of comments that need to be updated too, but with so much up in the air right now, I've kind of put off changing this wording to after type const is fully yeeted, and we can just talk about consts with a gca!() rhs. kind of a pain to try to invent some wording like "constant with type const or direct_const_arg!() rhs or is a macroless direct const requires an explicit type" that's not a mouthful, but if you think it's worth it I can poke around~

kind: hir::TraitItemKind::Const(_, ct), ..
}) => ct?,
hir::Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(.., ct), .. }) => ct,
hir::Node::AnonConst(..) | hir::Node::ConstBlock(..) => {

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.

why for anon const/const block 🤔 I would expect us to not call this query on these defkinds but I guess we do in practice for some reason?

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.

yeah, like, the debug assert in eval_in_interpreter, thir_body, the par_hir_body_owners call in rustc_hir_analysis/lib.rs, the rustc_monomorphize/collector.rs, buncha wonky places that don't particularly care about const items vs anon consts, and it just clutters the caller to check for anon consts. but also totally reasonable to guard against anon consts there too, and ICE in const_of_item for anon consts instead.

record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id));
}
if should_encode_const_of_item(self.tcx, def_id, def_kind) {
if let DefKind::Const { .. } | DefKind::AssocConst { .. } | DefKind::AnonConst =

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 guess this is the same question as above, why encode it for AnonConst :3

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.

yeah, also, related comment in the PR description:

should we serialize the const_of_item query for anon consts, or just guard against the DefKind in some helper that returns the actually serialized query impl? Behavior is the same, idk perf jank or whatever.

///
/// This is NOT the same as whether the `def_id` can be represented in/used by the type system.
/// For that, you probably want to ask `const_of_item().is_some()`.
pub fn is_type_const(self, def_id: impl IntoQueryKey<DefId>) -> bool {

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.

U changed elsewhere to be is_type_const_syntax right? I would do similar here to make it clear this is not so much a semantic thing any longer (though it may not matter much since type const yeet soon)

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.

mm yeah, when developing this PR I had this called is_type_const_syntax to make sure I looked at all callsites, but I renamed it back just before submit. (grepping is_type_const_syntax is zero hits, it's not a thing in this PR)

but yea, tbh reasonable to keep that change instead of reverting it, if it's useful in this PR's development it's probably just straight up useful always and should be kept :P

if tcx.is_type_const(def_id) {
// Under generic_const_args, `def_id` might be a trait alias that is a regular const,
// but is `impl`d as a directly represented const. We do not know whether it is here, so
// we must use type system normalization for all consts under generic_const_args.

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.

In theory we could only do this for projections, not free/inherent consts since those we can just look at const_of_item for during MIR building. But I don't think that matters 🤔

I'm not confident in whether I consider this to be a hack or a principled fix tbh 😅 It's probably a bit in the middle I suppose... Can you add a FIXME to revisit this before stabilization even if it's fine for now and may even wind up being the long term thing we do

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.

o though pls use a term other than "trait alias" since that means something else

{
debug_assert!(
tcx.const_of_item(owner_def.to_def_id()).is_none(),
"thir_body queried for type_const"

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.

probably not always a type const right?

{
debug_assert!(
tcx.const_of_item(def).is_none(),
"CTFE tried to evaluate type-const: {:?}",

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.

probably not always a type const right?

let const_value = if alias_const.kind.is_type_const(self.tcx) {
// Under generic_const_args, `alias_const` might be a trait alias that is a regular const,
// but is `impl`d as a directly represented const. We do not know whether it is here, so we
// must use type system normalization for all consts under generic_const_args.

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.

Suggested change
// must use type system normalization for all consts under generic_const_args.
// must use type system normalization for all consts under generic_const_args.
//
// We probably want to always use type system norm on stable too
// but that would be a breaking change so right now we limit it to
// just GCA.

maybe 🤔

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.

it would be worth linking to something but im not sure what, i dont know that I have a good write up anywhere of plans for const patterns. but I should write one

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.

you made an issue for this here, maybe this link? rust-lang/project-const-generics#105 (there's nothing really in this issue at the moment though)

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.

on a tangent, more than just const patterns, I think a writeup for the uuuh compiler/rustc_mir_build/src/builder/expr/as_constant.rs change would be lovely. when I was yapping with lcnr about this, that one in particular took a lot to communicate/sync on. like, all the stuff around padding bytes and multiple value representations and whatever and more importantly, how we plan to address those issues, big oof, rough times. (lcnr had the idea to spec const items as roundtripping their result through a valtree or something, but yea, no clue myself)

@khyperia

khyperia commented Sep 2, 2026

Copy link
Copy Markdown
Member Author

@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 Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc 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.

GCA: associated constant is not normalized properly in generic argument

3 participants