add field representing types#152730
Conversation
|
Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr Some changes occurred to the CTFE machinery Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri HIR ty lowering was modified cc @fmease |
|
|
This comment has been minimized.
This comment has been minimized.
fe3fa8b to
f5f42d1
Compare
|
Some changes occurred in src/tools/rustfmt cc @rust-lang/rustfmt Some changes occurred in src/tools/clippy cc @rust-lang/clippy |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
72f9813 to
2c83a72
Compare
This comment has been minimized.
This comment has been minimized.
2c83a72 to
edbf7d1
Compare
This comment has been minimized.
This comment has been minimized.
edbf7d1 to
a94a2f8
Compare
|
Reminder, once the PR becomes ready for a review, use |
This comment has been minimized.
This comment has been minimized.
|
The tracking issue should probably be edited to mention the visibility problem. |
|
@bors r+ |
|
@theemathas done & thanks for pinging about that again! |
|
The following code causes the compiler to stack overflow with this PR: #![feature(field_projections)]
#![expect(incomplete_features)]
use std::field::{Field, field_of};
pub struct Weird<T>(<field_of!(Weird<Option<T>>, 0) as Field>::Type); |
|
I would say we probably shouldn't block this PR on it (unless it's exposing a fundamental flaw) but open a GH issue once this PR is merged. |
…-item, r=oli-obk add field representing types *[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/152730)* > [!NOTE] > This is a rewrite of rust-lang#146307 by using a lang item instead of a custom `TyKind`. We still need a `hir::TyKind::FieldOf` variant, because resolving the field name cannot be done before HIR construction. The advantage of doing it this way is that we don't need to make any changes to types after HIR (including symbol mangling). At the very beginning of this feature implementation, I tried to do it using a lang item, but then quickly abandoned the approach, because at that time I was still intending to support nested fields. Here is a [range-diff](https://triagebot.infra.rust-lang.org/gh-range-diff/rust-lang/rust/605f49b27444a738ea4032cb77e3bdc4eb811bab..d15f5052095b3549111854a2555dd7026b0a729e/605f49b27444a738ea4032cb77e3bdc4eb811bab..f5f42d1e03495dbaa23671c46b15fccddeb3492f) between the two PRs --- # Add Field Representing Types (FRTs) This PR implements the first step of the field projection lang experiment (Tracking Issue: rust-lang#145383). Field representing types (FRTs) are a new kind of type. They can be named through the use of the `field_of!` macro with the first argument being the type and the second the name of the field (or variant and field in the case of an enum). No nested fields are supported. FRTs natively implement the `Field` 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. Only fields of non-packed structs are supported, fields of enums an unions have unique types for each field, but those do not implement the `Field` trait. 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-projection `lang-experiment` branch](https://github.com/Rust-for-Linux/field-projection/tree/lang-experiment). ## API added to `core::field` ```rust pub unsafe trait Field { type Base; type Type; const OFFSET: usize; } pub macro field_of($Container:ty, $($fields:expr)+ $(,)?); ``` Along with a perma-unstable type that the compiler uses in the expansion of the macro: ```rust #[unstable(feature = "field_representing_type_raw", issue = "none")] pub struct FieldRepresentingType<T: ?Sized, const VARIANT: u32, const FIELD: u32> { _phantom: PhantomData<T>, } ``` ## 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. 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 a [`PinnableField` trait](https://github.com/Rust-for-Linux/field-projection/blob/lang-experiment/src/marker.rs#L9-L23) 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`. > [!NOTE] > The approach of field projections has changed considerably since this PR was opened. In the end we might not need FRTs, so this API is highly experimental. FRTs should act as though they were defined as `struct 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 from that crate. The `Field` traits should be implemented by the compiler & populated with correct information (`unsafe` code needs to be able to rely on them being correct). ## TODOs There are some `FIXME(FRTs)` scattered around the code: - Diagnostics for `field_of!` can be improved - `tests/ui/field_representing_types/nonexistent.rs` - `tests/ui/field_representing_types/non-struct.rs` - `tests/ui/field_representing_types/offset.rs` - `tests/ui/field_representing_types/not-field-if-packed.rs` - `tests/ui/field_representing_types/invalid.rs` - Simple type alias already seem to work, but might need some extra work in `compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs` r? @oli-obk
…-item, r=oli-obk add field representing types *[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/152730)* > [!NOTE] > This is a rewrite of rust-lang#146307 by using a lang item instead of a custom `TyKind`. We still need a `hir::TyKind::FieldOf` variant, because resolving the field name cannot be done before HIR construction. The advantage of doing it this way is that we don't need to make any changes to types after HIR (including symbol mangling). At the very beginning of this feature implementation, I tried to do it using a lang item, but then quickly abandoned the approach, because at that time I was still intending to support nested fields. Here is a [range-diff](https://triagebot.infra.rust-lang.org/gh-range-diff/rust-lang/rust/605f49b27444a738ea4032cb77e3bdc4eb811bab..d15f5052095b3549111854a2555dd7026b0a729e/605f49b27444a738ea4032cb77e3bdc4eb811bab..f5f42d1e03495dbaa23671c46b15fccddeb3492f) between the two PRs --- # Add Field Representing Types (FRTs) This PR implements the first step of the field projection lang experiment (Tracking Issue: rust-lang#145383). Field representing types (FRTs) are a new kind of type. They can be named through the use of the `field_of!` macro with the first argument being the type and the second the name of the field (or variant and field in the case of an enum). No nested fields are supported. FRTs natively implement the `Field` 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. Only fields of non-packed structs are supported, fields of enums an unions have unique types for each field, but those do not implement the `Field` trait. 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-projection `lang-experiment` branch](https://github.com/Rust-for-Linux/field-projection/tree/lang-experiment). ## API added to `core::field` ```rust pub unsafe trait Field { type Base; type Type; const OFFSET: usize; } pub macro field_of($Container:ty, $($fields:expr)+ $(,)?); ``` Along with a perma-unstable type that the compiler uses in the expansion of the macro: ```rust #[unstable(feature = "field_representing_type_raw", issue = "none")] pub struct FieldRepresentingType<T: ?Sized, const VARIANT: u32, const FIELD: u32> { _phantom: PhantomData<T>, } ``` ## 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. 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 a [`PinnableField` trait](https://github.com/Rust-for-Linux/field-projection/blob/lang-experiment/src/marker.rs#L9-L23) 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`. > [!NOTE] > The approach of field projections has changed considerably since this PR was opened. In the end we might not need FRTs, so this API is highly experimental. FRTs should act as though they were defined as `struct 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 from that crate. The `Field` traits should be implemented by the compiler & populated with correct information (`unsafe` code needs to be able to rely on them being correct). ## TODOs There are some `FIXME(FRTs)` scattered around the code: - Diagnostics for `field_of!` can be improved - `tests/ui/field_representing_types/nonexistent.rs` - `tests/ui/field_representing_types/non-struct.rs` - `tests/ui/field_representing_types/offset.rs` - `tests/ui/field_representing_types/not-field-if-packed.rs` - `tests/ui/field_representing_types/invalid.rs` - Simple type alias already seem to work, but might need some extra work in `compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs` r? @oli-obk
…uwer Rollup of 12 pull requests Successful merges: - #153211 (`rust-analyzer` subtree update) - #149027 (Improve cross-crate trait impl param mismatch suggestions ) - #152730 (add field representing types) - #153136 (Correctly handle `#[doc(alias = "...")]` attribute on inlined reexports) - #152165 (Normalize capture place `ty`s to prevent ICE) - #152615 (refactor 'valid for read/write' definition: exclude null) - #153109 (Fix LegacyKeyValueFormat report from docker build: aarch64-gnu-debug) - #153172 (Fix comment about placeholders) - #153187 (Fix ICE when macro-expanded extern crate shadows std) - #153190 (Don't allow subdiagnostic to use variables from their parent) - #153200 (Remove redundant clone) - #153216 (mark two polonius tests as known-bug)
Rollup merge of #152730 - BennoLossin:field-projections-lang-item, r=oli-obk add field representing types *[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/152730)* > [!NOTE] > This is a rewrite of #146307 by using a lang item instead of a custom `TyKind`. We still need a `hir::TyKind::FieldOf` variant, because resolving the field name cannot be done before HIR construction. The advantage of doing it this way is that we don't need to make any changes to types after HIR (including symbol mangling). At the very beginning of this feature implementation, I tried to do it using a lang item, but then quickly abandoned the approach, because at that time I was still intending to support nested fields. Here is a [range-diff](https://triagebot.infra.rust-lang.org/gh-range-diff/rust-lang/rust/605f49b27444a738ea4032cb77e3bdc4eb811bab..d15f5052095b3549111854a2555dd7026b0a729e/605f49b27444a738ea4032cb77e3bdc4eb811bab..f5f42d1e03495dbaa23671c46b15fccddeb3492f) between the two PRs --- # 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 with the first argument being the type and the second the name of the field (or variant and field in the case of an enum). No nested fields are supported. FRTs natively implement the `Field` 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. Only fields of non-packed structs are supported, fields of enums an unions have unique types for each field, but those do not implement the `Field` trait. 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-projection `lang-experiment` branch](https://github.com/Rust-for-Linux/field-projection/tree/lang-experiment). ## API added to `core::field` ```rust pub unsafe trait Field { type Base; type Type; const OFFSET: usize; } pub macro field_of($Container:ty, $($fields:expr)+ $(,)?); ``` Along with a perma-unstable type that the compiler uses in the expansion of the macro: ```rust #[unstable(feature = "field_representing_type_raw", issue = "none")] pub struct FieldRepresentingType<T: ?Sized, const VARIANT: u32, const FIELD: u32> { _phantom: PhantomData<T>, } ``` ## 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. 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 a [`PinnableField` trait](https://github.com/Rust-for-Linux/field-projection/blob/lang-experiment/src/marker.rs#L9-L23) 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`. > [!NOTE] > The approach of field projections has changed considerably since this PR was opened. In the end we might not need FRTs, so this API is highly experimental. FRTs should act as though they were defined as `struct 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 from that crate. The `Field` traits should be implemented by the compiler & populated with correct information (`unsafe` code needs to be able to rely on them being correct). ## TODOs There are some `FIXME(FRTs)` scattered around the code: - Diagnostics for `field_of!` can be improved - `tests/ui/field_representing_types/nonexistent.rs` - `tests/ui/field_representing_types/non-struct.rs` - `tests/ui/field_representing_types/offset.rs` - `tests/ui/field_representing_types/not-field-if-packed.rs` - `tests/ui/field_representing_types/invalid.rs` - Simple type alias already seem to work, but might need some extra work in `compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs` r? @oli-obk
|
@BennoLossin any chance you can open up a follow up PR to add a formatting test case for this like I asked in #152730 (comment)? The tests should be pretty simple. Check out these other examples that use builtin syntax:
All you'd need to do is add a test file to |
|
Oh sure, sorry about forgetting that, filed a PR: #153229 |
rustfmt: add test for field representing type builtin syntax As requested by @ytmimi in rust-lang#152730 (comment). Not sure if you want/need a more complex example. Just let me know.
rustfmt: add test for field representing type builtin syntax As requested by @ytmimi in rust-lang#152730 (comment). Not sure if you want/need a more complex example. Just let me know.
|
I've filed the circularly-defined struct as #153256. For some reason, it now causes the compiler to hang in my testing, instead of the previously-observed stack overflow. |
Local builds are less optimized and may successfully hit existing stack growing instructions before blowing up. The root issue of an infinite recursion is the same. |
Rollup merge of #153229 - BennoLossin:frt-fmt, r=ytmimi rustfmt: add test for field representing type builtin syntax As requested by @ytmimi in #152730 (comment). Not sure if you want/need a more complex example. Just let me know.
…uwer Rollup of 12 pull requests Successful merges: - rust-lang/rust#153211 (`rust-analyzer` subtree update) - rust-lang/rust#149027 (Improve cross-crate trait impl param mismatch suggestions ) - rust-lang/rust#152730 (add field representing types) - rust-lang/rust#153136 (Correctly handle `#[doc(alias = "...")]` attribute on inlined reexports) - rust-lang/rust#152165 (Normalize capture place `ty`s to prevent ICE) - rust-lang/rust#152615 (refactor 'valid for read/write' definition: exclude null) - rust-lang/rust#153109 (Fix LegacyKeyValueFormat report from docker build: aarch64-gnu-debug) - rust-lang/rust#153172 (Fix comment about placeholders) - rust-lang/rust#153187 (Fix ICE when macro-expanded extern crate shadows std) - rust-lang/rust#153190 (Don't allow subdiagnostic to use variables from their parent) - rust-lang/rust#153200 (Remove redundant clone) - rust-lang/rust#153216 (mark two polonius tests as known-bug)
View all comments
Note
This is a rewrite of #146307 by using a lang item instead of a custom
TyKind. We still need ahir::TyKind::FieldOfvariant, because resolving the field name cannot be done before HIR construction. The advantage of doing it this way is that we don't need to make any changes to types after HIR (including symbol mangling). At the very beginning of this feature implementation, I tried to do it using a lang item, but then quickly abandoned the approach, because at that time I was still intending to support nested fields.Here is a range-diff between the two PRs
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 with the first argument being the type and the second the name of the field (or variant and field in the case of an enum). No nested fields are supported.FRTs natively implement the
Fieldtrait 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. Only fields of non-packed structs are supported, fields of enums an unions have unique types for each field, but those do not implement theFieldtrait.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
coreinstead of creating my own using the hash of the name of the field. See the Rust-for-Linux/field-projectionlang-experimentbranch.API added to
core::fieldAlong with a perma-unstable type that the compiler uses in the expansion of the macro:
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. 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 aPinnableFieldtrait 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.Note
The approach of field projections has changed considerably since this PR was opened. In the end we might not need FRTs, so this API is highly experimental.
FRTs should act as though they were defined as
struct 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 from that crate. TheFieldtraits should be implemented by the compiler & populated with correct information (unsafecode needs to be able to rely on them being correct).TODOs
There are some
FIXME(FRTs)scattered around the code:field_of!can be improvedtests/ui/field_representing_types/nonexistent.rstests/ui/field_representing_types/non-struct.rstests/ui/field_representing_types/offset.rstests/ui/field_representing_types/not-field-if-packed.rstests/ui/field_representing_types/invalid.rscompiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rsr? @oli-obk