-
Notifications
You must be signed in to change notification settings - Fork 13.8k
Add field representing types #146307
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
base: master
Are you sure you want to change the base?
Add field representing types #146307
Conversation
2bd0ff4
to
a6b191a
Compare
changes to the core type system Some changes occurred in src/tools/clippy cc @rust-lang/clippy Some changes occurred in diagnostic error codes Some changes occurred to the CTFE machinery Some changes occurred in compiler/rustc_sanitizers cc @rcvalle HIR ty lowering was modified cc @fmease Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri Some changes occurred in exhaustiveness checking cc @Nadrieril This PR changes MIR cc @oli-obk, @RalfJung, @JakobDegen, @vakaras Some changes occurred in compiler/rustc_codegen_ssa This PR changes rustc_public cc @oli-obk, @celinval, @ouz-a Some changes occurred in src/tools/rustfmt cc @rust-lang/rustfmt Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
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.
There are some changes to symbol mangling & constant names that I'm not sure how they resulted from my changes. Anybody has any idea?
Some changes occurred to constck cc @fee1-dead |
This comment has been minimized.
This comment has been minimized.
Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 |
This comment has been minimized.
This comment has been minimized.
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.
Could you ensure you have a test that is generic over the field and that queries the offset? That would hit all these points I just mentioned here (or at least some of them), and anyway seems like a very non-trivial case to test.
Or... wait the intrinsic is only used to define that one associated const? I don't know exactly when and how we normalize those but it may be that we indeed never see that MIR in its generic form then...
The test may have to invoke the intrinsic directly to trigger the case I am thinking of.
Co-authored-by: Ralf Jung <[email protected]>
Co-authored-by: Ralf Jung <[email protected]>
e5f69a4
to
4f0462e
Compare
The job Click to see the possible cause of the failure (guessed by this bot)
|
Add Field Representing Types (FRTs)
This PR implements the first step of the field projection lang experiment (Tracking Issue: #145383). Field representing types (FRTs) are a new kind of type. They can be named through the use of the
field_of!
macro that uses the same syntax as theoffset_of!
macro. They natively implement theField
trait that's also added in this PR. It exposes information about the field such as the type of the field, the type of the base (i.e. the type that contains the field) and the offset within that base type.This PR was created in collaboration with @dingxiangfei2009, it wouldn't have been possible without him, so huge thanks for mentoring me!
I updated my library solution for field projections to use the FRTs from
core
instead of creating my own using the hash of the name of the field. See the Rust-for-Linux/field-projectionlang-experiment
branch.API added to
core::field
Explanation of Field Representing Types (FRTs)
FRTs are used for compile-time & trait-level reflection for fields of structs & tuples. Each struct & tuple has a unique compiler-generated type nameable through the
field_of!
macro (using the same syntax asoffset_of!
). This type natively contains information about the field such as the outermost container, type of the field and its offset. Users may implement additional traits on these types in order to record custom information (for example a crate may define aPinnableField
trait that records whether the field is structurally pinned).They are the foundation of field projections, a general operation that's generic over the fields of a struct. This genericism needs to be expressible in the trait system. FRTs make this possible, since an operation generic over fields can just be a function with a generic parameter
F: Field
.FRTs should act as though they were defined as
enum MyStruct_my_field<StructGenerics> {}
next to the struct. So it should be local to the crate defining the struct so that one can implement any trait for the FRT. TheField
traits should be implemented by the compiler & populated with correct information (unsafe
code needs to be able to rely on them being correct).Implementation Details
offset_of!
type checking machinery in theFnCtxt
case,FieldPath
for using them in bothfield_of!
andoffset_of!
,lower_field_path
toHirTyLowerer
,OFFSET
constant of theUnalignedField
trait,Decisions
During the development several desirable properties of FRTs were discovered. Either due to simplifying the implementation or because of language design reasons. These decisions are:
FRTs are uninhabited and have the same layout as
!
[Unaligned]Field
traits, so no need to make them useful as values.Freeze
FRTs are considered local by the orphan check if and only if:
So
field_of!(Foo, bar.baz)
is local ifFoo
andBar
are local (Baz
is allowed to be foreign). Except for tuples, fundamental types are not handled specially. Tuples are allowed as intermediate bases, as long as the first one isn't a tuple. Sofield_of!(Foo, bar.0.baz)
is considered local ifFoo
is local &bar
has type(Bar0, Bar1, ..., BarN)
withBar0
also being local.The reasoning for these two rules is the following: we don't want to allow foreign crates control over FRTs, since they will often encode field invariants (such as the offset in the
UnalignedField
case, or that the field is aligned (Field
)).Tuples are an exception to this, but only if the user controls the outer-most container.
In the future, the first rule could be lifted to:
This would allow users to implement traits on
field_of!((LocalTy, LocalTy), 0)
. But still preventfield_of!((usize, usize), 0)
.traits may be implemented for FRTs in the usual way (so if the FRT or the trait is local). There is an exception:
Drop
: since FRTs are uninhabited, having aDrop
impl doesn't really make sense. It also would have required duplicating a lot of logic from ADTs and as such it simplified the implementation.The
Field
trait is not user-implementableTODOs
There are several
FIXME(field_projections)
scattered around the code. These are either because I & Ding didn't 100% know what to do in that case. Note that not all are comments, some are also contained asbug!("FIXME(field_projections): ...")
.compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_symbol_mangling/src/export.rs
compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/json/conversions.rs
src/librustdoc/clean/mod.rs
enum
support would bedecided against enum support in this PR
OFFSET
constant for those, or do we need different traits?decided against
?Sized
types in this PR