-
-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Reflection MVP #146923
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reflection MVP #146923
Conversation
aab0141 to
4234855
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
4234855 to
6dd9a6a
Compare
This comment has been minimized.
This comment has been minimized.
6dd9a6a to
a77bbe2
Compare
This comment has been minimized.
This comment has been minimized.
| /// It can only be called at compile time. | ||
| #[unstable(feature = "type_info", issue = "146922")] | ||
| #[rustc_const_unstable(feature = "type_info", issue = "146922")] | ||
| pub const fn info(self) -> Type { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This currently has zero regards for semver, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, but it also only supports tuples, which was an explicit choice so we can handle semver related things when we support Adts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless you mean the fact that it allows inspecting a generic param and now knowing it's a tuple. This can look through opaque types and stuff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right it also breaks parametricity (though specialization also does that).
Not super relevant right now, but I hope "discuss semver considerations" is a major item somewhere on the agenda for this feature. ;) (The tracking issue is still rather barebones at the moment.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe controversial, but could Type be limited to viewing types within the current crate, and anything outside it simply be Opaque/Foreign/etc.? Libraries that want the Type of one of their types to be part of the public API could then expose it via a public constant or function returning said constant.
|
It seems like... trying to obtain a |
Oh whoops, that shouldn't happen. I'll add some more tests |
library/core/src/mem/type_info.rs
Outdated
| /// Primitives | ||
| Leaf, | ||
| /// FIXME(#146922): add all the common types | ||
| Unimplemented, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See https://docs.rs/const-type-layout/latest/const_type_layout/struct.TypeLayoutInfo.html for some prior work
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
This is an MVP. Please do not flood this PR with all your wildest reflection dreams. Anything that suggests to extend the scope of this PR is off-topic. |
|
Currently, this implementation says that, in the type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
newer contributor here. basically, I just got some nits you can ignore :)
thank you so much for working on this!!! :D
|
|
||
| #[unstable(feature = "type_info", issue = "146922")] | ||
| pub mod type_info; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be on purpose, but did you intend to use the same re-export pattern as above?
Otherwise, wouldn't this make a guarantee that everything in this module would become unstable/stable at the same time? (and prevent making changes to those internals..?)
if other MVPs tend to ignore this stuff, please ignore this comment :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I make the module stable, its internals would not become stable. The module may also stay unstable forever. For easier usage while entirely unstable I'm just making the module publicly available so all internals can be used and played with
13e3656 to
82028b0
Compare
|
@bors r=BoxyUwU |
Reflection MVP I am opening this PR for discussion about the general design we should start out with, as there are various options (that are not too hard to transition between each other, so we should totally just pick one and go with it and reiterate later) r? @scottmcm and @joshtriplett project goal issue: rust-lang/rust-project-goals#406 tracking issue: rust-lang#146922 The design currently implemented by this PR is * `TypeId::info` (method, usually used as `id.info()` returns a `Type` struct * the `Type` struct has fields that contain information about the type * the most notable field is `kind`, which is a non-exhaustive enum over all possible type kinds and their specific information. So it has a `Tuple(Tuple)` variant, where the only field is a `Tuple` struct type that contains more information (The list of type ids that make up the tuple). * To get nested type information (like the type of fields) you need to call `TypeId::info` again. * There is only one language intrinsic to go from `TypeId` to `Type`, and it does all the work An alternative design could be * Lots of small methods (each backed by an intrinsic) on `TypeId` that return all the individual information pieces (size, align, number of fields, number of variants, ...) * This is how C++ does it (see https://lemire.me/blog/2025/06/22/c26-will-include-compile-time-reflection-why-should-you-care/ and https://isocpp.org/files/papers/P2996R13.html#member-queries) * Advantage: you only get the information you ask for, so it's probably cheaper if you get just one piece of information for lots of types (e.g. reimplementing size_of in terms of `TypeId::info` is likely expensive and wasteful) * Disadvantage: lots of method calling (and `Option` return types, or "general" methods like `num_fields` returning 0 for primitives) instead of matching and field accesses * a crates.io crate could implement `TypeId::info` in terms of this design The backing implementation is modular enough that switching from one to the other is probably not an issue, and the alternative design could be easier for the CTFE engine's implementation, just not as nice to use for end users (without crates wrapping the logic) One wart of this design that I'm fixing in separate branches is that `TypeId::info` will panic if used at runtime, while it should be uncallable
Reflection MVP I am opening this PR for discussion about the general design we should start out with, as there are various options (that are not too hard to transition between each other, so we should totally just pick one and go with it and reiterate later) r? @scottmcm and @joshtriplett project goal issue: rust-lang/rust-project-goals#406 tracking issue: rust-lang#146922 The design currently implemented by this PR is * `TypeId::info` (method, usually used as `id.info()` returns a `Type` struct * the `Type` struct has fields that contain information about the type * the most notable field is `kind`, which is a non-exhaustive enum over all possible type kinds and their specific information. So it has a `Tuple(Tuple)` variant, where the only field is a `Tuple` struct type that contains more information (The list of type ids that make up the tuple). * To get nested type information (like the type of fields) you need to call `TypeId::info` again. * There is only one language intrinsic to go from `TypeId` to `Type`, and it does all the work An alternative design could be * Lots of small methods (each backed by an intrinsic) on `TypeId` that return all the individual information pieces (size, align, number of fields, number of variants, ...) * This is how C++ does it (see https://lemire.me/blog/2025/06/22/c26-will-include-compile-time-reflection-why-should-you-care/ and https://isocpp.org/files/papers/P2996R13.html#member-queries) * Advantage: you only get the information you ask for, so it's probably cheaper if you get just one piece of information for lots of types (e.g. reimplementing size_of in terms of `TypeId::info` is likely expensive and wasteful) * Disadvantage: lots of method calling (and `Option` return types, or "general" methods like `num_fields` returning 0 for primitives) instead of matching and field accesses * a crates.io crate could implement `TypeId::info` in terms of this design The backing implementation is modular enough that switching from one to the other is probably not an issue, and the alternative design could be easier for the CTFE engine's implementation, just not as nice to use for end users (without crates wrapping the logic) One wart of this design that I'm fixing in separate branches is that `TypeId::info` will panic if used at runtime, while it should be uncallable
|
@bors p=6 |
This comment has been minimized.
This comment has been minimized.
What is this?This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.Comparing 1b9ae9e (parent) -> f57eac1 (this PR) Test differencesShow 172 test diffsStage 1
Stage 2
Additionally, 166 doctest diffs were found. These are ignored, as they are noisy. Job group index
Test dashboardRun cargo run --manifest-path src/ci/citool/Cargo.toml -- \
test-dashboard f57eac1bf98cb5d578e3364b64365ec398c137df --output-dir test-dashboardAnd then open Job duration changes
How to interpret the job duration changes?Job durations can vary a lot, based on the actual runner instance |
|
Finished benchmarking commit (f57eac1): comparison URL. Overall result: no relevant changes - no action needed@rustbot label: -perf-regression Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)Results (primary -1.9%, secondary 0.7%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary -2.4%, secondary -0.8%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 472.721s -> 473.812s (0.23%) |
I am opening this PR for discussion about the general design we should start out with, as there are various options (that are not too hard to transition between each other, so we should totally just pick one and go with it and reiterate later)
r? @scottmcm and @joshtriplett
project goal issue: rust-lang/rust-project-goals#406
tracking issue: #146922
The design currently implemented by this PR is
TypeId::info(method, usually used asid.info()returns aTypestructTypestruct has fields that contain information about the typekind, which is a non-exhaustive enum over all possible type kinds and their specific information. So it has aTuple(Tuple)variant, where the only field is aTuplestruct type that contains more information (The list of type ids that make up the tuple).TypeId::infoagain.TypeIdtoType, and it does all the workAn alternative design could be
TypeIdthat return all the individual information pieces (size, align, number of fields, number of variants, ...)TypeId::infois likely expensive and wasteful)Optionreturn types, or "general" methods likenum_fieldsreturning 0 for primitives) instead of matching and field accessesTypeId::infoin terms of this designThe backing implementation is modular enough that switching from one to the other is probably not an issue, and the alternative design could be easier for the CTFE engine's implementation, just not as nice to use for end users (without crates wrapping the logic)
One wart of this design that I'm fixing in separate branches is that
TypeId::infowill panic if used at runtime, while it should be uncallable