mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
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: rust-lang/rust#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
This commit is contained in:
@@ -4706,6 +4706,7 @@ dependencies = [
|
||||
"ena",
|
||||
"indexmap",
|
||||
"rustc-hash 2.1.1",
|
||||
"rustc_abi",
|
||||
"rustc_ast_ir",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_messages",
|
||||
|
||||
@@ -21,7 +21,64 @@
|
||||
mod ty;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
|
||||
pub use ty::{Layout, TyAbiInterface, TyAndLayout};
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// The *source-order* index of a field in a variant.
|
||||
///
|
||||
/// This is how most code after type checking refers to fields, rather than
|
||||
/// using names (as names have hygiene complications and more complex lookup).
|
||||
///
|
||||
/// Particularly for `repr(Rust)` types, this may not be the same as *layout* order.
|
||||
/// (It is for `repr(C)` `struct`s, however.)
|
||||
///
|
||||
/// For example, in the following types,
|
||||
/// ```rust
|
||||
/// # enum Never {}
|
||||
/// # #[repr(u16)]
|
||||
/// enum Demo1 {
|
||||
/// Variant0 { a: Never, b: i32 } = 100,
|
||||
/// Variant1 { c: u8, d: u64 } = 10,
|
||||
/// }
|
||||
/// struct Demo2 { e: u8, f: u16, g: u8 }
|
||||
/// ```
|
||||
/// `b` is `FieldIdx(1)` in `VariantIdx(0)`,
|
||||
/// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and
|
||||
/// `f` is `FieldIdx(1)` in `VariantIdx(0)`.
|
||||
#[cfg_attr(feature = "nightly", derive(rustc_macros::HashStable_Generic))]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
#[gate_rustc_only]
|
||||
pub struct FieldIdx {}
|
||||
}
|
||||
|
||||
impl FieldIdx {
|
||||
/// The second field, at index 1.
|
||||
///
|
||||
/// For use alongside [`FieldIdx::ZERO`], particularly with scalar pairs.
|
||||
pub const ONE: FieldIdx = FieldIdx::from_u32(1);
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// The *source-order* index of a variant in a type.
|
||||
///
|
||||
/// For enums, these are always `0..variant_count`, regardless of any
|
||||
/// custom discriminants that may have been defined, and including any
|
||||
/// variants that may end up uninhabited due to field types. (Some of the
|
||||
/// variants may not be present in a monomorphized ABI [`Variants`], but
|
||||
/// those skipped variants are always counted when determining the *index*.)
|
||||
///
|
||||
/// `struct`s, `tuples`, and `unions`s are considered to have a single variant
|
||||
/// with variant index zero, aka [`FIRST_VARIANT`].
|
||||
#[cfg_attr(feature = "nightly", derive(rustc_macros::HashStable_Generic))]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
#[gate_rustc_only]
|
||||
pub struct VariantIdx {
|
||||
/// Equivalent to `VariantIdx(0)`.
|
||||
const FIRST_VARIANT = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// A variant is absent if it's uninhabited and only has ZST fields.
|
||||
// Present uninhabited variants only require space for their fields,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
use crate::layout::{FieldIdx, VariantIdx};
|
||||
use crate::{
|
||||
AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
|
||||
PointeeInfo, Primitive, Size, Variants,
|
||||
@@ -11,60 +12,6 @@
|
||||
|
||||
// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// The *source-order* index of a field in a variant.
|
||||
///
|
||||
/// This is how most code after type checking refers to fields, rather than
|
||||
/// using names (as names have hygiene complications and more complex lookup).
|
||||
///
|
||||
/// Particularly for `repr(Rust)` types, this may not be the same as *layout* order.
|
||||
/// (It is for `repr(C)` `struct`s, however.)
|
||||
///
|
||||
/// For example, in the following types,
|
||||
/// ```rust
|
||||
/// # enum Never {}
|
||||
/// # #[repr(u16)]
|
||||
/// enum Demo1 {
|
||||
/// Variant0 { a: Never, b: i32 } = 100,
|
||||
/// Variant1 { c: u8, d: u64 } = 10,
|
||||
/// }
|
||||
/// struct Demo2 { e: u8, f: u16, g: u8 }
|
||||
/// ```
|
||||
/// `b` is `FieldIdx(1)` in `VariantIdx(0)`,
|
||||
/// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and
|
||||
/// `f` is `FieldIdx(1)` in `VariantIdx(0)`.
|
||||
#[derive(HashStable_Generic)]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
pub struct FieldIdx {}
|
||||
}
|
||||
|
||||
impl FieldIdx {
|
||||
/// The second field, at index 1.
|
||||
///
|
||||
/// For use alongside [`FieldIdx::ZERO`], particularly with scalar pairs.
|
||||
pub const ONE: FieldIdx = FieldIdx::from_u32(1);
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// The *source-order* index of a variant in a type.
|
||||
///
|
||||
/// For enums, these are always `0..variant_count`, regardless of any
|
||||
/// custom discriminants that may have been defined, and including any
|
||||
/// variants that may end up uninhabited due to field types. (Some of the
|
||||
/// variants may not be present in a monomorphized ABI [`Variants`], but
|
||||
/// those skipped variants are always counted when determining the *index*.)
|
||||
///
|
||||
/// `struct`s, `tuples`, and `unions`s are considered to have a single variant
|
||||
/// with variant index zero, aka [`FIRST_VARIANT`].
|
||||
#[derive(HashStable_Generic)]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
pub struct VariantIdx {
|
||||
/// Equivalent to `VariantIdx(0)`.
|
||||
const FIRST_VARIANT = 0;
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
|
||||
|
||||
@@ -64,9 +64,9 @@
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use extern_abi::CVariadicStatus;
|
||||
pub use extern_abi::{ExternAbi, all_names};
|
||||
pub use layout::{FIRST_VARIANT, FieldIdx, LayoutCalculator, LayoutCalculatorError, VariantIdx};
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
|
||||
pub use layout::{LayoutCalculator, LayoutCalculatorError};
|
||||
pub use layout::{Layout, TyAbiInterface, TyAndLayout};
|
||||
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
|
||||
@@ -2553,6 +2553,11 @@ pub enum TyKind {
|
||||
/// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero<u32>`,
|
||||
/// just as part of the type system.
|
||||
Pat(Box<Ty>, Box<TyPat>),
|
||||
/// A `field_of` expression (e.g., `builtin # field_of(Struct, field)`).
|
||||
///
|
||||
/// Usually not written directly in user code but indirectly via the macro
|
||||
/// `core::field::field_of!(...)`.
|
||||
FieldOf(Box<Ty>, Option<Ident>, Ident),
|
||||
/// Sometimes we need a dummy value when no error has occurred.
|
||||
Dummy,
|
||||
/// Placeholder for a kind that has failed to be defined.
|
||||
|
||||
@@ -298,6 +298,7 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
|
||||
| ast::TyKind::ImplicitSelf
|
||||
| ast::TyKind::CVarArgs
|
||||
| ast::TyKind::Pat(..)
|
||||
| ast::TyKind::FieldOf(..)
|
||||
| ast::TyKind::Dummy
|
||||
| ast::TyKind::Err(..) => break None,
|
||||
}
|
||||
|
||||
@@ -1496,6 +1496,13 @@ fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
|
||||
TyKind::Pat(ty, pat) => {
|
||||
hir::TyKind::Pat(self.lower_ty_alloc(ty, itctx), self.lower_ty_pat(pat, ty.span))
|
||||
}
|
||||
TyKind::FieldOf(ty, variant, field) => hir::TyKind::FieldOf(
|
||||
self.lower_ty_alloc(ty, itctx),
|
||||
self.arena.alloc(hir::TyFieldPath {
|
||||
variant: variant.map(|variant| self.lower_ident(variant)),
|
||||
field: self.lower_ident(*field),
|
||||
}),
|
||||
),
|
||||
TyKind::MacCall(_) => {
|
||||
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
|
||||
}
|
||||
|
||||
@@ -1377,6 +1377,23 @@ pub fn print_type(&mut self, ty: &ast::Ty) {
|
||||
self.word(" is ");
|
||||
self.print_ty_pat(pat);
|
||||
}
|
||||
ast::TyKind::FieldOf(ty, variant, field) => {
|
||||
self.word("builtin # field_of");
|
||||
self.popen();
|
||||
let ib = self.ibox(0);
|
||||
self.print_type(ty);
|
||||
self.word(",");
|
||||
self.space();
|
||||
|
||||
if let Some(variant) = variant {
|
||||
self.print_ident(*variant);
|
||||
self.word(".");
|
||||
}
|
||||
self.print_ident(*field);
|
||||
|
||||
self.end(ib);
|
||||
self.pclose();
|
||||
}
|
||||
}
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
use rustc_middle::mir::interpret::ReportedErrorInfo;
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, mir};
|
||||
use rustc_middle::ty::{self, FieldInfo, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_target::callconv::FnAbi;
|
||||
use tracing::debug;
|
||||
@@ -23,8 +23,9 @@
|
||||
use crate::interpret::{
|
||||
self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
|
||||
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar,
|
||||
compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub,
|
||||
throw_ub_custom, throw_unsup, throw_unsup_format, type_implements_dyn_trait,
|
||||
compile_time_machine, ensure_monomorphic_enough, err_inval, interp_ok, throw_exhaust,
|
||||
throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
|
||||
type_implements_dyn_trait,
|
||||
};
|
||||
|
||||
/// When hitting this many interpreted terminators we emit a deny by default lint
|
||||
@@ -619,6 +620,27 @@ fn call_intrinsic(
|
||||
ecx.write_type_info(ty, dest)?;
|
||||
}
|
||||
|
||||
sym::field_offset => {
|
||||
let frt_ty = instance.args.type_at(0);
|
||||
ensure_monomorphic_enough(ecx.tcx.tcx, frt_ty)?;
|
||||
|
||||
let (ty, variant, field) = if let ty::Adt(def, args) = frt_ty.kind()
|
||||
&& let Some(FieldInfo { base, variant_idx, field_idx, .. }) =
|
||||
def.field_representing_type_info(ecx.tcx.tcx, args)
|
||||
{
|
||||
(base, variant_idx, field_idx)
|
||||
} else {
|
||||
span_bug!(ecx.cur_span(), "expected field representing type, got {frt_ty}")
|
||||
};
|
||||
let layout = ecx.layout_of(ty)?;
|
||||
let cx = ty::layout::LayoutCx::new(ecx.tcx.tcx, ecx.typing_env());
|
||||
|
||||
let layout = layout.for_variant(&cx, variant);
|
||||
let offset = layout.fields.offset(field.index()).bytes();
|
||||
|
||||
ecx.write_scalar(Scalar::from_target_usize(offset, ecx), dest)?;
|
||||
}
|
||||
|
||||
_ => {
|
||||
// We haven't handled the intrinsic, let's see if we can use a fallback body.
|
||||
if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
pub use self::projection::{OffsetMode, Projectable};
|
||||
pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation};
|
||||
pub use self::util::EnteredTraceSpan;
|
||||
pub(crate) use self::util::{create_static_alloc, type_implements_dyn_trait};
|
||||
pub(crate) use self::util::{
|
||||
create_static_alloc, ensure_monomorphic_enough, type_implements_dyn_trait,
|
||||
};
|
||||
pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking};
|
||||
pub use self::visitor::ValueVisitor;
|
||||
|
||||
@@ -221,6 +221,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(internal, custom_mir, "1.65.0", None),
|
||||
/// Implementation details of externally implementable items
|
||||
(internal, eii_internals, "1.94.0", None),
|
||||
/// Implementation details of field representing types.
|
||||
(internal, field_representing_type_raw, "CURRENT_RUSTC_VERSION", None),
|
||||
/// Outputs useful `assert!` messages
|
||||
(unstable, generic_assert, "1.63.0", None),
|
||||
/// Allows using the #[rustc_intrinsic] attribute.
|
||||
@@ -486,6 +488,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(unstable, ffi_const, "1.45.0", Some(58328)),
|
||||
/// Allows the use of `#[ffi_pure]` on foreign functions.
|
||||
(unstable, ffi_pure, "1.45.0", Some(58329)),
|
||||
/// Experimental field projections.
|
||||
(incomplete, field_projections, "CURRENT_RUSTC_VERSION", Some(145383)),
|
||||
/// Allows marking trait functions as `final` to prevent overriding impls
|
||||
(unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(131179)),
|
||||
/// Controlling the behavior of fmt::Debug
|
||||
|
||||
@@ -1741,6 +1741,12 @@ pub fn innermost_block(&self) -> &Block<'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct TyFieldPath {
|
||||
pub variant: Option<Ident>,
|
||||
pub field: Ident,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct TyPat<'hir> {
|
||||
#[stable_hasher(ignore)]
|
||||
@@ -3804,6 +3810,10 @@ pub enum TyKind<'hir, Unambig = ()> {
|
||||
Err(rustc_span::ErrorGuaranteed),
|
||||
/// Pattern types (`pattern_type!(u32 is 1..)`)
|
||||
Pat(&'hir Ty<'hir>, &'hir TyPat<'hir>),
|
||||
/// Field representing type (`field_of!(Struct, field)`).
|
||||
///
|
||||
/// The optional ident is the variant when an enum is passed `field_of!(Enum, Variant.field)`.
|
||||
FieldOf(&'hir Ty<'hir>, &'hir TyFieldPath),
|
||||
/// `TyKind::Infer` means the type should be inferred instead of it having been
|
||||
/// specified. This can appear anywhere in a type.
|
||||
///
|
||||
|
||||
@@ -1047,6 +1047,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -
|
||||
try_visit!(visitor.visit_ty_unambig(ty));
|
||||
try_visit!(visitor.visit_pattern_type_pattern(pat));
|
||||
}
|
||||
TyKind::FieldOf(ty, TyFieldPath { variant, field }) => {
|
||||
try_visit!(visitor.visit_ty_unambig(ty));
|
||||
visit_opt!(visitor, visit_ident, *variant);
|
||||
try_visit!(visitor.visit_ident(*field));
|
||||
}
|
||||
}
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
@@ -435,6 +435,13 @@ fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) {
|
||||
// Reborrowing related lang-items
|
||||
Reborrow, sym::reborrow, reborrow, Target::Trait, GenericRequirement::Exact(0);
|
||||
CoerceShared, sym::coerce_shared, coerce_shared, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
||||
// Field representing types.
|
||||
FieldRepresentingType, sym::field_representing_type, field_representing_type, Target::Struct, GenericRequirement::Exact(3);
|
||||
Field, sym::field, field, Target::Trait, GenericRequirement::Exact(0);
|
||||
FieldBase, sym::field_base, field_base, Target::AssocTy, GenericRequirement::Exact(0);
|
||||
FieldType, sym::field_type, field_type, Target::AssocTy, GenericRequirement::Exact(0);
|
||||
FieldOffset, sym::field_offset, field_offset, Target::AssocConst, GenericRequirement::Exact(0);
|
||||
}
|
||||
|
||||
/// The requirement imposed on the generics of a lang item
|
||||
|
||||
@@ -117,6 +117,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
|
||||
| sym::fabsf128
|
||||
| sym::fadd_algebraic
|
||||
| sym::fdiv_algebraic
|
||||
| sym::field_offset
|
||||
| sym::floorf16
|
||||
| sym::floorf32
|
||||
| sym::floorf64
|
||||
@@ -297,6 +298,7 @@ pub(crate) fn check_intrinsic_type(
|
||||
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
|
||||
}
|
||||
sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize),
|
||||
sym::field_offset => (1, 0, vec![], tcx.types.usize),
|
||||
sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
|
||||
sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()),
|
||||
sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => {
|
||||
|
||||
@@ -1446,6 +1446,15 @@ pub struct NoVariantNamed<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("no field `{$field}` on type `{$ty}`", code = E0609)]
|
||||
pub struct NoFieldOnType<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub field: Ident,
|
||||
}
|
||||
|
||||
// FIXME(fmease): Deduplicate:
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
use std::slice;
|
||||
|
||||
use rustc_abi::FIRST_VARIANT;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
@@ -50,11 +51,11 @@
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::check::check_abi;
|
||||
use crate::check_c_variadic_abi;
|
||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation};
|
||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoFieldOnType};
|
||||
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
|
||||
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
|
||||
use crate::middle::resolve_bound_vars as rbv;
|
||||
use crate::{NoVariantNamed, check_c_variadic_abi};
|
||||
|
||||
/// The context in which an implied bound is being added to a item being lowered (i.e. a sizedness
|
||||
/// trait or a default trait)
|
||||
@@ -3050,6 +3051,14 @@ pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
self.record_ty(pat.hir_id, ty, pat.span);
|
||||
pat_ty
|
||||
}
|
||||
hir::TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => self.lower_field_of(
|
||||
self.lower_ty(ty),
|
||||
self.item_def_id(),
|
||||
ty.span,
|
||||
hir_ty.hir_id,
|
||||
*variant,
|
||||
*field,
|
||||
),
|
||||
hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar),
|
||||
};
|
||||
|
||||
@@ -3091,6 +3100,159 @@ fn lower_pat_ty_pat(
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_field_of(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
item_def_id: LocalDefId,
|
||||
ty_span: Span,
|
||||
hir_id: HirId,
|
||||
variant: Option<Ident>,
|
||||
field: Ident,
|
||||
) -> Ty<'tcx> {
|
||||
let dcx = self.dcx();
|
||||
let tcx = self.tcx();
|
||||
match ty.kind() {
|
||||
ty::Adt(def, _) => {
|
||||
let base_did = def.did();
|
||||
let kind_name = tcx.def_descr(base_did);
|
||||
let (variant_idx, variant) = if def.is_enum() {
|
||||
let Some(variant) = variant else {
|
||||
let err = dcx
|
||||
.create_err(NoVariantNamed { span: field.span, ident: field, ty })
|
||||
.with_span_help(
|
||||
field.span.shrink_to_lo(),
|
||||
"you might be missing a variant here: `Variant.`",
|
||||
)
|
||||
.emit();
|
||||
return Ty::new_error(tcx, err);
|
||||
};
|
||||
|
||||
if let Some(res) = def
|
||||
.variants()
|
||||
.iter_enumerated()
|
||||
.find(|(_, f)| f.ident(tcx).normalize_to_macros_2_0() == variant)
|
||||
{
|
||||
res
|
||||
} else {
|
||||
let err = dcx
|
||||
.create_err(NoVariantNamed { span: variant.span, ident: variant, ty })
|
||||
.emit();
|
||||
return Ty::new_error(tcx, err);
|
||||
}
|
||||
} else {
|
||||
if let Some(variant) = variant {
|
||||
let adt_path = tcx.def_path_str(base_did);
|
||||
struct_span_code_err!(
|
||||
dcx,
|
||||
variant.span,
|
||||
E0609,
|
||||
"{kind_name} `{adt_path}` does not have any variants",
|
||||
)
|
||||
.with_span_label(variant.span, "variant unknown")
|
||||
.emit();
|
||||
}
|
||||
(FIRST_VARIANT, def.non_enum_variant())
|
||||
};
|
||||
let block = tcx.local_def_id_to_hir_id(item_def_id);
|
||||
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(field, def.did(), block);
|
||||
if let Some((field_idx, field)) = variant
|
||||
.fields
|
||||
.iter_enumerated()
|
||||
.find(|(_, f)| f.ident(tcx).normalize_to_macros_2_0() == ident)
|
||||
{
|
||||
if field.vis.is_accessible_from(def_scope, tcx) {
|
||||
tcx.check_stability(field.did, Some(hir_id), ident.span, None);
|
||||
} else {
|
||||
let adt_path = tcx.def_path_str(base_did);
|
||||
struct_span_code_err!(
|
||||
dcx,
|
||||
ident.span,
|
||||
E0616,
|
||||
"field `{ident}` of {kind_name} `{adt_path}` is private",
|
||||
)
|
||||
.with_span_label(ident.span, "private field")
|
||||
.emit();
|
||||
}
|
||||
Ty::new_field_representing_type(tcx, ty, variant_idx, field_idx)
|
||||
} else {
|
||||
let err =
|
||||
dcx.create_err(NoFieldOnType { span: ident.span, field: ident, ty }).emit();
|
||||
Ty::new_error(tcx, err)
|
||||
}
|
||||
}
|
||||
ty::Tuple(tys) => {
|
||||
let index = match field.as_str().parse::<usize>() {
|
||||
Ok(idx) => idx,
|
||||
Err(_) => {
|
||||
let err =
|
||||
dcx.create_err(NoFieldOnType { span: field.span, field, ty }).emit();
|
||||
return Ty::new_error(tcx, err);
|
||||
}
|
||||
};
|
||||
if field.name != sym::integer(index) {
|
||||
bug!("we parsed above, but now not equal?");
|
||||
}
|
||||
if tys.get(index).is_some() {
|
||||
Ty::new_field_representing_type(tcx, ty, FIRST_VARIANT, index.into())
|
||||
} else {
|
||||
let err = dcx.create_err(NoFieldOnType { span: field.span, field, ty }).emit();
|
||||
Ty::new_error(tcx, err)
|
||||
}
|
||||
}
|
||||
// FIXME(FRTs): support type aliases
|
||||
/*
|
||||
ty::Alias(AliasTyKind::Free, ty) => {
|
||||
return self.lower_field_of(
|
||||
ty,
|
||||
item_def_id,
|
||||
ty_span,
|
||||
hir_id,
|
||||
variant,
|
||||
field,
|
||||
);
|
||||
}*/
|
||||
ty::Alias(..) => Ty::new_error(
|
||||
tcx,
|
||||
dcx.span_err(ty_span, format!("could not resolve fields of `{ty}`")),
|
||||
),
|
||||
ty::Error(err) => Ty::new_error(tcx, *err),
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(_, _)
|
||||
| ty::UnsafeBinder(_)
|
||||
| ty::Dynamic(_, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::CoroutineClosure(_, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::CoroutineWitness(_, _)
|
||||
| ty::Never
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Slice(..) => Ty::new_error(
|
||||
tcx,
|
||||
dcx.span_err(ty_span, format!("type `{ty}` doesn't have fields")),
|
||||
),
|
||||
ty::Infer(_) => Ty::new_error(
|
||||
tcx,
|
||||
dcx.span_err(ty_span, format!("cannot use `{ty}` in this position")),
|
||||
),
|
||||
// FIXME(FRTs): support these types?
|
||||
ty::Array(..) | ty::Pat(..) => Ty::new_error(
|
||||
tcx,
|
||||
dcx.span_err(ty_span, format!("type `{ty}` is not yet supported in `field_of!`")),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option<LocalDefId>) -> Ty<'tcx> {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
use rustc_hir::{
|
||||
BindingMode, ByRef, ConstArg, ConstArgExprField, ConstArgKind, GenericArg, GenericBound,
|
||||
GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind,
|
||||
PreciseCapturingArg, RangeEnd, Term, TyPatKind,
|
||||
PreciseCapturingArg, RangeEnd, Term, TyFieldPath, TyPatKind,
|
||||
};
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym};
|
||||
@@ -464,6 +464,17 @@ fn print_type(&mut self, ty: &hir::Ty<'_>) {
|
||||
self.word(" is ");
|
||||
self.print_ty_pat(pat);
|
||||
}
|
||||
hir::TyKind::FieldOf(ty, TyFieldPath { variant, field }) => {
|
||||
self.word("field_of!(");
|
||||
self.print_type(ty);
|
||||
self.word(", ");
|
||||
if let Some(variant) = *variant {
|
||||
self.print_ident(variant);
|
||||
self.word(".");
|
||||
}
|
||||
self.print_ident(*field);
|
||||
self.word(")");
|
||||
}
|
||||
}
|
||||
self.end(ib)
|
||||
}
|
||||
|
||||
@@ -490,15 +490,6 @@ pub(crate) fn new() -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("no field `{$field}` on type `{$ty}`", code = E0609)]
|
||||
pub(crate) struct NoFieldOnType<'tcx> {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) ty: Ty<'tcx>,
|
||||
pub(crate) field: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("no field named `{$field}` on enum variant `{$container}::{$ident}`", code = E0609)]
|
||||
pub(crate) struct NoFieldOnVariant<'tcx> {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal};
|
||||
use rustc_hir_analysis::NoVariantNamed;
|
||||
use rustc_hir_analysis::errors::NoFieldOnType;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
|
||||
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
@@ -43,7 +44,7 @@
|
||||
use crate::errors::{
|
||||
AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr,
|
||||
BaseExpressionDoubleDotRemove, CantDereference, FieldMultiplySpecifiedInInitializer,
|
||||
FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType,
|
||||
FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn,
|
||||
NoFieldOnVariant, ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive,
|
||||
TypeMismatchFruTypo, YieldExprOutsideOfCoroutine,
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use std::ops::Range;
|
||||
use std::str;
|
||||
|
||||
use rustc_abi::{FIRST_VARIANT, ReprOptions, VariantIdx};
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx, ReprOptions, VariantIdx};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
@@ -15,6 +15,8 @@
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use rustc_session::DataTypeKind;
|
||||
use rustc_span::sym;
|
||||
use rustc_type_ir::FieldInfo;
|
||||
use rustc_type_ir::solve::AdtDestructorKind;
|
||||
use tracing::{debug, info, trace};
|
||||
|
||||
@@ -23,8 +25,8 @@
|
||||
};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::mir::interpret::ErrorHandled;
|
||||
use crate::ty;
|
||||
use crate::ty::util::{Discr, IntTypeExt};
|
||||
use crate::ty::{self, ConstKind};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
|
||||
pub struct AdtFlags(u16);
|
||||
@@ -58,6 +60,8 @@ impl AdtFlags: u16 {
|
||||
const IS_PIN = 1 << 11;
|
||||
/// Indicates whether the type is `#[pin_project]`.
|
||||
const IS_PIN_PROJECT = 1 << 12;
|
||||
/// Indicates whether the type is `FieldRepresentingType`.
|
||||
const IS_FIELD_REPRESENTING_TYPE = 1 << 13;
|
||||
}
|
||||
}
|
||||
rustc_data_structures::external_bitflags_debug! { AdtFlags }
|
||||
@@ -200,6 +204,51 @@ pub fn flags(self) -> AdtFlags {
|
||||
pub fn repr(self) -> ReprOptions {
|
||||
self.0.0.repr
|
||||
}
|
||||
|
||||
pub fn field_representing_type_info(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> Option<FieldInfo<TyCtxt<'tcx>>> {
|
||||
if !self.is_field_representing_type() {
|
||||
return None;
|
||||
}
|
||||
let base = args.type_at(0);
|
||||
let variant_idx = match args.const_at(1).kind() {
|
||||
ConstKind::Value(v) => VariantIdx::from_u32(v.to_leaf().to_u32()),
|
||||
_ => return None,
|
||||
};
|
||||
let field_idx = match args.const_at(2).kind() {
|
||||
ConstKind::Value(v) => FieldIdx::from_u32(v.to_leaf().to_u32()),
|
||||
_ => return None,
|
||||
};
|
||||
let (ty, variant, name) = match base.kind() {
|
||||
ty::Adt(base_def, base_args) => {
|
||||
let variant = base_def.variant(variant_idx);
|
||||
let field = &variant.fields[field_idx];
|
||||
(field.ty(tcx, base_args), base_def.is_enum().then_some(variant.name), field.name)
|
||||
}
|
||||
ty::Tuple(tys) => {
|
||||
if variant_idx != FIRST_VARIANT {
|
||||
bug!("expected variant of tuple to be FIRST_VARIANT, but found {variant_idx:?}")
|
||||
}
|
||||
(
|
||||
if let Some(ty) = tys.get(field_idx.index()) {
|
||||
*ty
|
||||
} else {
|
||||
bug!(
|
||||
"expected valid tuple index, but got {field_idx:?}, tuple length: {}",
|
||||
tys.len()
|
||||
)
|
||||
},
|
||||
None,
|
||||
sym::integer(field_idx.index()),
|
||||
)
|
||||
}
|
||||
_ => panic!(),
|
||||
};
|
||||
Some(FieldInfo { base, ty, variant, variant_idx, name, field_idx })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
|
||||
@@ -211,6 +260,10 @@ fn is_struct(self) -> bool {
|
||||
self.is_struct()
|
||||
}
|
||||
|
||||
fn is_packed(self) -> bool {
|
||||
self.repr().packed()
|
||||
}
|
||||
|
||||
fn struct_tail_ty(self, interner: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
|
||||
Some(interner.type_of(self.non_enum_variant().tail_opt()?.did))
|
||||
}
|
||||
@@ -223,6 +276,14 @@ fn is_manually_drop(self) -> bool {
|
||||
self.is_manually_drop()
|
||||
}
|
||||
|
||||
fn field_representing_type_info(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> Option<FieldInfo<TyCtxt<'tcx>>> {
|
||||
self.field_representing_type_info(tcx, args)
|
||||
}
|
||||
|
||||
fn all_field_tys(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@@ -321,6 +382,9 @@ pub(super) fn new(
|
||||
if tcx.is_lang_item(did, LangItem::Pin) {
|
||||
flags |= AdtFlags::IS_PIN;
|
||||
}
|
||||
if tcx.is_lang_item(did, LangItem::FieldRepresentingType) {
|
||||
flags |= AdtFlags::IS_FIELD_REPRESENTING_TYPE;
|
||||
}
|
||||
|
||||
AdtDefData { did, variants, flags, repr }
|
||||
}
|
||||
@@ -449,6 +513,10 @@ pub fn is_pin_project(self) -> bool {
|
||||
self.flags().contains(AdtFlags::IS_PIN_PROJECT)
|
||||
}
|
||||
|
||||
pub fn is_field_representing_type(self) -> bool {
|
||||
self.flags().contains(AdtFlags::IS_FIELD_REPRESENTING_TYPE)
|
||||
}
|
||||
|
||||
/// Returns `true` if this type has a destructor.
|
||||
pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||
self.destructor(tcx).is_some()
|
||||
|
||||
@@ -755,6 +755,8 @@ fn $to_solver(lang_item: LangItem) -> Option<$solver_ty> {
|
||||
CoroutineReturn,
|
||||
CoroutineYield,
|
||||
DynMetadata,
|
||||
FieldBase,
|
||||
FieldType,
|
||||
FutureOutput,
|
||||
Metadata,
|
||||
// tidy-alphabetical-end
|
||||
@@ -786,6 +788,7 @@ fn $to_solver(lang_item: LangItem) -> Option<$solver_ty> {
|
||||
Destruct,
|
||||
DiscriminantKind,
|
||||
Drop,
|
||||
Field,
|
||||
Fn,
|
||||
FnMut,
|
||||
FnOnce,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use rustc_macros::{Lift, extension};
|
||||
use rustc_session::cstore::{ExternCrate, ExternCrateSource};
|
||||
use rustc_span::{Ident, RemapPathScopeComponents, Symbol, kw, sym};
|
||||
use rustc_type_ir::{Upcast as _, elaborate};
|
||||
use rustc_type_ir::{FieldInfo, Upcast as _, elaborate};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
// `pretty` is a separate module only for organization.
|
||||
@@ -793,6 +793,16 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
|
||||
false => write!(self, "{}", self.tcx().item_name(def_id))?,
|
||||
},
|
||||
},
|
||||
ty::Adt(def, args)
|
||||
if let Some(FieldInfo { base, variant, name, .. }) =
|
||||
def.field_representing_type_info(self.tcx(), args) =>
|
||||
{
|
||||
if let Some(variant) = variant {
|
||||
write!(self, "field_of!({base}, {variant}.{name})")?;
|
||||
} else {
|
||||
write!(self, "field_of!({base}, {name})")?;
|
||||
}
|
||||
}
|
||||
ty::Adt(def, args) => self.print_def_path(def.did(), args)?,
|
||||
ty::Dynamic(data, r) => {
|
||||
let print_r = self.should_print_optional_region(r);
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
use crate::traits::ObligationCause;
|
||||
use crate::ty::InferTy::*;
|
||||
use crate::ty::{
|
||||
self, AdtDef, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv, Region, Ty,
|
||||
TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
|
||||
self, AdtDef, Const, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv, Region,
|
||||
Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, ValTree,
|
||||
};
|
||||
|
||||
// Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
|
||||
@@ -487,6 +487,35 @@ pub fn new_pat(tcx: TyCtxt<'tcx>, base: Ty<'tcx>, pat: ty::Pattern<'tcx>) -> Ty<
|
||||
Ty::new(tcx, Pat(base, pat))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_field_representing_type(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
base: Ty<'tcx>,
|
||||
variant: VariantIdx,
|
||||
field: FieldIdx,
|
||||
) -> Ty<'tcx> {
|
||||
let Some(did) = tcx.lang_items().field_representing_type() else {
|
||||
bug!("could not locate the `FieldRepresentingType` lang item")
|
||||
};
|
||||
let def = tcx.adt_def(did);
|
||||
let args = tcx.mk_args(&[
|
||||
base.into(),
|
||||
Const::new_value(
|
||||
tcx,
|
||||
ValTree::from_scalar_int(tcx, variant.as_u32().into()),
|
||||
tcx.types.u32,
|
||||
)
|
||||
.into(),
|
||||
Const::new_value(
|
||||
tcx,
|
||||
ValTree::from_scalar_int(tcx, field.as_u32().into()),
|
||||
tcx.types.u32,
|
||||
)
|
||||
.into(),
|
||||
]);
|
||||
Ty::new_adt(tcx, def, args)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
|
||||
|
||||
@@ -348,6 +348,11 @@ fn consider_structural_builtin_unsize_candidates(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Vec<Candidate<I>>;
|
||||
|
||||
fn consider_builtin_field_candidate(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
}
|
||||
|
||||
/// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit
|
||||
@@ -617,6 +622,7 @@ fn assemble_builtin_impl_candidates<G: GoalKind<D>>(
|
||||
Some(SolverTraitLangItem::BikeshedGuaranteedNoDrop) => {
|
||||
G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal)
|
||||
}
|
||||
Some(SolverTraitLangItem::Field) => G::consider_builtin_field_candidate(self, goal),
|
||||
_ => Err(NoSolution),
|
||||
}
|
||||
};
|
||||
|
||||
@@ -430,6 +430,13 @@ fn consider_structural_builtin_unsize_candidates(
|
||||
) -> Vec<Candidate<I>> {
|
||||
unreachable!("Unsize is not const")
|
||||
}
|
||||
|
||||
fn consider_builtin_field_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, D>,
|
||||
_goal: Goal<<D as SolverDelegate>::Interner, Self>,
|
||||
) -> Result<Candidate<<D as SolverDelegate>::Interner>, NoSolution> {
|
||||
unreachable!("Field is not const")
|
||||
}
|
||||
}
|
||||
|
||||
impl<D, I> EvalCtxt<'_, D>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
|
||||
use rustc_type_ir::solve::SizedTraitKind;
|
||||
use rustc_type_ir::{self as ty, Interner, NormalizesTo, PredicateKind, Upcast as _};
|
||||
use rustc_type_ir::{self as ty, FieldInfo, Interner, NormalizesTo, PredicateKind, Upcast as _};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
@@ -950,6 +950,29 @@ fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
unreachable!("`BikeshedGuaranteedNoDrop` does not have an associated type: {:?}", goal)
|
||||
}
|
||||
|
||||
fn consider_builtin_field_candidate(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Adt(def, args) = self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
let Some(FieldInfo { base, ty, .. }) = def.field_representing_type_info(ecx.cx(), args)
|
||||
else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
let ty = match ecx.cx().as_lang_item(goal.predicate.def_id()) {
|
||||
Some(SolverLangItem::FieldBase) => base,
|
||||
Some(SolverLangItem::FieldType) => ty,
|
||||
_ => panic!("unexpected associated type {:?} in `Field`", goal.predicate),
|
||||
};
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
ecx.instantiate_normalizes_to_term(goal, ty.into());
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<D, I> EvalCtxt<'_, D>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
AliasBoundKind, CandidatePreferenceMode, CanonicalResponse, SizedTraitKind,
|
||||
};
|
||||
use rustc_type_ir::{
|
||||
self as ty, Interner, Movability, PredicatePolarity, TraitPredicate, TraitRef,
|
||||
self as ty, FieldInfo, Interner, Movability, PredicatePolarity, TraitPredicate, TraitRef,
|
||||
TypeVisitableExt as _, TypingMode, Upcast as _, elaborate,
|
||||
};
|
||||
use tracing::{debug, instrument, trace};
|
||||
@@ -844,6 +844,54 @@ fn consider_structural_builtin_unsize_candidates(
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn consider_builtin_field_candidate(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
if let ty::Adt(def, args) = goal.predicate.self_ty().kind()
|
||||
&& let Some(FieldInfo { base, ty, .. }) =
|
||||
def.field_representing_type_info(ecx.cx(), args)
|
||||
&& {
|
||||
let sized_trait = ecx.cx().require_trait_lang_item(SolverTraitLangItem::Sized);
|
||||
// FIXME: add better support for builtin impls of traits that check for the bounds
|
||||
// on the trait definition in std.
|
||||
|
||||
// NOTE: these bounds have to be kept in sync with the definition of the `Field`
|
||||
// trait in `library/core/src/field.rs` as well as the old trait solver `fn
|
||||
// assemble_candidates_for_field_trait` in
|
||||
// `compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs`.
|
||||
ecx.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
Goal {
|
||||
param_env: goal.param_env,
|
||||
predicate: TraitRef::new(ecx.cx(), sized_trait, [base]).upcast(ecx.cx()),
|
||||
},
|
||||
);
|
||||
ecx.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
Goal {
|
||||
param_env: goal.param_env,
|
||||
predicate: TraitRef::new(ecx.cx(), sized_trait, [ty]).upcast(ecx.cx()),
|
||||
},
|
||||
);
|
||||
ecx.try_evaluate_added_goals()? == Certainty::Yes
|
||||
}
|
||||
&& match base.kind() {
|
||||
ty::Adt(def, _) => def.is_struct() && !def.is_packed(),
|
||||
ty::Tuple(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
{
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Small helper function to change the `def_id` of a trait predicate - this is not normally
|
||||
|
||||
@@ -1140,7 +1140,7 @@ enum FloatComponent {
|
||||
/// Parse the field access used in offset_of, matched by `$(e:expr)+`.
|
||||
/// Currently returns a list of idents. However, it should be possible in
|
||||
/// future to also do array indices, which might be arbitrary expressions.
|
||||
fn parse_floating_field_access(&mut self) -> PResult<'a, Vec<Ident>> {
|
||||
pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, Vec<Ident>> {
|
||||
let mut fields = Vec::new();
|
||||
let mut trailing_dot = None;
|
||||
|
||||
|
||||
@@ -329,6 +329,8 @@ fn parse_ty_common(
|
||||
self.parse_borrowed_pointee()?
|
||||
} else if self.eat_keyword_noexpect(kw::Typeof) {
|
||||
self.parse_typeof_ty(lo)?
|
||||
} else if self.is_builtin() {
|
||||
self.parse_builtin_ty()?
|
||||
} else if self.eat_keyword(exp!(Underscore)) {
|
||||
// A type to be inferred `_`
|
||||
TyKind::Infer
|
||||
@@ -802,6 +804,52 @@ fn parse_typeof_ty(&mut self, lo: Span) -> PResult<'a, TyKind> {
|
||||
Ok(TyKind::Err(guar))
|
||||
}
|
||||
|
||||
fn parse_builtin_ty(&mut self) -> PResult<'a, TyKind> {
|
||||
self.parse_builtin(|this, lo, ident| {
|
||||
Ok(match ident.name {
|
||||
sym::field_of => Some(this.parse_ty_field_of(lo)?),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn parse_ty_field_of(&mut self, _lo: Span) -> PResult<'a, TyKind> {
|
||||
let container = self.parse_ty()?;
|
||||
self.expect(exp!(Comma))?;
|
||||
|
||||
let fields = self.parse_floating_field_access()?;
|
||||
let trailing_comma = self.eat_noexpect(&TokenKind::Comma);
|
||||
|
||||
if let Err(mut e) = self.expect_one_of(&[], &[exp!(CloseParen)]) {
|
||||
if trailing_comma {
|
||||
e.note("unexpected third argument to field_of");
|
||||
} else {
|
||||
e.note("field_of expects dot-separated field and variant names");
|
||||
}
|
||||
e.emit();
|
||||
}
|
||||
|
||||
// Eat tokens until the macro call ends.
|
||||
if self.may_recover() {
|
||||
while !self.token.kind.is_close_delim_or_eof() {
|
||||
self.bump();
|
||||
}
|
||||
}
|
||||
|
||||
match *fields {
|
||||
[] => Err(self.dcx().struct_span_err(
|
||||
self.token.span,
|
||||
"`field_of!` expects dot-separated field and variant names",
|
||||
)),
|
||||
[field] => Ok(TyKind::FieldOf(container, None, field)),
|
||||
[variant, field] => Ok(TyKind::FieldOf(container, Some(variant), field)),
|
||||
_ => Err(self.dcx().struct_span_err(
|
||||
fields.iter().map(|f| f.span).collect::<Vec<_>>(),
|
||||
"`field_of!` only supports a single field or a variant with a field",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a function pointer type (`TyKind::FnPtr`).
|
||||
/// ```ignore (illustrative)
|
||||
/// [unsafe] [extern "ABI"] fn (S) -> T
|
||||
|
||||
@@ -410,6 +410,7 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v, AmbigArg>) {
|
||||
TraitObject,
|
||||
Infer,
|
||||
Pat,
|
||||
FieldOf,
|
||||
Err
|
||||
]
|
||||
);
|
||||
@@ -688,6 +689,7 @@ fn visit_ty(&mut self, t: &'v ast::Ty) {
|
||||
MacCall,
|
||||
CVarArgs,
|
||||
Dummy,
|
||||
FieldOf,
|
||||
Err
|
||||
]
|
||||
);
|
||||
|
||||
@@ -950,7 +950,15 @@
|
||||
ffi_const,
|
||||
ffi_pure,
|
||||
ffi_returns_twice,
|
||||
field,
|
||||
field_base,
|
||||
field_init_shorthand,
|
||||
field_of,
|
||||
field_offset,
|
||||
field_projections,
|
||||
field_representing_type,
|
||||
field_representing_type_raw,
|
||||
field_type,
|
||||
fields,
|
||||
file,
|
||||
final_associated_functions,
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::{
|
||||
self, Term, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode, Upcast,
|
||||
self, FieldInfo, Term, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode, Upcast,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::sym;
|
||||
@@ -987,6 +987,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||
| LangItem::Future
|
||||
| LangItem::Iterator
|
||||
| LangItem::AsyncIterator
|
||||
| LangItem::Field
|
||||
| LangItem::Fn
|
||||
| LangItem::FnMut
|
||||
| LangItem::FnOnce
|
||||
@@ -1547,6 +1548,20 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
|
||||
}
|
||||
});
|
||||
(metadata_ty.into(), obligations)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::Field) {
|
||||
let ty::Adt(def, args) = self_ty.kind() else {
|
||||
bug!("only field representing types can implement `Field`")
|
||||
};
|
||||
let Some(FieldInfo { base, ty, .. }) = def.field_representing_type_info(tcx, args) else {
|
||||
bug!("only field representing types can implement `Field`")
|
||||
};
|
||||
if tcx.is_lang_item(item_def_id, LangItem::FieldBase) {
|
||||
(base.into(), PredicateObligations::new())
|
||||
} else if tcx.is_lang_item(item_def_id, LangItem::FieldType) {
|
||||
(ty.into(), PredicateObligations::new())
|
||||
} else {
|
||||
bug!("unexpected associated type {:?} in `Field`", obligation.predicate);
|
||||
}
|
||||
} else {
|
||||
bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate);
|
||||
};
|
||||
|
||||
@@ -12,14 +12,18 @@
|
||||
use hir::def_id::DefId;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind};
|
||||
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
|
||||
use rustc_infer::traits::{Obligation, PolyTraitObligation, PredicateObligation, SelectionError};
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::{self, SizedTraitKind, Ty, TypeVisitableExt, TypingMode, elaborate};
|
||||
use rustc_middle::ty::{
|
||||
self, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, TypingMode, elaborate,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use super::SelectionCandidate::*;
|
||||
use super::{SelectionCandidateSet, SelectionContext, TraitObligationStack};
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::util;
|
||||
|
||||
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
@@ -128,6 +132,9 @@ pub(super) fn assemble_candidates<'o>(
|
||||
&mut candidates,
|
||||
);
|
||||
}
|
||||
Some(LangItem::Field) => {
|
||||
self.assemble_candidates_for_field_trait(obligation, &mut candidates);
|
||||
}
|
||||
_ => {
|
||||
// We re-match here for traits that can have both builtin impls and user written impls.
|
||||
// After the builtin impls we need to also add user written impls, which we do not want to
|
||||
@@ -1439,4 +1446,52 @@ fn assemble_candidates_for_bikeshed_guaranteed_no_drop_trait(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_candidates_for_field_trait(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||
) {
|
||||
if let ty::Adt(def, args) = obligation.predicate.self_ty().skip_binder().kind()
|
||||
&& let Some(FieldInfo { base, ty, .. }) =
|
||||
def.field_representing_type_info(self.tcx(), args)
|
||||
// NOTE: these bounds have to be kept in sync with the definition of the `Field` trait
|
||||
// in `library/core/src/field.rs` as well as the new trait solver `fn
|
||||
// consider_builtin_field_candidate` in
|
||||
// `compiler/rustc_next_trait_solver/src/solve/trait_goals.rs`.
|
||||
&& match self.infcx.evaluate_obligation(&PredicateObligation::new(
|
||||
self.tcx(),
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env,
|
||||
TraitRef::new(
|
||||
self.tcx(),
|
||||
self.tcx().require_lang_item(LangItem::Sized, DUMMY_SP),
|
||||
[base],
|
||||
),
|
||||
)) {
|
||||
Ok(res) if res.must_apply_modulo_regions() => true,
|
||||
_ => false,
|
||||
}
|
||||
&& match self.infcx.evaluate_obligation(&PredicateObligation::new(
|
||||
self.tcx(),
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env,
|
||||
TraitRef::new(
|
||||
self.tcx(),
|
||||
self.tcx().require_lang_item(LangItem::Sized, DUMMY_SP),
|
||||
[ty],
|
||||
),
|
||||
)) {
|
||||
Ok(res) if res.must_apply_modulo_regions() => true,
|
||||
_ => false,
|
||||
}
|
||||
&& match base.kind() {
|
||||
ty::Adt(def, _) => def.is_struct() && !def.repr().packed(),
|
||||
ty::Tuple(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
{
|
||||
candidates.vec.push(BuiltinCandidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +262,7 @@ fn confirm_builtin_candidate(
|
||||
Some(
|
||||
LangItem::Destruct
|
||||
| LangItem::DiscriminantKind
|
||||
| LangItem::Field
|
||||
| LangItem::FnPtrTrait
|
||||
| LangItem::PointeeTrait
|
||||
| LangItem::Tuple
|
||||
|
||||
@@ -386,6 +386,22 @@ fn resolve_associated_item<'tcx>(
|
||||
assert_eq!(name, sym::transmute);
|
||||
let args = tcx.erase_and_anonymize_regions(rcvr_args);
|
||||
Some(ty::Instance::new_raw(trait_item_id, args))
|
||||
} else if tcx.is_lang_item(trait_ref.def_id, LangItem::Field) {
|
||||
if tcx.is_lang_item(trait_item_id, LangItem::FieldOffset) {
|
||||
let self_ty = trait_ref.self_ty();
|
||||
match self_ty.kind() {
|
||||
ty::Adt(def, _) if def.is_field_representing_type() => {}
|
||||
_ => bug!("expected field representing type, found {self_ty}"),
|
||||
}
|
||||
Some(Instance {
|
||||
def: ty::InstanceKind::Item(
|
||||
tcx.lang_items().get(LangItem::FieldOffset).unwrap(),
|
||||
),
|
||||
args: rcvr_args,
|
||||
})
|
||||
} else {
|
||||
bug!("unexpected associated associated item")
|
||||
}
|
||||
} else {
|
||||
Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ derive-where = "1.2.7"
|
||||
ena = "0.14.4"
|
||||
indexmap = "2.0.0"
|
||||
rustc-hash = "2.0.0"
|
||||
rustc_abi = { path = "../rustc_abi", default-features = false }
|
||||
rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
|
||||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||
rustc_error_messages = { path = "../rustc_error_messages", optional = true }
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::{AdtDestructorKind, SizedTraitKind};
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{self as ty, ClauseKind, CollectAndApply, Interner, PredicateKind, UpcastFrom};
|
||||
use crate::{
|
||||
self as ty, ClauseKind, CollectAndApply, FieldInfo, Interner, PredicateKind, UpcastFrom,
|
||||
};
|
||||
|
||||
pub trait Ty<I: Interner<Ty = Self>>:
|
||||
Copy
|
||||
@@ -577,6 +579,8 @@ pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
|
||||
|
||||
fn is_struct(self) -> bool;
|
||||
|
||||
fn is_packed(self) -> bool;
|
||||
|
||||
/// Returns the type of the struct tail.
|
||||
///
|
||||
/// Expects the `AdtDef` to be a struct. If it is not, then this will panic.
|
||||
@@ -586,6 +590,12 @@ pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
|
||||
|
||||
fn is_manually_drop(self) -> bool;
|
||||
|
||||
fn field_representing_type_info(
|
||||
self,
|
||||
interner: I,
|
||||
args: I::GenericArgs,
|
||||
) -> Option<FieldInfo<I>>;
|
||||
|
||||
// FIXME: perhaps use `all_fields` and expose `FieldDef`.
|
||||
fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl IntoIterator<Item = I::Ty>>;
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ pub enum SolverLangItem {
|
||||
CoroutineReturn,
|
||||
CoroutineYield,
|
||||
DynMetadata,
|
||||
FieldBase,
|
||||
FieldType,
|
||||
FutureOutput,
|
||||
Metadata,
|
||||
// tidy-alphabetical-end
|
||||
@@ -36,6 +38,7 @@ pub enum SolverTraitLangItem {
|
||||
Destruct,
|
||||
DiscriminantKind,
|
||||
Drop,
|
||||
Field,
|
||||
Fn,
|
||||
FnMut,
|
||||
FnOnce,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_NoContext};
|
||||
|
||||
@@ -440,3 +441,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.as_str().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldInfo<I: Interner> {
|
||||
pub base: I::Ty,
|
||||
pub ty: I::Ty,
|
||||
pub variant: Option<I::Symbol>,
|
||||
pub variant_idx: VariantIdx,
|
||||
pub name: I::Symbol,
|
||||
pub field_idx: FieldIdx,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
//! Field Reflection
|
||||
|
||||
use crate::marker::PhantomData;
|
||||
|
||||
/// Field Representing Type
|
||||
#[unstable(feature = "field_representing_type_raw", issue = "none")]
|
||||
#[lang = "field_representing_type"]
|
||||
#[expect(missing_debug_implementations)]
|
||||
#[fundamental]
|
||||
pub struct FieldRepresentingType<T: ?Sized, const VARIANT: u32, const FIELD: u32> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
// SAFETY: `FieldRepresentingType` doesn't contain any `T`
|
||||
unsafe impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Send
|
||||
for FieldRepresentingType<T, VARIANT, FIELD>
|
||||
{
|
||||
}
|
||||
|
||||
// SAFETY: `FieldRepresentingType` doesn't contain any `T`
|
||||
unsafe impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Sync
|
||||
for FieldRepresentingType<T, VARIANT, FIELD>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Copy
|
||||
for FieldRepresentingType<T, VARIANT, FIELD>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Clone
|
||||
for FieldRepresentingType<T, VARIANT, FIELD>
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
/// Expands to the field representing type of the given field.
|
||||
///
|
||||
/// The container type may be a tuple, `struct`, `union` or `enum`. In the case of an enum, the
|
||||
/// variant must also be specified. Only a single field is supported.
|
||||
#[unstable(feature = "field_projections", issue = "145383")]
|
||||
#[allow_internal_unstable(field_representing_type_raw, builtin_syntax)]
|
||||
// NOTE: when stabilizing this macro, we can never add new trait impls for `FieldRepresentingType`,
|
||||
// since it is `#[fundamental]` and thus could break users of this macro, since the compiler expands
|
||||
// it to `FieldRepresentingType<...>`. Thus stabilizing this requires careful thought about the
|
||||
// completeness of the trait impls for `FieldRepresentingType`.
|
||||
pub macro field_of($Container:ty, $($fields:expr)+ $(,)?) {
|
||||
builtin # field_of($Container, $($fields)+)
|
||||
}
|
||||
|
||||
/// Type representing a field of a `struct`, `union`, `enum` variant or tuple.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Given a valid value of type `Self::Base`, there exists a valid value of type `Self::Type` at
|
||||
/// byte offset `OFFSET`
|
||||
#[lang = "field"]
|
||||
#[unstable(feature = "field_projections", issue = "145383")]
|
||||
#[rustc_deny_explicit_impl]
|
||||
#[rustc_dyn_incompatible_trait]
|
||||
// NOTE: the compiler provides the impl of `Field` for `FieldRepresentingType` when it can guarantee
|
||||
// the safety requirements of this trait. It also has to manually add the correct trait bounds on
|
||||
// associated types (and the `Self` type). Thus any changes to the bounds here must be reflected in
|
||||
// the old and new trait solver:
|
||||
// - `fn assemble_candidates_for_field_trait` in
|
||||
// `compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs`, and
|
||||
// - `fn consider_builtin_field_candidate` in
|
||||
// `compiler/rustc_next_trait_solver/src/solve/trait_goals.rs`.
|
||||
pub unsafe trait Field: Send + Sync + Copy {
|
||||
/// The type of the base where this field exists in.
|
||||
#[lang = "field_base"]
|
||||
type Base;
|
||||
|
||||
/// The type of the field.
|
||||
#[lang = "field_type"]
|
||||
type Type;
|
||||
|
||||
/// The offset of the field in bytes.
|
||||
#[lang = "field_offset"]
|
||||
const OFFSET: usize = crate::intrinsics::field_offset::<Self>();
|
||||
}
|
||||
@@ -2812,6 +2812,20 @@ pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(
|
||||
#[lang = "offset_of"]
|
||||
pub const fn offset_of<T: PointeeSized>(variant: u32, field: u32) -> usize;
|
||||
|
||||
/// The offset of a field queried by its field representing type.
|
||||
///
|
||||
/// Returns the offset of the field represented by `F`. This function essentially does the same as
|
||||
/// the [`offset_of`] intrinsic, but expects the field to be represented by a generic rather than
|
||||
/// the variant and field indices. This also is a safe intrinsic and can only be evaluated at
|
||||
/// compile-time, so it should only appear in constants or inline const blocks.
|
||||
///
|
||||
/// There should be no need to call this intrinsic manually, as its value is used to define
|
||||
/// [`Field::OFFSET`](crate::field::Field::OFFSET), which is publicly accessible.
|
||||
#[rustc_intrinsic]
|
||||
#[unstable(feature = "field_projections", issue = "145383")]
|
||||
#[rustc_const_unstable(feature = "field_projections", issue = "145383")]
|
||||
pub const fn field_offset<F: crate::field::Field>() -> usize;
|
||||
|
||||
/// Returns the number of variants of the type `T` cast to a `usize`;
|
||||
/// if `T` has no variants, returns `0`. Uninhabited variants will be counted.
|
||||
///
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
#![feature(extern_types)]
|
||||
#![feature(f16)]
|
||||
#![feature(f128)]
|
||||
#![feature(field_projections)]
|
||||
#![feature(freeze_impls)]
|
||||
#![feature(fundamental)]
|
||||
#![feature(funnel_shifts)]
|
||||
@@ -274,6 +275,8 @@ pub mod autodiff {
|
||||
pub mod convert;
|
||||
pub mod default;
|
||||
pub mod error;
|
||||
#[unstable(feature = "field_projections", issue = "145383")]
|
||||
pub mod field;
|
||||
pub mod index;
|
||||
pub mod marker;
|
||||
pub mod ops;
|
||||
|
||||
@@ -495,6 +495,8 @@
|
||||
pub use core::convert;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::default;
|
||||
#[unstable(feature = "field_projections", issue = "145383")]
|
||||
pub use core::field;
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
pub use core::future;
|
||||
#[stable(feature = "core_hint", since = "1.27.0")]
|
||||
|
||||
@@ -1809,6 +1809,14 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
||||
}
|
||||
TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
|
||||
TyKind::Pat(ty, pat) => Type::Pat(Box::new(clean_ty(ty, cx)), format!("{pat:?}").into()),
|
||||
TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => {
|
||||
let field_str = if let Some(variant) = variant {
|
||||
format!("{variant}.{field}")
|
||||
} else {
|
||||
format!("{field}")
|
||||
};
|
||||
Type::FieldOf(Box::new(clean_ty(ty, cx)), field_str.into())
|
||||
}
|
||||
TyKind::Array(ty, const_arg) => {
|
||||
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants
|
||||
// as we currently do not supply the parent generics to anonymous constants
|
||||
|
||||
@@ -1349,6 +1349,7 @@ pub(crate) enum Type {
|
||||
/// The `String` field is a stringified version of the array's length parameter.
|
||||
Array(Box<Type>, Box<str>),
|
||||
Pat(Box<Type>, Box<str>),
|
||||
FieldOf(Box<Type>, Box<str>),
|
||||
/// A raw pointer type: `*const i32`, `*mut i32`
|
||||
RawPointer(Mutability, Box<Type>),
|
||||
/// A reference type: `&i32`, `&'a mut Foo`
|
||||
@@ -1562,6 +1563,7 @@ pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
|
||||
Slice(..) => PrimitiveType::Slice,
|
||||
Array(..) => PrimitiveType::Array,
|
||||
Type::Pat(..) => PrimitiveType::Pat,
|
||||
Type::FieldOf(..) => PrimitiveType::FieldOf,
|
||||
RawPointer(..) => PrimitiveType::RawPointer,
|
||||
QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
|
||||
Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
|
||||
@@ -1609,6 +1611,7 @@ pub(crate) enum PrimitiveType {
|
||||
Slice,
|
||||
Array,
|
||||
Pat,
|
||||
FieldOf,
|
||||
Tuple,
|
||||
Unit,
|
||||
RawPointer,
|
||||
@@ -1764,6 +1767,7 @@ pub(crate) fn as_sym(&self) -> Symbol {
|
||||
Char => sym::char,
|
||||
Array => sym::array,
|
||||
Pat => sym::pat,
|
||||
FieldOf => sym::field_of,
|
||||
Slice => sym::slice,
|
||||
Tuple => sym::tuple,
|
||||
Unit => sym::unit,
|
||||
|
||||
@@ -967,6 +967,11 @@ fn fmt_type(
|
||||
fmt::Display::fmt(&print_type(t, cx), f)?;
|
||||
write!(f, " is {pat}")
|
||||
}
|
||||
clean::Type::FieldOf(t, field) => {
|
||||
write!(f, "field_of!(")?;
|
||||
fmt::Display::fmt(&print_type(t, cx), f)?;
|
||||
write!(f, ", {field})")
|
||||
}
|
||||
clean::Array(box clean::Generic(name), n) if !f.alternate() => primitive_link(
|
||||
f,
|
||||
PrimitiveType::Array,
|
||||
|
||||
@@ -2049,6 +2049,7 @@ fn get_index_type_id(
|
||||
}
|
||||
// Not supported yet
|
||||
clean::Type::Pat(..)
|
||||
| clean::Type::FieldOf(..)
|
||||
| clean::Generic(_)
|
||||
| clean::SelfTy
|
||||
| clean::ImplTrait(_)
|
||||
|
||||
@@ -579,6 +579,8 @@ fn from_clean(ty: &clean::Type, renderer: &JsonRenderer<'_>) -> Self {
|
||||
type_: Box::new(t.into_json(renderer)),
|
||||
__pat_unstable_do_not_use: p.to_string(),
|
||||
},
|
||||
// FIXME(FRTs): implement
|
||||
clean::Type::FieldOf(..) => todo!(),
|
||||
ImplTrait(g) => Type::ImplTrait(g.into_json(renderer)),
|
||||
Infer => Type::Infer,
|
||||
RawPointer(mutability, type_) => Type::RawPointer {
|
||||
|
||||
@@ -852,6 +852,7 @@ fn for_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Self {
|
||||
| TyKind::Ptr(_)
|
||||
| TyKind::FnPtr(_)
|
||||
| TyKind::Pat(..)
|
||||
| TyKind::FieldOf(..)
|
||||
| TyKind::Never
|
||||
| TyKind::Tup(_)
|
||||
| TyKind::Path(_) => Self::Deref,
|
||||
|
||||
@@ -531,6 +531,7 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) {
|
||||
|
||||
// experimental
|
||||
| TyKind::Pat(..)
|
||||
| TyKind::FieldOf(..)
|
||||
|
||||
// unused
|
||||
| TyKind::CVarArgs
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
GenericParam, GenericParamKind, GenericParamSource, Generics, HirId, HirIdMap, InlineAsmOperand, ItemId, ItemKind,
|
||||
LetExpr, Lifetime, LifetimeKind, LifetimeParamKind, Node, ParamName, Pat, PatExpr, PatExprKind, PatField, PatKind,
|
||||
Path, PathSegment, PreciseCapturingArgKind, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty,
|
||||
TyKind, TyPat, TyPatKind, UseKind, WherePredicate, WherePredicateKind,
|
||||
TyFieldPath, TyKind, TyPat, TyPatKind, UseKind, WherePredicate, WherePredicateKind,
|
||||
};
|
||||
use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
|
||||
use rustc_lint::LateContext;
|
||||
@@ -1529,6 +1529,13 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
|
||||
self.hash_ty(ty);
|
||||
self.hash_ty_pat(pat);
|
||||
},
|
||||
TyKind::FieldOf(base, TyFieldPath { variant, field }) => {
|
||||
self.hash_ty(base);
|
||||
if let Some(variant) = variant {
|
||||
self.hash_name(variant.name);
|
||||
}
|
||||
self.hash_name(field.name);
|
||||
},
|
||||
TyKind::Ptr(mut_ty) => {
|
||||
self.hash_ty(mut_ty.ty);
|
||||
mut_ty.mutbl.hash(&mut self.s);
|
||||
|
||||
@@ -257,7 +257,6 @@ macro_rules! generate {
|
||||
f64_legacy_const_nan,
|
||||
f64_legacy_const_neg_infinity,
|
||||
f64_legacy_const_radix,
|
||||
field,
|
||||
file_options,
|
||||
filter,
|
||||
filter_map,
|
||||
|
||||
@@ -1030,6 +1030,14 @@ fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteR
|
||||
let pat = pat.rewrite_result(context, shape)?;
|
||||
Ok(format!("{ty} is {pat}"))
|
||||
}
|
||||
ast::TyKind::FieldOf(ref ty, ref variant, ref field) => {
|
||||
let ty = ty.rewrite_result(context, shape)?;
|
||||
if let Some(variant) = variant {
|
||||
Ok(format!("builtin # field_of({ty}, {variant}.{field})"))
|
||||
} else {
|
||||
Ok(format!("builtin # field_of({ty}, {field})"))
|
||||
}
|
||||
}
|
||||
ast::TyKind::UnsafeBinder(ref binder) => {
|
||||
let mut result = String::new();
|
||||
if binder.generic_params.is_empty() {
|
||||
|
||||
@@ -597,6 +597,12 @@ See:
|
||||
- [`ffi_const` | The Unstable book](https://doc.rust-lang.org/unstable-book/language-features/ffi-const.html)
|
||||
- [`ffi_pure` | The Unstable book](https://doc.rust-lang.org/beta/unstable-book/language-features/ffi-pure.html)
|
||||
|
||||
## `tests/ui/field_representing_types`: `#![feature(field_projections)]`
|
||||
|
||||
Tests for field representing types `field_of!(Struct, field)`.
|
||||
|
||||
See: [Tracking Issue for Field Projections #145383](https://github.com/rust-lang/rust/issues/145383)
|
||||
|
||||
## `tests/ui/float`
|
||||
|
||||
See: [Tracking Issue for `f16` and `f128` float types #116909](https://github.com/rust-lang/rust/issues/116909)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
use std::field::{Field, field_of}; //~ ERROR: use of unstable library feature `field_projections` [E0658]
|
||||
//~^ ERROR: use of unstable library feature `field_projections` [E0658]
|
||||
use std::ptr;
|
||||
|
||||
fn project_ref<F: Field>(
|
||||
//~^ ERROR: use of unstable library feature `field_projections` [E0658]
|
||||
r: &F::Base, //~ ERROR: use of unstable library feature `field_projections` [E0658]
|
||||
) -> &F::Type
|
||||
//~^ ERROR: use of unstable library feature `field_projections` [E0658]
|
||||
where
|
||||
F::Type: Sized, //~ ERROR: use of unstable library feature `field_projections` [E0658]
|
||||
{
|
||||
unsafe { &*ptr::from_ref(r).byte_add(F::OFFSET).cast() } //~ ERROR: use of unstable library feature `field_projections` [E0658]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
struct Foo(());
|
||||
let _ = project_ref::<field_of!(Foo, 0)>(&Foo(())); //~ ERROR: use of unstable library feature `field_projections` [E0658]
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
error[E0658]: use of unstable library feature `field_projections`
|
||||
--> $DIR/feature-gate-field-projections.rs:18:27
|
||||
|
|
||||
LL | let _ = project_ref::<field_of!(Foo, 0)>(&Foo(()));
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
|
||||
= help: add `#![feature(field_projections)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: use of unstable library feature `field_projections`
|
||||
--> $DIR/feature-gate-field-projections.rs:1:18
|
||||
|
|
||||
LL | use std::field::{Field, field_of};
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
|
||||
= help: add `#![feature(field_projections)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: use of unstable library feature `field_projections`
|
||||
--> $DIR/feature-gate-field-projections.rs:1:25
|
||||
|
|
||||
LL | use std::field::{Field, field_of};
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
|
||||
= help: add `#![feature(field_projections)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: use of unstable library feature `field_projections`
|
||||
--> $DIR/feature-gate-field-projections.rs:5:19
|
||||
|
|
||||
LL | fn project_ref<F: Field>(
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
|
||||
= help: add `#![feature(field_projections)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: use of unstable library feature `field_projections`
|
||||
--> $DIR/feature-gate-field-projections.rs:11:5
|
||||
|
|
||||
LL | F::Type: Sized,
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
|
||||
= help: add `#![feature(field_projections)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: use of unstable library feature `field_projections`
|
||||
--> $DIR/feature-gate-field-projections.rs:7:9
|
||||
|
|
||||
LL | r: &F::Base,
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
|
||||
= help: add `#![feature(field_projections)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: use of unstable library feature `field_projections`
|
||||
--> $DIR/feature-gate-field-projections.rs:8:7
|
||||
|
|
||||
LL | ) -> &F::Type
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
|
||||
= help: add `#![feature(field_projections)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: use of unstable library feature `field_projections`
|
||||
--> $DIR/feature-gate-field-projections.rs:13:42
|
||||
|
|
||||
LL | unsafe { &*ptr::from_ref(r).byte_add(F::OFFSET).cast() }
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
|
||||
= help: add `#![feature(field_projections)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
@@ -0,0 +1,4 @@
|
||||
use std::field::FieldRepresentingType;
|
||||
//~^ ERROR: use of unstable library feature `field_representing_type_raw` [E0658]
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,12 @@
|
||||
error[E0658]: use of unstable library feature `field_representing_type_raw`
|
||||
--> $DIR/feature-gate-field-representing-type-raw.rs:1:5
|
||||
|
|
||||
LL | use std::field::FieldRepresentingType;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(field_representing_type_raw)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
@@ -0,0 +1,6 @@
|
||||
pub struct Point {
|
||||
pub x: usize,
|
||||
pub y: usize,
|
||||
}
|
||||
|
||||
pub trait ForeignTrait {}
|
||||
@@ -0,0 +1,27 @@
|
||||
error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
|
||||
--> $DIR/incoherent-impl.rs:22:1
|
||||
|
|
||||
LL | impl ForeignTrait for field_of!(Point, x) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^-------------------
|
||||
| |
|
||||
| `Point` is not defined in the current crate
|
||||
|
|
||||
= note: impl doesn't have any local type before any uncovered type parameters
|
||||
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
|
||||
= note: define and implement a trait or new type instead
|
||||
|
||||
error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
|
||||
--> $DIR/incoherent-impl.rs:25:1
|
||||
|
|
||||
LL | impl ForeignTrait for field_of!((usize, usize), 0) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^----------------------------
|
||||
| |
|
||||
| this is not defined in the current crate because tuples are always foreign
|
||||
|
|
||||
= note: impl doesn't have any local type before any uncovered type parameters
|
||||
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
|
||||
= note: define and implement a trait or new type instead
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0117`.
|
||||
@@ -0,0 +1,27 @@
|
||||
error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
|
||||
--> $DIR/incoherent-impl.rs:22:1
|
||||
|
|
||||
LL | impl ForeignTrait for field_of!(Point, x) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^-------------------
|
||||
| |
|
||||
| `Point` is not defined in the current crate
|
||||
|
|
||||
= note: impl doesn't have any local type before any uncovered type parameters
|
||||
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
|
||||
= note: define and implement a trait or new type instead
|
||||
|
||||
error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
|
||||
--> $DIR/incoherent-impl.rs:25:1
|
||||
|
|
||||
LL | impl ForeignTrait for field_of!((usize, usize), 0) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^----------------------------
|
||||
| |
|
||||
| this is not defined in the current crate because tuples are always foreign
|
||||
|
|
||||
= note: impl doesn't have any local type before any uncovered type parameters
|
||||
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
|
||||
= note: define and implement a trait or new type instead
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0117`.
|
||||
@@ -0,0 +1,28 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
//@ aux-build:extern-crate.rs
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(field_projections)]
|
||||
extern crate extern_crate;
|
||||
|
||||
use std::field::field_of;
|
||||
|
||||
use extern_crate::{ForeignTrait, Point};
|
||||
|
||||
pub trait MyTrait {}
|
||||
|
||||
impl MyTrait for field_of!(Point, x) {}
|
||||
impl MyTrait for field_of!(Player, pos) {}
|
||||
impl MyTrait for field_of!((usize, usize), 0) {}
|
||||
|
||||
pub struct Player {
|
||||
pos: Point,
|
||||
}
|
||||
|
||||
impl ForeignTrait for field_of!(Point, x) {}
|
||||
//~^ ERROR: only traits defined in the current crate can be implemented for types defined outside of the crate [E0117]
|
||||
impl ForeignTrait for field_of!(Player, pos) {}
|
||||
impl ForeignTrait for field_of!((usize, usize), 0) {}
|
||||
//~^ ERROR: only traits defined in the current crate can be implemented for types defined outside of the crate [E0117]
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,71 @@
|
||||
error: unexpected end of macro invocation
|
||||
--> $DIR/invalid.rs:23:28
|
||||
|
|
||||
LL | let _: field_of!(Struct);
|
||||
| ^ missing tokens in macro arguments
|
||||
|
|
||||
note: while trying to match `,`
|
||||
--> $SRC_DIR/core/src/field.rs:LL:COL
|
||||
|
||||
error: unexpected end of macro invocation
|
||||
--> $DIR/invalid.rs:24:29
|
||||
|
|
||||
LL | let _: field_of!(Struct,);
|
||||
| ^ missing tokens in macro arguments
|
||||
|
|
||||
note: while trying to match meta-variable `$fields:expr`
|
||||
--> $SRC_DIR/core/src/field.rs:LL:COL
|
||||
|
||||
error: no rules expected `extra`
|
||||
--> $DIR/invalid.rs:25:37
|
||||
|
|
||||
LL | let _: field_of!(Struct, field, extra);
|
||||
| ^^^^^ no rules expected this token in macro call
|
||||
|
|
||||
= note: while trying to match sequence end
|
||||
|
||||
error: offset_of expects dot-separated field and variant names
|
||||
--> $DIR/invalid.rs:27:28
|
||||
|
|
||||
LL | let _: field_of!(Enum, Variant..field);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: `field_of!` expects dot-separated field and variant names
|
||||
--> $DIR/invalid.rs:27:12
|
||||
|
|
||||
LL | let _: field_of!(Enum, Variant..field);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| in this macro invocation
|
||||
| this macro call doesn't expand to a type
|
||||
|
|
||||
= note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: offset_of expects dot-separated field and variant names
|
||||
--> $DIR/invalid.rs:29:30
|
||||
|
|
||||
LL | let _: field_of!(Struct, [42]);
|
||||
| ^^^^
|
||||
|
||||
error: `field_of!` expects dot-separated field and variant names
|
||||
--> $DIR/invalid.rs:29:12
|
||||
|
|
||||
LL | let _: field_of!(Struct, [42]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| in this macro invocation
|
||||
| this macro call doesn't expand to a type
|
||||
|
|
||||
= note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: `field_of!` only supports a single field or a variant with a field
|
||||
--> $DIR/invalid.rs:31:30
|
||||
|
|
||||
LL | let _: field_of!(Struct, field1.field2.field3);
|
||||
| ------------------^^^^^^-^^^^^^-^^^^^^-
|
||||
| |
|
||||
| in this macro invocation
|
||||
| this macro call doesn't expand to a type
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
error: unexpected end of macro invocation
|
||||
--> $DIR/invalid.rs:23:28
|
||||
|
|
||||
LL | let _: field_of!(Struct);
|
||||
| ^ missing tokens in macro arguments
|
||||
|
|
||||
note: while trying to match `,`
|
||||
--> $SRC_DIR/core/src/field.rs:LL:COL
|
||||
|
||||
error: unexpected end of macro invocation
|
||||
--> $DIR/invalid.rs:24:29
|
||||
|
|
||||
LL | let _: field_of!(Struct,);
|
||||
| ^ missing tokens in macro arguments
|
||||
|
|
||||
note: while trying to match meta-variable `$fields:expr`
|
||||
--> $SRC_DIR/core/src/field.rs:LL:COL
|
||||
|
||||
error: no rules expected `extra`
|
||||
--> $DIR/invalid.rs:25:37
|
||||
|
|
||||
LL | let _: field_of!(Struct, field, extra);
|
||||
| ^^^^^ no rules expected this token in macro call
|
||||
|
|
||||
= note: while trying to match sequence end
|
||||
|
||||
error: offset_of expects dot-separated field and variant names
|
||||
--> $DIR/invalid.rs:27:28
|
||||
|
|
||||
LL | let _: field_of!(Enum, Variant..field);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: `field_of!` expects dot-separated field and variant names
|
||||
--> $DIR/invalid.rs:27:12
|
||||
|
|
||||
LL | let _: field_of!(Enum, Variant..field);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| in this macro invocation
|
||||
| this macro call doesn't expand to a type
|
||||
|
|
||||
= note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: offset_of expects dot-separated field and variant names
|
||||
--> $DIR/invalid.rs:29:30
|
||||
|
|
||||
LL | let _: field_of!(Struct, [42]);
|
||||
| ^^^^
|
||||
|
||||
error: `field_of!` expects dot-separated field and variant names
|
||||
--> $DIR/invalid.rs:29:12
|
||||
|
|
||||
LL | let _: field_of!(Struct, [42]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| in this macro invocation
|
||||
| this macro call doesn't expand to a type
|
||||
|
|
||||
= note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: `field_of!` only supports a single field or a variant with a field
|
||||
--> $DIR/invalid.rs:31:30
|
||||
|
|
||||
LL | let _: field_of!(Struct, field1.field2.field3);
|
||||
| ------------------^^^^^^-^^^^^^-^^^^^^-
|
||||
| |
|
||||
| in this macro invocation
|
||||
| this macro call doesn't expand to a type
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(field_projections)]
|
||||
|
||||
use std::field::field_of;
|
||||
|
||||
pub struct Struct {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
pub union Union {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
pub enum Enum {
|
||||
Variant { field: i32 },
|
||||
}
|
||||
|
||||
pub trait Trait {}
|
||||
|
||||
fn main() {
|
||||
let _: field_of!(Struct); //~ ERROR: unexpected end of macro invocation
|
||||
let _: field_of!(Struct,); //~ ERROR: unexpected end of macro invocation
|
||||
let _: field_of!(Struct, field, extra); //~ ERROR: no rules expected `extra`
|
||||
// FIXME(FRTs): adjust error message to mention `field_of!` & prevent double errors
|
||||
let _: field_of!(Enum, Variant..field); //~ ERROR: offset_of expects dot-separated field and variant names
|
||||
//~^ ERROR: `field_of!` expects dot-separated field and variant names
|
||||
let _: field_of!(Struct, [42]); //~ ERROR: offset_of expects dot-separated field and variant names
|
||||
//~^ ERROR: `field_of!` expects dot-separated field and variant names
|
||||
let _: field_of!(Struct, field1.field2.field3); //~ ERROR: `field_of!` only supports a single field or a variant with a field
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
error[E0277]: the trait bound `field_of!(MyUnion, field): std::field::Field` is not satisfied
|
||||
--> $DIR/non-struct.rs:22:20
|
||||
|
|
||||
LL | assert_field::<field_of!(MyUnion, field)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyUnion, field)`
|
||||
|
|
||||
note: required by a bound in `assert_field`
|
||||
--> $DIR/non-struct.rs:18:20
|
||||
|
|
||||
LL | fn assert_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `assert_field`
|
||||
|
||||
error[E0277]: the trait bound `field_of!(MyEnum, A.a): std::field::Field` is not satisfied
|
||||
--> $DIR/non-struct.rs:25:20
|
||||
|
|
||||
LL | assert_field::<field_of!(MyEnum, A.a)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyEnum, A.a)`
|
||||
|
|
||||
note: required by a bound in `assert_field`
|
||||
--> $DIR/non-struct.rs:18:20
|
||||
|
|
||||
LL | fn assert_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `assert_field`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -0,0 +1,27 @@
|
||||
error[E0277]: the trait bound `field_of!(MyUnion, field): std::field::Field` is not satisfied
|
||||
--> $DIR/non-struct.rs:22:20
|
||||
|
|
||||
LL | assert_field::<field_of!(MyUnion, field)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyUnion, field)`
|
||||
|
|
||||
note: required by a bound in `assert_field`
|
||||
--> $DIR/non-struct.rs:18:20
|
||||
|
|
||||
LL | fn assert_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `assert_field`
|
||||
|
||||
error[E0277]: the trait bound `field_of!(MyEnum, A.a): std::field::Field` is not satisfied
|
||||
--> $DIR/non-struct.rs:25:20
|
||||
|
|
||||
LL | assert_field::<field_of!(MyEnum, A.a)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyEnum, A.a)`
|
||||
|
|
||||
note: required by a bound in `assert_field`
|
||||
--> $DIR/non-struct.rs:18:20
|
||||
|
|
||||
LL | fn assert_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `assert_field`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -0,0 +1,27 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(field_projections)]
|
||||
|
||||
use std::field::{Field, field_of};
|
||||
|
||||
pub union MyUnion {
|
||||
field: u32,
|
||||
other: i32,
|
||||
}
|
||||
|
||||
pub enum MyEnum {
|
||||
A { a: i32, b: i64 },
|
||||
B { x: i64, y: i32 },
|
||||
}
|
||||
|
||||
fn assert_field<F: Field>() {}
|
||||
|
||||
fn main() {
|
||||
// FIXME(FRTs): improve this error message, point to the `union`.
|
||||
assert_field::<field_of!(MyUnion, field)>();
|
||||
//~^ ERROR: the trait bound `field_of!(MyUnion, field): std::field::Field` is not satisfied [E0277]
|
||||
// FIXME(FRTs): improve this error message, point to the `enum`.
|
||||
assert_field::<field_of!(MyEnum, A.a)>();
|
||||
//~^ ERROR: the trait bound `field_of!(MyEnum, A.a): std::field::Field` is not satisfied [E0277]
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
error[E0573]: expected type, found function `main`
|
||||
--> $DIR/nonexistent.rs:43:22
|
||||
|
|
||||
LL | let _: field_of!(main, field);
|
||||
| ^^^^ not a type
|
||||
|
||||
error[E0609]: no field `other` on type `Struct`
|
||||
--> $DIR/nonexistent.rs:23:30
|
||||
|
|
||||
LL | let _: field_of!(Struct, other);
|
||||
| ^^^^^
|
||||
|
||||
error[E0609]: no field `0` on type `Struct`
|
||||
--> $DIR/nonexistent.rs:24:30
|
||||
|
|
||||
LL | let _: field_of!(Struct, 0);
|
||||
| ^
|
||||
|
||||
error[E0609]: no field `other` on type `Union`
|
||||
--> $DIR/nonexistent.rs:25:29
|
||||
|
|
||||
LL | let _: field_of!(Union, other);
|
||||
| ^^^^^
|
||||
|
||||
error[E0609]: no field `0` on type `Union`
|
||||
--> $DIR/nonexistent.rs:26:29
|
||||
|
|
||||
LL | let _: field_of!(Union, 0);
|
||||
| ^
|
||||
|
||||
error[E0609]: no field `other` on type `Enum`
|
||||
--> $DIR/nonexistent.rs:28:36
|
||||
|
|
||||
LL | let _: field_of!(Enum, Variant.other);
|
||||
| ^^^^^
|
||||
|
||||
error[E0609]: no field `0` on type `Enum`
|
||||
--> $DIR/nonexistent.rs:29:36
|
||||
|
|
||||
LL | let _: field_of!(Enum, Variant.0);
|
||||
| ^
|
||||
|
||||
error[E0599]: no variant named `OtherVariant` found for enum `Enum`
|
||||
--> $DIR/nonexistent.rs:31:28
|
||||
|
|
||||
LL | let _: field_of!(Enum, OtherVariant.field);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0599]: no variant named `OtherVariant` found for enum `Enum`
|
||||
--> $DIR/nonexistent.rs:32:28
|
||||
|
|
||||
LL | let _: field_of!(Enum, OtherVariant.0);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0609]: no field `2` on type `((), ())`
|
||||
--> $DIR/nonexistent.rs:33:32
|
||||
|
|
||||
LL | let _: field_of!(((), ()), 2);
|
||||
| ^
|
||||
|
||||
error[E0609]: no field `field` on type `((), ())`
|
||||
--> $DIR/nonexistent.rs:34:32
|
||||
|
|
||||
LL | let _: field_of!(((), ()), field);
|
||||
| ^^^^^
|
||||
|
||||
error: type `i32` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:36:22
|
||||
|
|
||||
LL | let _: field_of!(i32, field);
|
||||
| ^^^
|
||||
|
||||
error: type `[Struct]` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:37:22
|
||||
|
|
||||
LL | let _: field_of!([Struct], field);
|
||||
| ^^^^^^^^
|
||||
|
||||
error: type `[Struct; 42]` is not yet supported in `field_of!`
|
||||
--> $DIR/nonexistent.rs:38:22
|
||||
|
|
||||
LL | let _: field_of!([Struct; 42], field);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: type `&'static Struct` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:39:22
|
||||
|
|
||||
LL | let _: field_of!(&'static Struct, field);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: type `*const Struct` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:40:22
|
||||
|
|
||||
LL | let _: field_of!(*const Struct, field);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: type `fn() -> Struct` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:41:22
|
||||
|
|
||||
LL | let _: field_of!(fn() -> Struct, field);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: type `dyn Trait` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:42:22
|
||||
|
|
||||
LL | let _: field_of!(dyn Trait, field);
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: cannot use `_` in this position
|
||||
--> $DIR/nonexistent.rs:44:22
|
||||
|
|
||||
LL | let _: field_of!(_, field);
|
||||
| ^
|
||||
|
||||
error: type `T` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:48:22
|
||||
|
|
||||
LL | let _: field_of!(T, field);
|
||||
| ^
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0573, E0599, E0609.
|
||||
For more information about an error, try `rustc --explain E0573`.
|
||||
@@ -0,0 +1,124 @@
|
||||
error[E0573]: expected type, found function `main`
|
||||
--> $DIR/nonexistent.rs:43:22
|
||||
|
|
||||
LL | let _: field_of!(main, field);
|
||||
| ^^^^ not a type
|
||||
|
||||
error[E0609]: no field `other` on type `Struct`
|
||||
--> $DIR/nonexistent.rs:23:30
|
||||
|
|
||||
LL | let _: field_of!(Struct, other);
|
||||
| ^^^^^
|
||||
|
||||
error[E0609]: no field `0` on type `Struct`
|
||||
--> $DIR/nonexistent.rs:24:30
|
||||
|
|
||||
LL | let _: field_of!(Struct, 0);
|
||||
| ^
|
||||
|
||||
error[E0609]: no field `other` on type `Union`
|
||||
--> $DIR/nonexistent.rs:25:29
|
||||
|
|
||||
LL | let _: field_of!(Union, other);
|
||||
| ^^^^^
|
||||
|
||||
error[E0609]: no field `0` on type `Union`
|
||||
--> $DIR/nonexistent.rs:26:29
|
||||
|
|
||||
LL | let _: field_of!(Union, 0);
|
||||
| ^
|
||||
|
||||
error[E0609]: no field `other` on type `Enum`
|
||||
--> $DIR/nonexistent.rs:28:36
|
||||
|
|
||||
LL | let _: field_of!(Enum, Variant.other);
|
||||
| ^^^^^
|
||||
|
||||
error[E0609]: no field `0` on type `Enum`
|
||||
--> $DIR/nonexistent.rs:29:36
|
||||
|
|
||||
LL | let _: field_of!(Enum, Variant.0);
|
||||
| ^
|
||||
|
||||
error[E0599]: no variant named `OtherVariant` found for enum `Enum`
|
||||
--> $DIR/nonexistent.rs:31:28
|
||||
|
|
||||
LL | let _: field_of!(Enum, OtherVariant.field);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0599]: no variant named `OtherVariant` found for enum `Enum`
|
||||
--> $DIR/nonexistent.rs:32:28
|
||||
|
|
||||
LL | let _: field_of!(Enum, OtherVariant.0);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0609]: no field `2` on type `((), ())`
|
||||
--> $DIR/nonexistent.rs:33:32
|
||||
|
|
||||
LL | let _: field_of!(((), ()), 2);
|
||||
| ^
|
||||
|
||||
error[E0609]: no field `field` on type `((), ())`
|
||||
--> $DIR/nonexistent.rs:34:32
|
||||
|
|
||||
LL | let _: field_of!(((), ()), field);
|
||||
| ^^^^^
|
||||
|
||||
error: type `i32` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:36:22
|
||||
|
|
||||
LL | let _: field_of!(i32, field);
|
||||
| ^^^
|
||||
|
||||
error: type `[Struct]` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:37:22
|
||||
|
|
||||
LL | let _: field_of!([Struct], field);
|
||||
| ^^^^^^^^
|
||||
|
||||
error: type `[Struct; 42]` is not yet supported in `field_of!`
|
||||
--> $DIR/nonexistent.rs:38:22
|
||||
|
|
||||
LL | let _: field_of!([Struct; 42], field);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: type `&'static Struct` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:39:22
|
||||
|
|
||||
LL | let _: field_of!(&'static Struct, field);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: type `*const Struct` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:40:22
|
||||
|
|
||||
LL | let _: field_of!(*const Struct, field);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: type `fn() -> Struct` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:41:22
|
||||
|
|
||||
LL | let _: field_of!(fn() -> Struct, field);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: type `dyn Trait` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:42:22
|
||||
|
|
||||
LL | let _: field_of!(dyn Trait, field);
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: cannot use `_` in this position
|
||||
--> $DIR/nonexistent.rs:44:22
|
||||
|
|
||||
LL | let _: field_of!(_, field);
|
||||
| ^
|
||||
|
||||
error: type `T` doesn't have fields
|
||||
--> $DIR/nonexistent.rs:48:22
|
||||
|
|
||||
LL | let _: field_of!(T, field);
|
||||
| ^
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0573, E0599, E0609.
|
||||
For more information about an error, try `rustc --explain E0573`.
|
||||
@@ -0,0 +1,49 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(field_projections)]
|
||||
|
||||
use std::field::field_of;
|
||||
|
||||
pub struct Struct {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
pub union Union {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
pub enum Enum {
|
||||
Variant { field: i32 },
|
||||
}
|
||||
|
||||
pub trait Trait {}
|
||||
|
||||
fn main() {
|
||||
let _: field_of!(Struct, other); //~ ERROR: no field `other` on type `Struct` [E0609]
|
||||
let _: field_of!(Struct, 0); //~ ERROR: no field `0` on type `Struct` [E0609]
|
||||
let _: field_of!(Union, other); //~ ERROR: no field `other` on type `Union` [E0609]
|
||||
let _: field_of!(Union, 0); //~ ERROR: no field `0` on type `Union` [E0609]
|
||||
// FIXME(FRTs): make the error mention the variant too.
|
||||
let _: field_of!(Enum, Variant.other); //~ ERROR: no field `other` on type `Enum` [E0609]
|
||||
let _: field_of!(Enum, Variant.0); //~ ERROR: no field `0` on type `Enum` [E0609]
|
||||
// FIXME(FRTs): select correct error code
|
||||
let _: field_of!(Enum, OtherVariant.field); //~ ERROR: no variant named `OtherVariant` found for enum `Enum`
|
||||
let _: field_of!(Enum, OtherVariant.0); //~ ERROR: no variant named `OtherVariant` found for enum `Enum`
|
||||
let _: field_of!(((), ()), 2); //~ ERROR: no field `2` on type `((), ())` [E0609]
|
||||
let _: field_of!(((), ()), field); //~ ERROR: no field `field` on type `((), ())` [E0609]
|
||||
|
||||
let _: field_of!(i32, field); //~ ERROR: type `i32` doesn't have fields
|
||||
let _: field_of!([Struct], field); //~ ERROR: type `[Struct]` doesn't have fields
|
||||
let _: field_of!([Struct; 42], field); //~ ERROR: type `[Struct; 42]` is not yet supported in `field_of!`
|
||||
let _: field_of!(&'static Struct, field); //~ ERROR: type `&'static Struct` doesn't have fields
|
||||
let _: field_of!(*const Struct, field); //~ ERROR: type `*const Struct` doesn't have fields
|
||||
let _: field_of!(fn() -> Struct, field); //~ ERROR: type `fn() -> Struct` doesn't have fields
|
||||
let _: field_of!(dyn Trait, field); //~ ERROR: type `dyn Trait` doesn't have fields
|
||||
let _: field_of!(main, field); //~ ERROR: expected type, found function `main`
|
||||
let _: field_of!(_, field); //~ ERROR: cannot use `_` in this position
|
||||
}
|
||||
|
||||
fn generic<T>() {
|
||||
let _: field_of!(T, field); //~ ERROR: type `T` doesn't have fields
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
error[E0277]: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied
|
||||
--> $DIR/not-field-if-packed.rs:15:20
|
||||
|
|
||||
LL | assert_field::<field_of!(MyStruct, 0)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 0)`
|
||||
|
|
||||
note: required by a bound in `assert_field`
|
||||
--> $DIR/not-field-if-packed.rs:11:20
|
||||
|
|
||||
LL | fn assert_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `assert_field`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -0,0 +1,15 @@
|
||||
error[E0277]: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied
|
||||
--> $DIR/not-field-if-packed.rs:15:20
|
||||
|
|
||||
LL | assert_field::<field_of!(MyStruct, 0)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 0)`
|
||||
|
|
||||
note: required by a bound in `assert_field`
|
||||
--> $DIR/not-field-if-packed.rs:11:20
|
||||
|
|
||||
LL | fn assert_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `assert_field`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -0,0 +1,17 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(field_projections)]
|
||||
|
||||
use std::field::{Field, field_of};
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct MyStruct(usize);
|
||||
|
||||
fn assert_field<F: Field>() {}
|
||||
|
||||
fn main() {
|
||||
// FIXME(FRTs): improve this error message, point to the `repr(packed)` span.
|
||||
assert_field::<field_of!(MyStruct, 0)>();
|
||||
//~^ ERROR: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied [E0277]
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
//@ run-pass
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(field_projections)]
|
||||
|
||||
use std::field::{Field, field_of};
|
||||
use std::mem::offset_of;
|
||||
use std::ptr;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Struct {
|
||||
a: i32,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
// FIXME(FRTs): need to mark these fields as used by the `field_of!` macro.
|
||||
#[expect(dead_code)]
|
||||
pub union Union {
|
||||
a: i32,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
#[repr(C, i8)]
|
||||
pub enum Enum {
|
||||
A { a: i32, b: i64 },
|
||||
B { x: i64, y: i32 },
|
||||
}
|
||||
|
||||
fn project_ref<'a, T, F: Field<Base = T>>(r: &'a T) -> &'a F::Type {
|
||||
unsafe { &*ptr::from_ref(r).byte_add(F::OFFSET).cast() }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(<field_of!(Struct, a)>::OFFSET, offset_of!(Struct, a));
|
||||
assert_eq!(<field_of!(Struct, b)>::OFFSET, offset_of!(Struct, b));
|
||||
|
||||
let _: field_of!(Union, a);
|
||||
let _: field_of!(Union, b);
|
||||
|
||||
let _: field_of!(Enum, A.a);
|
||||
let _: field_of!(Enum, A.b);
|
||||
let _: field_of!(Enum, B.x);
|
||||
let _: field_of!(Enum, B.y);
|
||||
|
||||
let s = Struct { a: 42, b: 24 };
|
||||
let r = &s;
|
||||
let a = project_ref::<Struct, field_of!(Struct, a)>(r);
|
||||
let b = project_ref::<Struct, field_of!(Struct, b)>(r);
|
||||
assert_eq!(*a, 42);
|
||||
assert_eq!(*b, 24);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
error[E0616]: field `a` of struct `foo::Struct` is private
|
||||
--> $DIR/privacy.rs:28:30
|
||||
|
|
||||
LL | let _: field_of!(Struct, a);
|
||||
| ^ private field
|
||||
|
||||
error[E0616]: field `a` of union `foo::Union` is private
|
||||
--> $DIR/privacy.rs:30:29
|
||||
|
|
||||
LL | let _: field_of!(Union, a);
|
||||
| ^ private field
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0616`.
|
||||
@@ -0,0 +1,15 @@
|
||||
error[E0616]: field `a` of struct `foo::Struct` is private
|
||||
--> $DIR/privacy.rs:28:30
|
||||
|
|
||||
LL | let _: field_of!(Struct, a);
|
||||
| ^ private field
|
||||
|
||||
error[E0616]: field `a` of union `foo::Union` is private
|
||||
--> $DIR/privacy.rs:30:29
|
||||
|
|
||||
LL | let _: field_of!(Union, a);
|
||||
| ^ private field
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0616`.
|
||||
@@ -0,0 +1,34 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(field_projections)]
|
||||
|
||||
use std::field::field_of;
|
||||
|
||||
mod foo {
|
||||
pub struct Struct {
|
||||
a: i32,
|
||||
pub b: i32,
|
||||
}
|
||||
|
||||
pub union Union {
|
||||
a: i32,
|
||||
pub b: u32,
|
||||
}
|
||||
|
||||
pub enum Enum {
|
||||
A { field: i32 },
|
||||
B(i32),
|
||||
}
|
||||
}
|
||||
|
||||
use foo::{Enum, Struct, Union};
|
||||
|
||||
fn main() {
|
||||
let _: field_of!(Struct, a); //~ ERROR: field `a` of struct `foo::Struct` is private [E0616]
|
||||
let _: field_of!(Struct, b);
|
||||
let _: field_of!(Union, a); //~ ERROR: field `a` of union `foo::Union` is private [E0616]
|
||||
let _: field_of!(Union, b);
|
||||
let _: field_of!(Enum, A.field);
|
||||
let _: field_of!(Enum, B.0);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
error: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
--> $DIR/projections.rs:39:18
|
||||
|
|
||||
LL | _: field_of!(<<T as Trait>::Assoc as Special>::Assoc, field),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
--> $DIR/projections.rs:45:19
|
||||
|
|
||||
LL | _x: field_of!(<<T as Trait>::Assoc as Special>::Assoc, field),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: could not resolve fields of `<Struct as Trait>::Assoc`
|
||||
--> $DIR/projections.rs:24:22
|
||||
|
|
||||
LL | let _: field_of!(<Struct as Trait>::Assoc, field);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
--> $DIR/projections.rs:51:22
|
||||
|
|
||||
LL | let _: field_of!(<<T as Trait>::Assoc as Special>::Assoc, field);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
--> $DIR/projections.rs:56:22
|
||||
|
|
||||
LL | let _: field_of!(<<T as Trait>::Assoc as Special>::Assoc, other);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
error: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
--> $DIR/projections.rs:39:18
|
||||
|
|
||||
LL | _: field_of!(<<T as Trait>::Assoc as Special>::Assoc, field),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
--> $DIR/projections.rs:45:19
|
||||
|
|
||||
LL | _x: field_of!(<<T as Trait>::Assoc as Special>::Assoc, field),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: could not resolve fields of `<Struct as Trait>::Assoc`
|
||||
--> $DIR/projections.rs:24:22
|
||||
|
|
||||
LL | let _: field_of!(<Struct as Trait>::Assoc, field);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
--> $DIR/projections.rs:51:22
|
||||
|
|
||||
LL | let _: field_of!(<<T as Trait>::Assoc as Special>::Assoc, field);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
--> $DIR/projections.rs:56:22
|
||||
|
|
||||
LL | let _: field_of!(<<T as Trait>::Assoc as Special>::Assoc, other);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
#![feature(field_projections, freeze)]
|
||||
#![expect(incomplete_features, dead_code)]
|
||||
|
||||
use std::field::field_of;
|
||||
|
||||
struct Struct {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
type Alias = Struct;
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl Trait for Struct {
|
||||
type Assoc = Struct;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: field_of!(Alias, field);
|
||||
let _: field_of!(<Struct as Trait>::Assoc, field);
|
||||
//~^ ERROR: could not resolve fields of `<Struct as Trait>::Assoc`
|
||||
}
|
||||
|
||||
trait Special {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Constraint: Trait<Assoc = Struct> {}
|
||||
|
||||
impl Special for Struct {
|
||||
type Assoc = Self;
|
||||
}
|
||||
|
||||
fn with_constraint1<T: Constraint>(
|
||||
_: field_of!(<<T as Trait>::Assoc as Special>::Assoc, field),
|
||||
//~^ ERROR: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
) {
|
||||
}
|
||||
|
||||
fn with_constraint2<T: Constraint>(
|
||||
_x: field_of!(<<T as Trait>::Assoc as Special>::Assoc, field),
|
||||
//~^ ERROR: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
) {
|
||||
}
|
||||
|
||||
fn with_constraint3<T: Constraint>() {
|
||||
let _: field_of!(<<T as Trait>::Assoc as Special>::Assoc, field);
|
||||
//~^ ERROR: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
}
|
||||
|
||||
fn with_constraint_invalid_field<T: Constraint>() {
|
||||
let _: field_of!(<<T as Trait>::Assoc as Special>::Assoc, other);
|
||||
//~^ ERROR: could not resolve fields of `<<T as Trait>::Assoc as Special>::Assoc`
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
error[E0277]: the trait bound `field_of!(Generic<T>, count): std::field::Field` is not satisfied
|
||||
--> $DIR/sized.rs:20:19
|
||||
|
|
||||
LL | impls_field::<field_of!(Generic<T>, count)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(Generic<T>, count)`
|
||||
|
|
||||
note: required by a bound in `impls_field`
|
||||
--> $DIR/sized.rs:38:19
|
||||
|
|
||||
LL | fn impls_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `impls_field`
|
||||
|
||||
error[E0277]: the trait bound `field_of!(Generic<T>, last): std::field::Field` is not satisfied
|
||||
--> $DIR/sized.rs:22:19
|
||||
|
|
||||
LL | impls_field::<field_of!(Generic<T>, last)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(Generic<T>, last)`
|
||||
|
|
||||
note: required by a bound in `impls_field`
|
||||
--> $DIR/sized.rs:38:19
|
||||
|
|
||||
LL | fn impls_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `impls_field`
|
||||
|
||||
error[E0277]: the trait bound `field_of!(MyDST, count): std::field::Field` is not satisfied
|
||||
--> $DIR/sized.rs:32:19
|
||||
|
|
||||
LL | impls_field::<field_of!(MyDST, count)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyDST, count)`
|
||||
|
|
||||
note: required by a bound in `impls_field`
|
||||
--> $DIR/sized.rs:38:19
|
||||
|
|
||||
LL | fn impls_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `impls_field`
|
||||
|
||||
error[E0277]: the trait bound `field_of!(MyDST, last): std::field::Field` is not satisfied
|
||||
--> $DIR/sized.rs:34:19
|
||||
|
|
||||
LL | impls_field::<field_of!(MyDST, last)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyDST, last)`
|
||||
|
|
||||
note: required by a bound in `impls_field`
|
||||
--> $DIR/sized.rs:38:19
|
||||
|
|
||||
LL | fn impls_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `impls_field`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -0,0 +1,51 @@
|
||||
error[E0277]: the trait bound `field_of!(Generic<T>, count): std::field::Field` is not satisfied
|
||||
--> $DIR/sized.rs:20:19
|
||||
|
|
||||
LL | impls_field::<field_of!(Generic<T>, count)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(Generic<T>, count)`
|
||||
|
|
||||
note: required by a bound in `impls_field`
|
||||
--> $DIR/sized.rs:38:19
|
||||
|
|
||||
LL | fn impls_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `impls_field`
|
||||
|
||||
error[E0277]: the trait bound `field_of!(Generic<T>, last): std::field::Field` is not satisfied
|
||||
--> $DIR/sized.rs:22:19
|
||||
|
|
||||
LL | impls_field::<field_of!(Generic<T>, last)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(Generic<T>, last)`
|
||||
|
|
||||
note: required by a bound in `impls_field`
|
||||
--> $DIR/sized.rs:38:19
|
||||
|
|
||||
LL | fn impls_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `impls_field`
|
||||
|
||||
error[E0277]: the trait bound `field_of!(MyDST, count): std::field::Field` is not satisfied
|
||||
--> $DIR/sized.rs:32:19
|
||||
|
|
||||
LL | impls_field::<field_of!(MyDST, count)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyDST, count)`
|
||||
|
|
||||
note: required by a bound in `impls_field`
|
||||
--> $DIR/sized.rs:38:19
|
||||
|
|
||||
LL | fn impls_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `impls_field`
|
||||
|
||||
error[E0277]: the trait bound `field_of!(MyDST, last): std::field::Field` is not satisfied
|
||||
--> $DIR/sized.rs:34:19
|
||||
|
|
||||
LL | impls_field::<field_of!(MyDST, last)>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyDST, last)`
|
||||
|
|
||||
note: required by a bound in `impls_field`
|
||||
--> $DIR/sized.rs:38:19
|
||||
|
|
||||
LL | fn impls_field<F: Field>() {}
|
||||
| ^^^^^ required by this bound in `impls_field`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -0,0 +1,38 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(field_projections)]
|
||||
|
||||
use std::field::{Field, field_of};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub struct MyDST {
|
||||
count: usize,
|
||||
last: dyn Debug,
|
||||
}
|
||||
|
||||
pub struct Generic<T: ?Sized> {
|
||||
count: usize,
|
||||
last: T,
|
||||
}
|
||||
|
||||
fn generic<T: ?Sized>() {
|
||||
impls_field::<field_of!(Generic<T>, count)>();
|
||||
//~^ ERROR: the trait bound `field_of!(Generic<T>, count): std::field::Field` is not satisfied [E0277]
|
||||
impls_field::<field_of!(Generic<T>, last)>();
|
||||
//~^ ERROR: the trait bound `field_of!(Generic<T>, last): std::field::Field` is not satisfied [E0277]
|
||||
}
|
||||
|
||||
fn ok<T>() {
|
||||
impls_field::<field_of!(Generic<T>, count)>();
|
||||
impls_field::<field_of!(Generic<T>, last)>();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
impls_field::<field_of!(MyDST, count)>();
|
||||
//~^ ERROR: the trait bound `field_of!(MyDST, count): std::field::Field` is not satisfied [E0277]
|
||||
impls_field::<field_of!(MyDST, last)>();
|
||||
//~^ ERROR: the trait bound `field_of!(MyDST, last): std::field::Field` is not satisfied [E0277]
|
||||
}
|
||||
|
||||
fn impls_field<F: Field>() {}
|
||||
@@ -0,0 +1,29 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
//@ run-pass
|
||||
#![feature(field_projections, freeze)]
|
||||
#![expect(incomplete_features, dead_code)]
|
||||
use std::field::field_of;
|
||||
use std::marker::{Freeze, Unpin};
|
||||
|
||||
struct Struct {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
union Union {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
Variant1 { field: u32 },
|
||||
Variant2(u32),
|
||||
}
|
||||
|
||||
fn assert_traits<T: Send + Sync + Unpin + Copy + Clone + Sized + Freeze>() {}
|
||||
|
||||
fn main() {
|
||||
assert_traits::<field_of!(Struct, field)>();
|
||||
assert_traits::<field_of!(Union, field)>();
|
||||
assert_traits::<field_of!(Enum, Variant1.field)>();
|
||||
assert_traits::<field_of!(Enum, Variant2.0)>();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
error[E0120]: the `Drop` trait may only be implemented for local structs, enums, and unions
|
||||
--> $DIR/weird-impls.rs:10:15
|
||||
|
|
||||
LL | impl Drop for field_of!(MyStruct, 0) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ must be a struct, enum, or union in the current crate
|
||||
|
|
||||
= note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type defined in the current crate
|
||||
--> $DIR/weird-impls.rs:15:1
|
||||
|
|
||||
LL | unsafe impl Send for field_of!(MyStruct, 0) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait for type in another crate
|
||||
|
||||
error[E0322]: explicit impls for the `Field` trait are not permitted
|
||||
--> $DIR/weird-impls.rs:21:1
|
||||
|
|
||||
LL | unsafe impl Field for field_of!(MyStruct2, 0) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Field` not allowed
|
||||
|
||||
error[E0322]: explicit impls for the `Field` trait are not permitted
|
||||
--> $DIR/weird-impls.rs:30:1
|
||||
|
|
||||
LL | unsafe impl Field for MyField {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Field` not allowed
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0120, E0321, E0322.
|
||||
For more information about an error, try `rustc --explain E0120`.
|
||||
@@ -0,0 +1,30 @@
|
||||
error[E0120]: the `Drop` trait may only be implemented for local structs, enums, and unions
|
||||
--> $DIR/weird-impls.rs:10:15
|
||||
|
|
||||
LL | impl Drop for field_of!(MyStruct, 0) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ must be a struct, enum, or union in the current crate
|
||||
|
|
||||
= note: this error originates in the macro `field_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type defined in the current crate
|
||||
--> $DIR/weird-impls.rs:15:1
|
||||
|
|
||||
LL | unsafe impl Send for field_of!(MyStruct, 0) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait for type in another crate
|
||||
|
||||
error[E0322]: explicit impls for the `Field` trait are not permitted
|
||||
--> $DIR/weird-impls.rs:21:1
|
||||
|
|
||||
LL | unsafe impl Field for field_of!(MyStruct2, 0) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Field` not allowed
|
||||
|
||||
error[E0322]: explicit impls for the `Field` trait are not permitted
|
||||
--> $DIR/weird-impls.rs:30:1
|
||||
|
|
||||
LL | unsafe impl Field for MyField {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Field` not allowed
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0120, E0321, E0322.
|
||||
For more information about an error, try `rustc --explain E0120`.
|
||||
@@ -0,0 +1,37 @@
|
||||
//@ revisions: old next
|
||||
//@ [next] compile-flags: -Znext-solver
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(field_projections)]
|
||||
|
||||
use std::field::{Field, field_of};
|
||||
|
||||
pub struct MyStruct(());
|
||||
|
||||
impl Drop for field_of!(MyStruct, 0) {
|
||||
//~^ ERROR: the `Drop` trait may only be implemented for local structs, enums, and unions [E0120]
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
unsafe impl Send for field_of!(MyStruct, 0) {}
|
||||
//~^ ERROR: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type defined in the current crate [E0321]
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct MyStruct2(usize);
|
||||
|
||||
unsafe impl Field for field_of!(MyStruct2, 0) {
|
||||
//~^ ERROR: explicit impls for the `Field` trait are not permitted [E0322]
|
||||
type Base = MyStruct2;
|
||||
type Type = usize;
|
||||
const OFFSET: usize = 0;
|
||||
}
|
||||
|
||||
pub struct MyField;
|
||||
|
||||
unsafe impl Field for MyField {
|
||||
//~^ ERROR: explicit impls for the `Field` trait are not permitted [E0322]
|
||||
type Base = ();
|
||||
type Type = ();
|
||||
const OFFSET: usize = 0;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Reference in New Issue
Block a user