Skip to content

Reflection: get VariantId at runtime - #165141

Open
yara-blue wants to merge 5 commits into
rust-lang:mainfrom
yara-blue:reflection-type-id-variant-getter
Open

yara-blue wants to merge 5 commits into
rust-lang:mainfrom
yara-blue:reflection-type-id-variant-getter

Conversation

@yara-blue

Copy link
Copy Markdown
Contributor

We did not yet have a way to use reflection data for enum's at runtime. This adds a method to query the current VariantId give no type information except the TypeId. We do this in two steps:

  1. get the Discriminant given no information about the type at runtime
  2. map the Discriminant to a VariantId

To do 1) we need to generate code for the specific type. Specifically we need to generate std::mem::discriminant. Emitting a function ptr during const-eval is enough to get a monomorphized version of that generated. To get 2) we have an intrinsic that returns a list of VariantId to Discriminant mapping. Getting the discriminant then looking it up in the mapping is packaged into a single function which is what the user actually calls.

Since we have a lot of enum usage in rust the performance of this matters a lot. The current approach is suboptimal, the mapping is done through a linear scan and may not optimize out nicely. I suggest we put some effort in optimizing this after we are sure this will be the API.

@rustbot

rustbot commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter
gets adapted for the changes, if necessary.

cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

The reflection data structures are tied exactly to the implementation
in the compiler. Make sure to also adjust rustc_const_eval/src/const_eval/type_info.rs

cc @oli-obk

Some changes occurred in compiler/rustc_attr_ir

cc @jdonszelmann, @JonathanBrouwer

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

@rustbot rustbot added A-attributes Area: Attributes (`#[…]`, `#![…]`) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 29, 2026
@rustbot rustbot added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Oct 29, 2026
@rustbot

rustbot commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

r? @Mark-Simulacrum

rustbot has assigned @Mark-Simulacrum.
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: libs
  • libs expanded to 37 candidates
  • Random selection from ChrisDenton, JohnTitor, Mark-Simulacrum, clarfonthey

@yara-blue

Copy link
Copy Markdown
Contributor Author

This PR contains some commits that are currently in a rollup. I'll rebase it once that merges.

@yara-blue

Copy link
Copy Markdown
Contributor Author

r? oli-obk

@rustbot rustbot assigned oli-obk and unassigned Mark-Simulacrum Oct 29, 2026
@rust-log-analyzer

This comment has been minimized.

@yara-blue
yara-blue force-pushed the reflection-type-id-variant-getter branch from e285bfa to 9cc6dd5 Compare October 29, 2026 16:44
Comment thread library/core/src/mem/type_info.rs Outdated
///
/// See [`TypeId::variant_getter`] on how to safely use this function.
#[lang = "variant_getter"]
unsafe fn variant_getter<T: 'static>(val: *const ()) -> VariantId {

@oli-obk oli-obk Oct 29, 2026 •

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.

why is the 'static bound needed here? We're in reflection territory, so if it's just for TypeId::of, you can also just use type_info::of::<T>()

View changes since the review

Comment thread library/core/src/mem/type_info.rs Outdated
#[unstable(feature = "type_info", issue = "146922")]
#[rustc_const_unstable(feature = "type_info", issue = "146922")]
#[rustc_comptime]
pub fn variant_getter(self) -> fn(*const ()) -> VariantId {

@oli-obk oli-obk Oct 29, 2026 •

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.

you'll need to make the function pointer an unsafe function pointer, otherwise we have a safe function returning a safe function pointer that when called wrongly can cause UB

View changes since the review

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.

can additionally recommend callers to debug assert the VariantId they are getting back for having a TypeId of the type they expected.

pub fn type_id_variant_getter(_type_id: crate::any::TypeId) -> fn(*const ()) -> VariantId;

/// Returns a lookup table for converting between VariantId and Discriminant. This
/// is use internally by variant getter. **Please do not use this.**

@oli-obk oli-obk Oct 29, 2026 •

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.

by variant_getter (backticks and underscore)

View changes since the review

#[rustc_intrinsic]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_comptime]
pub fn type_id_variant_getter(_type_id: crate::any::TypeId) -> fn(*const ()) -> VariantId;

@oli-obk oli-obk Oct 29, 2026 •

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.

same as TypeId::variant_getter: return fn ptr should be unsafe

View changes since the review

@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 Oct 29, 2026
@rustbot

rustbot commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

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

@rust-log-analyzer

This comment has been minimized.

@yara-blue
yara-blue force-pushed the reflection-type-id-variant-getter branch from 9cc6dd5 to c414965 Compare October 29, 2026 18:02
@rustbot

rustbot commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

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.

@rust-log-analyzer

Copy link
Copy Markdown
Collaborator

The job test-x86_64-gnu-gcc-core-tests failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
[RUSTC-TIMING] corebenches test:true 0.115
error[E0133]: call to unsafe function is unsafe and requires unsafe block
 --> library/coretests/tests/mem/type_info/runtime.rs:9:16
  |
9 |     assert_eq!(variant_getter(as_unit_ptr(test_input)), const { TypeId::of::<T>().variant(0) });
  |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
  |
  = note: consult the function's documentation for information on how to avoid undefined behavior

error[E0133]: call to unsafe function is unsafe and requires unsafe block
  --> library/coretests/tests/mem/type_info/runtime.rs:24:9
   |
24 |         variant_getter(as_unit_ptr(&Kitty::Sleepy)),
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
   |
   = note: consult the function's documentation for information on how to avoid undefined behavior

error[E0133]: call to unsafe function is unsafe and requires unsafe block
  --> library/coretests/tests/mem/type_info/runtime.rs:28:9
   |
28 |         variant_getter(as_unit_ptr(&Kitty::Playful)),
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
   |
   = note: consult the function's documentation for information on how to avoid undefined behavior

error[E0133]: call to unsafe function is unsafe and requires unsafe block
  --> library/coretests/tests/mem/type_info/runtime.rs:32:9
   |
32 |         variant_getter(as_unit_ptr(&Kitty::Cuddly)),
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
   |
   = note: consult the function's documentation for information on how to avoid undefined behavior

warning: unused variable: `variant_getter`
  --> library/coretests/tests/mem/type_info/runtime.rs:94:9
   |
94 |     let variant_getter = const { TypeId::of::<!>().variant_getter() };
   |         ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_variant_getter`
   |
   = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default

[RUSTC-TIMING] coretests test:true 54.290
rustc exited with signal: 6 (SIGABRT) (core dumped)
error: `coretests` (test "coretests") generated 1 warning
error: could not compile `coretests` (test "coretests") due to 4 previous errors; 1 warning emitted

Caused by:
  process didn't exit successfully: `/checkout/obj/build/bootstrap/debug/rustc /checkout/obj/build/bootstrap/debug/rustc --crate-name coretests --edition=2024 library/coretests/tests/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat,unused-externs-silent --emit=dep-info,link -C opt-level=3 -C embed-bitcode=no -C codegen-units=1 --warn=unexpected_cfgs --check-cfg 'cfg(target_has_reliable_f16)' --check-cfg 'cfg(target_has_reliable_f16_math)' --check-cfg 'cfg(target_has_reliable_f128)' --check-cfg 'cfg(target_has_reliable_f128_math)' -Cembed-bitcode=yes -Zunstable-options -Cforce-frame-pointers=non-leaf -C overflow-checks=on --test --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=8e648b9a86af2a25 -C extra-filename=-87d8502a0950c483 --out-dir /checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/dist/build/coretests/87d8502a0950c483/out --target x86_64-unknown-linux-gnu -L dependency=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/dist/build/rand_core/e6ca3b32e65dc6c8/out -L dependency=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/dist/build/coretests/87d8502a0950c483/out --extern coretests=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/dist/build/coretests/2725d6e8dc02b311/out/libcoretests-2725d6e8dc02b311.rlib --extern coretests=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/dist/build/coretests/2725d6e8dc02b311/out/libcoretests-2725d6e8dc02b311.rmeta --extern rand=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/dist/build/rand/fdbf1810afc26db5/out/librand-fdbf1810afc26db5.rlib --extern rand=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/dist/build/rand/fdbf1810afc26db5/out/librand-fdbf1810afc26db5.rmeta --extern rand_xorshift=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/dist/build/rand_xorshift/934927e553085397/out/librand_xorshift-934927e553085397.rlib --extern rand_xorshift=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/dist/build/rand_xorshift/934927e553085397/out/librand_xorshift-934927e553085397.rmeta -Zannotate-moves '--check-cfg=cfg(feature,values(any()))' -Zunstable-options -Zmacro-backtrace -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Zinline-mir-preserve-debug -Zmir_strip_debuginfo=locals-in-tiny-functions -Clink-args=-Wl,-z,origin '-Clink-args=-Wl,-rpath,$ORIGIN/../lib' -Alinker-messages '-Zcrate-attr=doc(html_root_url="https://doc.rust-lang.org/nightly/")' -Cpanic=abort -Zpanic-abort-tests -Z binary-dep-depinfo --force-warn=unused_crate_dependencies` (exit status: 254)
Bootstrap failed while executing `--stage 1 test library/coretests`
Currently active steps:
test::Crate { build_compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu, mode: Std, crates: ["coretests"] } at src/bootstrap/src/core/build_steps/test.rs:3623
Build completed unsuccessfully in 0:13:16
  local time: Thu Oct 29 18:21:41 UTC 2026

Important

For more information how to resolve CI failures of this job, visit this link.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants